1533 votes

Changer le type de colonne dans pandas

Je veux convertir un tableau, représenté comme une liste de listes, en un DataFrame pandas. Voici un exemple extrêmement simplifié :

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a)

Quelle est la meilleure façon de convertir les colonnes dans les types appropriés, dans ce cas les colonnes 2 et 3 en flottants ? Existe-t-il un moyen de spécifier les types lors de la conversion en DataFrame ? Ou est-il préférable de créer d'abord le DataFrame, puis de parcourir les colonnes en boucle pour changer le type de chaque colonne ? Idéalement, je voudrais faire cela de manière dynamique car il peut y avoir des centaines de colonnes et je ne veux pas spécifier exactement quelles colonnes sont de quel type. Tout ce que je peux garantir, c'est que chaque colonne contient des valeurs du même type.

2560voto

ajcr Points 4047

Vous disposez de quatre options principales pour convertir les types dans pandas :

  1. to_numeric() - fournit une fonctionnalité permettant de convertir en toute sécurité des types non numériques (par exemple, des chaînes de caractères) en un type numérique approprié. (Voir aussi to_datetime() y to_timedelta() .)

  2. astype() - convertir (presque) tous les types en (presque) tous les autres types (même s'il n'est pas forcément judicieux de le faire). Permet également de convertir en catégoriel (très utile).

  3. infer_objects() - une méthode utilitaire pour convertir les colonnes d'objets contenant des objets Python en un type pandas si possible.

  4. convert_dtypes() - convertir les colonnes de DataFrame au "meilleur" dtype possible qui supporte pd.NA (objet de pandas pour indiquer une valeur manquante).

Lisez la suite pour des explications plus détaillées et l'utilisation de chacune de ces méthodes.


1. to_numeric()

La meilleure façon de convertir une ou plusieurs colonnes d'un DataFrame en valeurs numériques est d'utiliser la méthode suivante pandas.to_numeric() .

Cette fonction essaiera de transformer les objets non numériques (tels que les chaînes de caractères) en nombres entiers ou en nombres à virgule flottante, selon le cas.

Utilisation de base

L'entrée de l to_numeric() est une série ou une colonne unique d'un DataFrame.

>>> s = pd.Series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values
>>> s
0      8
1      6
2    7.5
3      3
4    0.9
dtype: object

>>> pd.to_numeric(s) # convert everything to float values
0    8.0
1    6.0
2    7.5
3    3.0
4    0.9
dtype: float64

Comme vous pouvez le voir, une nouvelle série est renvoyée. N'oubliez pas d'affecter cette sortie à une variable ou à un nom de colonne pour continuer à l'utiliser :

# convert Series
my_series = pd.to_numeric(my_series)

# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])

Vous pouvez également l'utiliser pour convertir plusieurs colonnes d'un DataFrame via la fonction apply() méthode :

# convert all columns of DataFrame
df = df.apply(pd.to_numeric) # convert all columns of DataFrame

# convert just columns "a" and "b"
df[["a", "b"]] = df[["a", "b"]].apply(pd.to_numeric)

Tant que vos valeurs peuvent toutes être converties, c'est probablement tout ce dont vous avez besoin.

Traitement des erreurs

Mais que faire si certaines valeurs ne peuvent pas être converties en un type numérique ?

to_numeric() prend également un errors qui vous permet de forcer des valeurs non numériques à être NaN ou simplement ignorer les colonnes contenant ces valeurs.

Voici un exemple utilisant une série de chaînes de caractères s qui a le dtype de l'objet :

>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0         1
1         2
2       4.7
3    pandas
4        10
dtype: object

Le comportement par défaut est de relancer le système s'il ne peut pas convertir une valeur. Dans ce cas, il ne peut pas convertir la chaîne de caractères 'pandas' :

>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string

Plutôt que d'échouer, nous pourrions vouloir que 'pandas' soit considéré comme une valeur numérique manquante/mauvaise. Nous pouvons contraindre les valeurs invalides à NaN comme suit en utilisant le errors l'argument du mot-clé :

>>> pd.to_numeric(s, errors='coerce')
0     1.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

La troisième option pour errors consiste simplement à ignorer l'opération si une valeur non valide est rencontrée :

>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched

Cette dernière option est particulièrement utile pour convertir l'ensemble de votre DataFrame, mais vous ne savez pas lesquelles de nos colonnes peuvent être converties de manière fiable en type numérique. Dans ce cas, il suffit d'écrire :

df.apply(pd.to_numeric, errors='ignore')

La fonction sera appliquée à chaque colonne du DataFrame. Les colonnes qui peuvent être converties en un type numérique seront converties, tandis que les colonnes qui ne le peuvent pas (par exemple, si elles contiennent des chaînes de caractères sans chiffres ou des dates) seront laissées telles quelles.

