Convertir les colonnes en chaîne dans Pandas


179

J'ai le DataFrame suivant à partir d'une requête SQL:

(Pdb) pp total_rows
     ColumnID  RespondentCount
0          -1                2
1  3030096843                1
2  3030096845                1

et je veux le faire pivoter comme ceci:

total_data = total_rows.pivot_table(cols=['ColumnID'])

(Pdb) pp total_data
ColumnID         -1            3030096843   3030096845
RespondentCount            2            1            1

[1 rows x 3 columns]


total_rows.pivot_table(cols=['ColumnID']).to_dict('records')[0]

{3030096843: 1, 3030096845: 1, -1: 2}

mais je veux m'assurer que les 303 colonnes sont converties en chaînes au lieu d'entiers afin que j'obtienne ceci:

{'3030096843': 1, '3030096845': 1, -1: 2}

Depuis pandas 1.0, la documentation recommande d'utiliser astype("string")au lieu deastype(str) pour de très bonnes raisons, jetez un œil.
cs95 il y a

Réponses:


333

Une façon de convertir en chaîne consiste à utiliser un type :

total_rows['ColumnID'] = total_rows['ColumnID'].astype(str)

Cependant, vous recherchez peut-être la to_jsonfonction, qui convertira les clés en json valide (et donc vos clés en chaînes):

In [11]: df = pd.DataFrame([['A', 2], ['A', 4], ['B', 6]])

In [12]: df.to_json()
Out[12]: '{"0":{"0":"A","1":"A","2":"B"},"1":{"0":2,"1":4,"2":6}}'

In [13]: df[0].to_json()
Out[13]: '{"0":"A","1":"A","2":"B"}'

Remarque: vous pouvez passer un tampon / fichier dans lequel enregistrer cela, ainsi que d'autres options ...


3
Je pense que to_string () est préférable en raison de la préservation des NULL stackoverflow.com/a/44008334/3647167
Keith

1
La conservation nulle de @Keith est intéressante. mais le document dit que son but est de «rendre un DataFrame en une sortie tabulaire conviviale pour la console». Je voudrais que quelqu'un
fasse

to_json()n'appelle probablement pas astype(str)car il quitte datetime64 et ses sous-classes en millisecondes depuis l'époque.
Sussch

1
@Sussch Je suppose que c'est parce que json n'a pas de format datetime explicite, donc vous êtes un peu obligé d'utiliser epoch. C'est-à-dire que je pense que c'est la norme.
Andy Hayden

50

Si vous avez besoin de convertir TOUTES les colonnes en chaînes, vous pouvez simplement utiliser:

df = df.astype(str)

Ceci est utile si vous avez besoin de tout sauf quelques colonnes pour être des chaînes / objets, puis revenez en arrière et convertissez les autres en tout ce dont vous avez besoin (entier dans ce cas):

 df[["D", "E"]] = df[["D", "E"]].astype(int) 

28

Voici l'autre, particulièrement utile pour convertir les multiples colonnes en chaîne au lieu d'une seule colonne:

In [76]: import numpy as np
In [77]: import pandas as pd
In [78]: df = pd.DataFrame({
    ...:     'A': [20, 30.0, np.nan],
    ...:     'B': ["a45a", "a3", "b1"],
    ...:     'C': [10, 5, np.nan]})
    ...: 

In [79]: df.dtypes ## Current datatype
Out[79]: 
A    float64
B     object
C    float64
dtype: object

## Multiple columns string conversion
In [80]: df[["A", "C"]] = df[["A", "C"]].astype(str) 

In [81]: df.dtypes ## Updated datatype after string conversion
Out[81]: 
A    object
B    object
C    object
dtype: object


0

pandas> = 1.0: Il est temps d'arrêter d'utiliser astype(str)!

Avant Pandas 1.0 (enfin, 0.25 en fait), c'était la façon de facto de déclarer une série / colonne comme une chaîne:

