Chaînes dans un DataFrame, mais dtype est un objet


96

Pourquoi Pandas me dit-il que j'ai des objets, bien que chaque élément de la colonne sélectionnée soit une chaîne - même après une conversion explicite.

Voici mon 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)

Cinq d'entre eux le sont dtype object. Je convertis explicitement ces objets en chaînes:

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

Ensuite, a df["attr2"]encore dtype object, bien que type(df["attr2"].ix[0]révèle str, ce qui est correct.

Pandas fait la distinction entre int64et float64et object. Quelle est la logique derrière cela quand il n'y a pas dtype str? Pourquoi est strcouvert par object?


Entré ici parce que les jointures échouent en raison du 'type d'objet' même si chaque chaîne "est"
Monica Heddneck

Réponses:


145

L'objet dtype provient de NumPy, il décrit le type d'élément dans un ndarray. Chaque élément d'un ndarray doit avoir la même taille en octets. Pour int64 et float64, ils font 8 octets. Mais pour les chaînes, la longueur de la chaîne n'est pas fixe. Ainsi, au lieu de sauvegarder directement les octets des chaînes dans le ndarray, les Pandas utilisent object ndarray, qui enregistre des pointeurs vers des objets, à cause de cela, le type de ce type ndarray est object.

Voici un exemple:

  • le tableau int64 contient 4 valeurs int64.
  • le tableau d'objets contient 4 pointeurs vers 3 objets chaîne.

entrez la description de l'image ici


3
Notez cependant que le fait d'avoir des colonnes de type `` objet '' a un impact majeur sur les performances des opérations de lecture / écriture de
DataFrame

puis-je obtenir le type de données renvoyé sous forme de chaîne, d'une manière ou d'une autre. Je sais que je peux toujours utiliser le type (df ["column"]. Iloc [0]), mais il se peut que ce soit nan
user1953366

7

La réponse acceptée est bonne. Je voulais juste fournir une réponse faisant référence à la documentation . La documentation dit:

Pandas utilise l'objet dtype pour stocker les chaînes.

Comme le dit le commentaire principal "Ne vous en faites pas, c'est censé être comme ça." (Bien que la réponse acceptée ait fait un excellent travail en expliquant le «pourquoi»; les chaînes sont de longueur variable)

Mais pour les chaînes, la longueur de la chaîne n'est pas fixe.


Pourquoi dois-je convertir chaque colonne que je passe en astype scipy ou sklearn (str) pour qu'elle l'accepte? semble que je devrais pouvoir appliquer cela à toutes les colonnes au départ.
Tinkinc

Je ne comprends pas; @Tinkinc que se passe-t-il si vous ne convertissez pas les colonnes en chaîne? Et cette réponse semble un moyen élégant de convertir toutes les colonnes enastype(str) bien que je me demande toujours que la conversion de chaîne est nécessaire
The Red Pea

Je ne peux pas remplir (0) tous les objets de ma trame de données restent (1, nan) au lieu de (1,0)
Tinkinc

Désolé @Tinkinc je ne comprends toujours pas; Je veux vous aider, mais votre problème semble plus complexe qu'un commentaire Stack Overflow. Pensez à poser une question ou à me rejoindre dans le chat. (vient de vous inviter)
The Red Pea

5

La réponse de @ HYRY est excellente. Je veux juste fournir un peu plus de contexte.

Les tableaux de données stockées sous la forme contiguë , de taille fixe des blocs de mémoire. La combinaison de ces propriétés est ce qui rend les baies ultra-rapides pour l'accès aux données. Par exemple, examiner comment votre ordinateur peut stocker un tableau d'entiers 32 bits, [3,0,1].

entrez la description de l'image ici

Si vous demandez à votre ordinateur de récupérer le 3ème élément du tableau, il commencera au début, puis sautera sur 64 bits pour atteindre le 3ème élément. Savoir exactement combien de bits sauter est ce qui rend les tableaux rapides .

Considérons maintenant la séquence de chaînes ['hello', 'i', 'am', 'a', 'banana']. Les chaînes sont des objets dont la taille varie, donc si vous essayez de les stocker dans des blocs de mémoire contigus, cela finira par ressembler à ceci.

entrez la description de l'image ici

Maintenant, votre ordinateur ne dispose pas d'un moyen rapide d'accéder à un élément demandé au hasard. La clé pour surmonter cela est d'utiliser des pointeurs. Fondamentalement, stockez chaque chaîne dans un emplacement de mémoire aléatoire et remplissez le tableau avec l'adresse mémoire de chaque chaîne. (Les adresses mémoire ne sont que des entiers.) Alors maintenant, les choses ressemblent à ceci

entrez la description de l'image ici

Maintenant, si vous demandez à votre ordinateur de récupérer le 3ème élément, comme auparavant, il peut sauter sur 64 bits (en supposant que les adresses mémoire sont des entiers de 32 bits) puis faire une étape supplémentaire pour aller chercher la chaîne.

Le défi pour NumPy est qu'il n'y a aucune garantie que les pointeurs pointent réellement vers des chaînes. C'est pourquoi il signale le dtype comme «objet».

Je vais sans vergogne brancher mon propre article de blog où j'en ai discuté à l'origine.


Bien écrit..Merci
tedd

1

À partir de la version 1.0.0 (janvier 2020), pandas a été introduit en tant que fonctionnalité expérimentale offrant un support de première classe pour les types de chaînes via pandas.StringDtype .

Alors que vous serez toujours voyez objectpar défaut, le nouveau type peut être utilisé en spécifiant un dtypedes pd.StringDtypeou simplement '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

2
Ne l'utilisez pas encore. Comme ils l'ont indiqué, The implementation may change without warning.ce qui signifie que les nouvelles mises à jour casseront vos anciens programmes.
NoName

1
Eh bien, tout dépend de l'usage que vous en ferez. Si vous souhaitez l'utiliser dans un système de production où des mises à niveau continues des packages sont nécessaires et où la rupture de l'API entraîne une charge de maintenance inacceptable, alors bien sûr, portez une attention particulière au mot «expérimental», mais si vous utilisez des pandas pour effectuer des explorations analyses dans des scripts dont la durée de vie n'augmente pas une journée de travail, alors ces préoccupations devraient signifier peu pour vous.
fuglede le

Depuis Pandas 1.1, l'API semble être stabilisée. Tous les dtypes peuvent maintenant être convertis en StringDtype .
D3f0
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.