Coulée descendante

Par défaut, la conversion avec to_numeric() vous donnera soit un int64 o float64 dtype (ou toute autre largeur d'entier propre à votre plate-forme).

C'est généralement ce que l'on souhaite, mais que se passe-t-il si l'on veut économiser de la mémoire et utiliser un dtype plus compact, tel que float32 o int8 ?

to_numeric() vous donne la possibilité d'effectuer un downcast vers 'integer' , 'signed' , 'unsigned' , 'float' . Voici un exemple pour une série simple s de type entier :

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Diffusion descendante vers 'integer' utilise le plus petit nombre entier possible qui peut contenir les valeurs :

>>> pd.to_numeric(s, downcast='integer')
0    1
1    2
2   -7
dtype: int8

Diffusion descendante vers 'float' choisit de la même manière un type flottant plus petit que la normale :

>>> pd.to_numeric(s, downcast='float')
0    1.0
1    2.0
2   -7.0
dtype: float32

2. astype()

El astype() vous permet d'être explicite quant au type de données que vous voulez donner à votre DataFrame ou à votre série. Elle est très polyvalente dans la mesure où vous pouvez essayer de passer d'un type à un autre.

Utilisation de base

Choisissez simplement un type : vous pouvez utiliser un dtype NumPy (par ex. np.int16 ), certains types Python (par exemple bool), ou des types spécifiques à pandas (comme le dtype categorical).

Appelez la méthode sur l'objet que vous voulez convertir et astype() va essayer de le convertir pour vous :

# convert all DataFrame columns to the int64 dtype
df = df.astype(int)

# convert column "a" to int64 dtype and "b" to complex type
df = df.astype({"a": int, "b": complex})

# convert Series to float16 type
s = s.astype(np.float16)

# convert Series to Python strings
s = s.astype(str)

# convert Series to categorical type - see docs for more details
s = s.astype('category')

Remarquez que j'ai dit "essayer" - si astype() ne sait pas comment convertir une valeur dans le Series ou le DataFrame, il émet une erreur. Par exemple, si vous avez un NaN o inf vous obtiendrez une erreur en essayant de la convertir en un nombre entier.

À partir de la version 0.20.0 de pandas, cette erreur peut être supprimée en passant la commande errors='ignore' . Votre objet original vous sera rendu intact.

Soyez prudent.

astype() est puissant, mais il convertit parfois les valeurs de manière "incorrecte". Par exemple :

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Il s'agit de petits entiers, alors pourquoi ne pas les convertir en un type 8 bits non signé pour économiser de la mémoire ?

>>> s.astype(np.uint8)
0      1
1      2
2    249
dtype: uint8

La conversion a fonctionné, mais le -7 a été enroulé pour devenir 249 (c'est-à-dire 2 8 - 7) !

J'essaie d'abaisser le niveau en utilisant pd.to_numeric(s, downcast='unsigned') à la place pourrait aider à prévenir cette erreur.


3. infer_objects()

La version 0.21.0 de pandas a introduit la méthode infer_objects() pour convertir les colonnes d'un DataFrame qui ont un type de données objet en un type plus spécifique (conversions douces).

Par exemple, voici un DataFrame avec deux colonnes de type objet. L'une contient des entiers réels et l'autre des chaînes de caractères représentant des entiers :

>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a    object
b    object
dtype: object

Utilisation de infer_objects() vous pouvez changer le type de la colonne 'a' en int64 :

>>> df = df.infer_objects()
>>> df.dtypes
a     int64
b    object
dtype: object

La colonne "b" n'a pas été modifiée car ses valeurs étaient des chaînes de caractères et non des nombres entiers. Si vous vouliez forcer les deux colonnes à un type entier, vous pourriez utiliser df.astype(int) à la place.


4. convert_dtypes()

Les versions 1.0 et supérieures comprennent une méthode convert_dtypes() pour convertir les colonnes de Series et de DataFrame dans le meilleur dtype possible qui prend en charge la fonction pd.NA valeur manquante.

Ici, "le meilleur possible" signifie le type le plus approprié pour contenir les valeurs. Par exemple, il s'agit d'un type pandas integer, si toutes les valeurs sont des entiers (ou des valeurs manquantes) : une colonne d'objets Python integer est convertie en Int64 une colonne de NumPy int32 deviendra le dtype pandas. Int32 .

Avec notre object Cadre de données df nous obtenons le résultat suivant :

>>> df.convert_dtypes().dtypes                                             
a     Int64
b    string
dtype: object

Comme la colonne 'a' contenait des valeurs entières, elle a été convertie au format Int64 (qui peut contenir des valeurs manquantes, à la différence de l'option int64 ).

La colonne 'b' contenait des objets de type chaîne, elle a donc été remplacée par la colonne 'pandas'. string dtype.

Par défaut, cette méthode déduit le type à partir des valeurs des objets dans chaque colonne. Nous pouvons changer cela en passant infer_objects=False :

>>> df.convert_dtypes(infer_objects=False).dtypes                          
a    object
b    string
dtype: object

Maintenant, la colonne 'a' est restée une colonne objet : pandas sait qu'elle peut être décrite comme une colonne 'integer' (en interne, elle s'appelle infer_dtype ) mais n'a pas déduit exactement quel type d'entier il devait avoir et ne l'a donc pas converti. La colonne "b" a de nouveau été convertie en type "string", car elle était reconnue comme contenant des valeurs "string".

11 votes

De plus, contrairement à .astype(float), cette méthode convertit les chaînes de caractères en NaNs au lieu de générer une erreur.

17 votes

.convert_objects est dépravé depuis 0.17 - utiliser df.to_numeric au lieu de

1 votes

Existe-t-il un moyen de error=coerce sur astype() ?

547voto

hernamesbarbara Points 1229

Que pensez-vous de ça ?

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])
df
Out[16]: 
  one  two three