# pandas <= 0.25
# Note to pedants: specifying the type is unnecessary since pandas will 
# automagically infer the type as object
s = pd.Series(['a', 'b', 'c'], dtype=str)
s.dtype
# dtype('O')

À partir de pandas 1.0, envisagez d'utiliser le "string"type à la place.

# pandas >= 1.0
s = pd.Series(['a', 'b', 'c'], dtype="string")
s.dtype
# StringDtype

Voici pourquoi, comme cité par la documentation:

  1. Vous pouvez accidentellement stocker un mélange de chaînes et de non-chaînes dans un tableau objet dtype. Il vaut mieux avoir un dtype dédié.

  2. objectdtype interrompt les opérations spécifiques à dtype comme DataFrame.select_dtypes(). Il n'existe pas de moyen clair de sélectionner uniquement du texte tout en excluant les colonnes non textuelles mais toujours de type objet.

  3. Lors de la lecture de code, le contenu d'un objecttableau dtype est moins clair que 'string'.

Voir également la section sur les différences de comportement entre "string"etobject .

Les types d'extensions (introduits dans 0.24 et formalisés dans 1.0) sont plus proches des pandas que numpy, ce qui est bien car les types numpy ne sont pas assez puissants. Par exemple, NumPy n'a aucun moyen de représenter les données manquantes dans des données entières (depuis type(NaN) == float). Mais les pandas peuvent utiliser des colonnes Nullable Integer .


Pourquoi devrais-je arrêter de l'utiliser?

Mélange accidentel de dtypes
La première raison, comme indiqué dans la documentation, est que vous pouvez accidentellement stocker des données non textuelles dans des colonnes d'objets.

# pandas <= 0.25
pd.Series(['a', 'b', 1.23])   # whoops, this should have been "1.23"

0       a
1       b
2    1.23
dtype: object

pd.Series(['a', 'b', 1.23]).tolist()
# ['a', 'b', 1.23]   # oops, pandas was storing this as float all the time.
# pandas >= 1.0
pd.Series(['a', 'b', 1.23], dtype="string")

0       a
1       b
2    1.23
dtype: string

pd.Series(['a', 'b', 1.23], dtype="string").tolist()
# ['a', 'b', '1.23']   # it's a string and we just averted some potentially nasty bugs.

Difficulté à différencier les chaînes et les autres objets python
Un autre exemple évident est qu'il est plus difficile de faire la distinction entre les "chaînes" et les "objets". Les objets sont essentiellement le type de couverture pour tout type qui ne prend pas en charge les opérations vectorisables .

Considérer,

# Setup
df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [{}, [1, 2, 3], 123]})
df
 
   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

Jusqu'à pandas 0.25, il n'y avait pratiquement aucun moyen de distinguer que "A" et "B" n'ont pas le même type de données.

# pandas <= 0.25  
df.dtypes

A    object
B    object
dtype: object

df.select_dtypes(object)

   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

Depuis pandas 1.0, cela devient beaucoup plus simple:

# pandas >= 1.0
# Convenience function I call to help illustrate my point.
df = df.convert_dtypes()
df.dtypes

A    string
B    object
dtype: object

df.select_dtypes("string")

   A
0  a
1  b
2  c

Lisibilité
Cela va de soi ;-)


OK, devrais-je arrêter de l'utiliser maintenant?

...Non. Au moment de la rédaction de cette réponse (version 1.1), il n'y a aucun avantage en termes de performances, mais la documentation s'attend à des améliorations futures pour améliorer considérablement les performances et réduire l'utilisation de la mémoire pour les "string"colonnes par opposition aux objets. Cela dit, cependant, il n'est jamais trop tôt pour prendre de bonnes habitudes!


-1

L'utilisation .apply()avec une lambdafonction de conversion fonctionne également dans ce cas:

total_rows['ColumnID'] = total_rows['ColumnID'].apply(lambda x: str(x))

Pour des dataframes entiers, vous pouvez utiliser .applymap(). (mais en tout cas .astype()est probablement plus rapide)

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.