Strings em um DataFrame, mas dtype é objeto

96

Por que o Pandas me diz que tenho objetos, embora cada item na coluna selecionada seja uma string - mesmo após a conversão explícita?

Este é meu DataFrame:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 56992 entries, 0 to 56991
Data columns (total 7 columns):
id            56992  non-null values
attr1         56992  non-null values
attr2         56992  non-null values
attr3         56992  non-null values
attr4         56992  non-null values
attr5         56992  non-null values
attr6         56992  non-null values
dtypes: int64(2), object(5)

Cinco deles são dtype object. Eu converto explicitamente esses objetos em strings:

for c in df.columns:
    if df[c].dtype == object:
        print "convert ", df[c].name, " to string"
        df[c] = df[c].astype(str)

Então, df["attr2"]ainda tem dtype object, embora type(df["attr2"].ix[0]revele str, o que é correto.

O Pandas distingue entre int64e float64e object. Qual é a lógica por trás disso quando não há dtype str? Por que um está strcoberto por object?

Xiphias
fonte
Vim aqui porque as junções estão falhando devido ao 'tipo de objeto', embora toda string "é"
Monica Heddneck

Respostas:

145

O objeto dtype vem de NumPy, ele descreve o tipo de elemento em um ndarray. Cada elemento em um ndarray deve ter o mesmo tamanho em bytes. Para int64 e float64, eles têm 8 bytes. Mas para cordas, o comprimento da corda não é fixo. Então, em vez de salvar os bytes de strings no ndarray diretamente, o Pandas usa o objeto ndarray, que salva ponteiros para objetos, por isso o dtipo desse tipo ndarray é objeto.

Aqui está um exemplo:

  • a matriz int64 contém 4 valores int64.
  • o array de objetos contém 4 ponteiros para 3 objetos string.

insira a descrição da imagem aqui

HYRY
fonte
3
Observe, no entanto, que ter colunas do tipo 'objeto' tem um grande impacto no desempenho das operações de leitura / gravação do
DataFrame
posso obter o tipo de dados retornado como string, de alguma forma. Sei que sempre posso usar o tipo (df ["coluna"]. Iloc [0]), mas pode acontecer que seja nan
user1953366
7

A resposta aceita é boa. Queria apenas fornecer uma resposta que referencia a documentação . A documentação diz:

O Pandas usa o tipo de objeto d para armazenar strings.

Como diz o comentário principal: "Não se preocupe com isso; é para ser assim." (Embora a resposta aceita tenha explicado muito bem o "porquê"; as strings têm comprimento variável)

Mas para cordas, o comprimento da corda não é fixo.

The Red Pea
fonte
Por que preciso converter todas as colunas que passo em scipy ou sklearn astype (str) para aceitá-lo? parece que devo ser capaz de aplicar isso a todas as colunas inicialmente.
Tinkinc de
Eu não entendo; @Tinkinc o que acontece se você não converter colunas em string? E essa resposta parece uma maneira elegante de converter todas as colunas,astype(str) embora eu ainda me pergunte se a conversão de strings é necessária
The Red Pea
Não consigo preencher (0) todos os objetos em meu dataframe permanecem (1, nan) em vez de (1,0)
Tinkinc
Desculpe @Tinkinc, ainda não entendi; Quero ajudar, mas seu problema parece mais complexo do que um comentário Stack Overflow. Considere fazer uma pergunta ou juntar-se a mim no chat. (acabei de convidá-lo)
The Red Pea
5

A resposta de @HYRY é ótima. Eu só quero fornecer um pouco mais de contexto.

Arrays dados armazenados como contígua , de tamanho fixo blocos de memória. A combinação dessas propriedades é o que torna os arrays extremamente rápidos para o acesso aos dados. Por exemplo, considere como seu computador pode armazenar uma matriz de inteiros de 32 bits [3,0,1],.

insira a descrição da imagem aqui

Se você pedir ao seu computador para buscar o terceiro elemento no array, ele começará no início e então saltará pelos 64 bits para chegar ao terceiro elemento. Saber exatamente quantos bits saltar é o que torna os arrays mais rápidos .

Agora considere a sequência de strings ['hello', 'i', 'am', 'a', 'banana']. Strings são objetos que variam em tamanho, então se você tentasse armazená-los em blocos de memória contíguos, ficaria assim.

insira a descrição da imagem aqui

Agora seu computador não tem uma maneira rápida de acessar um elemento solicitado aleatoriamente. A chave para superar isso é usar ponteiros. Basicamente, armazene cada string em algum local de memória aleatório e preencha o array com o endereço de memória de cada string. (Os endereços de memória são apenas números inteiros.) Então, agora, as coisas se parecem com isto

insira a descrição da imagem aqui

Agora, se você pedir ao seu computador para buscar o terceiro elemento, assim como antes, ele pode pular 64 bits (assumindo que os endereços de memória são inteiros de 32 bits) e então dar um passo extra para buscar a string.

O desafio para NumPy é que não há garantia de que os ponteiros estão realmente apontando para strings. É por isso que relata o dtype como 'objeto'.

Sem vergonha, vou inserir meu próprio artigo de blog onde originalmente discuti isso.

Ben
fonte
Nicely written..Thanks
Tedd
1

A partir da versão 1.0.0 (janeiro de 2020), o pandas foi introduzido como um recurso experimental que fornece suporte de primeira classe para tipos de strings pandas.StringDtype.

Embora você ainda esteja vendo objectpor padrão, o novo tipo pode ser usado especificando um dtypede pd.StringDtypeou simplesmente 'string':

>>> pd.Series(['abc', None, 'def'])
0     abc
1    None
2     def
dtype: object
>>> pd.Series(['abc', None, 'def'], dtype=pd.StringDtype())
0     abc
1    <NA>
2     def
dtype: string
>>> pd.Series(['abc', None, 'def']).astype('string')
0     abc
1    <NA>
2     def
dtype: string
Fuglede
fonte
2
Não use isso .... ainda. Como eles declararam, o The implementation may change without warning.que significa que novas atualizações irão quebrar seus programas antigos.
NoName
1
Bem, tudo depende de como você vai usá-lo. Se você quiser usá-lo em um sistema de produção onde atualizações contínuas de pacotes são necessárias e onde a quebra da API causa uma carga de manutenção inaceitável, então, preste muita atenção à palavra "experimental", mas se você estiver usando pandas para realizar explorações análises em scripts cujo tempo de vida não aumenta um dia de trabalho, essas preocupações devem significar pouco para você.
fuglede
No Pandas 1.1, a API parecia estar estabilizada. Todos os dtypes agora podem ser convertidos para StringDtype .
D3f0