0   a  1.2   4.2
1   b   70  0.03
2   x    5     0

df.dtypes
Out[17]: 
one      object
two      object
three    object

df[['two', 'three']] = df[['two', 'three']].astype(float)

df.dtypes
Out[19]: 
one       object
two      float64
three    float64

11 votes

Oui ! pd.DataFrame a un dtype qui pourrait vous permettre de faire ce que vous cherchez. df = pd.DataFrame(a, columns=['one', 'two', 'three'], dtype=float) In [2] : df.dtypes Out[2] : one object two float64 three float64 dtype : object

23 votes

Lorsque j'essaie comme suggéré, j'obtiens un avertissement SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead . Cela a peut-être été introduit dans une version plus récente de pandas et je ne vois rien de mal à cela, mais je me demande juste à quoi correspond cet avertissement. Avez-vous une idée ?

2 votes

@orange l'avertissement a pour but d'avertir les utilisateurs d'un comportement potentiellement déroutant avec les opérations enchaînées, et avec pandas qui renvoie des copies plutôt que de modifier les cadres de données. voir stackoverflow.com/questions/20625582/ et connexes.

55voto

Akash Nayak Points 655

Ce code ci-dessous va changer le type de données de la colonne.

df[['col.name1', 'col.name2'...]] = df[['col.name1', 'col.name2'..]].astype('data_type')

à la place du type de données, vous pouvez donner votre type de données, ce que vous voulez, comme str, float, int, etc.

2 votes

Notez que lorsque vous appliquez cette méthode à une colonne contenant les chaînes de caractères " True " et " False ", en utilisant le type de données " data_type ", vous n'avez pas à vous préoccuper de la qualité des données. bool tout est changé en True .

0 votes

Cette option peut également être convertie en type "catégorie".

35voto

Thom Ives Points 847

Lorsque je n'ai eu besoin de spécifier que des colonnes spécifiques, et que je voulais être explicite, j'ai utilisé (per EMPLACEMENT DES DOCS ):

dataframe = dataframe.astype({'col_name_1':'int','col_name_2':'float64', etc. ...})

Donc, en utilisant la question originale, mais en lui donnant des noms de colonnes ...

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col_name_1', 'col_name_2', 'col_name_3'])
df = df.astype({'col_name_2':'float64', 'col_name_3':'float64'})

28voto

coldspeed Points 111053

Pandas >= 1.0

Voici un tableau qui résume certaines des conversions les plus importantes dans les pandas.

enter image description here

Les conversions en chaîne de caractères sont triviales .astype(str) et ne sont pas représentés sur la figure.

"Conversions "dures" et "douces

Notez que dans ce contexte, le terme "conversion" peut désigner soit la conversion de données textuelles dans leur type de données réel (conversion dure), soit la déduction de types de données plus appropriés pour les données des colonnes d'objets (conversion souple). Pour illustrer la différence, regardez

df = pd.DataFrame({'a': ['1', '2', '3'], 'b': [4, 5, 6]}, dtype=object)
df.dtypes                                                                  

a    object
b    object
dtype: object

# Actually converts string to numeric - hard conversion
df.apply(pd.to_numeric).dtypes                                             

a    int64
b    int64
dtype: object

# Infers better data types for object data - soft conversion
df.infer_objects().dtypes                                                  

a    object  # no change
b     int64
dtype: object

# Same as infer_objects, but converts to equivalent ExtensionType
df.convert_dtypes().dtypes

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X