web-dev-qa-db-fra.com

Attribuer des dtypes à une colonne de données de pandas

Je veux définir les dtypes de plusieurs colonnes dans pd.Dataframe (j'ai un fichier que j'ai dû analyser manuellement dans une liste de listes, car le fichier n'était pas prêt pour pd.read_csv)

import pandas as pd
print pd.DataFrame([['a','1'],['b','2']],
                   dtype={'x':'object','y':'int'},
                   columns=['x','y'])

Je reçois

ValueError: entry not a 2- or 3- Tuple

Le seul moyen de les définir consiste à parcourir en boucle chaque variable de colonne et à procéder à une refonte avec astype

dtypes = {'x':'object','y':'int'}
mydata = pd.DataFrame([['a','1'],['b','2']],
                      columns=['x','y'])
for c in mydata.columns:
    mydata[c] = mydata[c].astype(dtypes[c])
print mydata['y'].dtype   #=> int64

Y a-t-il un meilleur moyen?

74
hatmatrix

Depuis 0.17, vous devez utiliser les conversions explicites:

pd.to_datetime, pd.to_timedelta and pd.to_numeric

(Comme mentionné ci-dessous, plus de "magie", convert_objects est obsolète en 0.17)

df = pd.DataFrame({'x': {0: 'a', 1: 'b'}, 'y': {0: '1', 1: '2'}, 'z': {0: '2018-05-01', 1: '2018-05-02'}})

df.dtypes

x    object
y    object
z    object
dtype: object

df

   x  y           z
0  a  1  2018-05-01
1  b  2  2018-05-02

Vous pouvez les appliquer à chaque colonne à convertir:

df["y"] = pd.to_numeric(df["y"])
df["z"] = pd.to_datetime(df["z"])    
df

   x  y          z
0  a  1 2018-05-01
1  b  2 2018-05-02

df.dtypes

x            object
y             int64
z    datetime64[ns]
dtype: object

et confirmez que le type est mis à jour.


RÉPONSE ANCIENNE/PÉRIMÉE des pandas 0.12 - 0.16: Vous pouvez utiliser convert_objects pour déduire de meilleurs types:

In [21]: df
Out[21]: 
   x  y
0  a  1
1  b  2

In [22]: df.dtypes
Out[22]: 
x    object
y    object
dtype: object

In [23]: df.convert_objects(convert_numeric=True)
Out[23]: 
   x  y
0  a  1
1  b  2

In [24]: df.convert_objects(convert_numeric=True).dtypes
Out[24]: 
x    object
y     int64
dtype: object

La magie! (Triste de le voir obsolète.)

43
Andy Hayden

Pour ceux qui viennent de Google (etc.) comme moi:

convert_objects est obsolète depuis le 0.17 - si vous l'utilisez, vous recevez un avertissement comme celui-ci: 

FutureWarning: convert_objects is deprecated.  Use the data-type specific converters 
pd.to_datetime, pd.to_timedelta and pd.to_numeric.

Vous devriez faire quelque chose comme ce qui suit:

56
Jack Yates

vous pouvez définir les types explicitement avec pandas DataFrame.astype(dtype, copy=True, raise_on_error=True, **kwargs) et transmettre un dictionnaire avec les types que vous souhaitez dtype

voici un exemple:

import pandas as pd
wheel_number = 5
car_name = 'jeep'
minutes_spent = 4.5

# set the columns
data_columns = ['wheel_number', 'car_name', 'minutes_spent']

# create an empty dataframe
data_df = pd.DataFrame(columns = data_columns)
df_temp = pd.DataFrame([[wheel_number, car_name, minutes_spent]],columns = data_columns)
data_df = data_df.append(df_temp, ignore_index=True) 

In [11]: data_df.dtypes
Out[11]:
wheel_number     float64
car_name          object
minutes_spent    float64
dtype: object

data_df = data_df.astype(dtype= {"wheel_number":"int64",
        "car_name":"object","minutes_spent":"float64"})

maintenant vous pouvez voir que ça a changé

In [18]: data_df.dtypes
Out[18]:
wheel_number       int64
car_name          object
minutes_spent    float64
24
Lauren

Une autre façon de définir les types de colonne consiste à créer tout d'abord un tableau numpy record avec les types souhaités, à le compléter puis à le transmettre à un constructeur DataFrame.

import pandas as pd
import numpy as np    

x = np.empty((10,), dtype=[('x', np.uint8), ('y', np.float64)])
df = pd.DataFrame(x)

df.dtypes ->

x      uint8
y    float64
8
Kaushik Ghose

Il vaut mieux utiliser np.arrays, puis passer les noms de données et de colonnes sous forme de dictionnaire.

import numpy as np
import pandas as pd
# Feature: np arrays are 1: efficient, 2: can be pre-sized
x = np.array(['a', 'b'], dtype=object)
y = np.array([ 1 ,  2 ], dtype=np.int32)
df = pd.DataFrame({
   'x' : x,    # Feature: column name is near data array
   'y' : y,
   }
 )
0
Clem Wang

face à un problème similaire à vous. Dans mon cas, j'ai des milliers de fichiers de journaux de Cisco que je dois analyser manuellement.

Afin d'être flexible avec les champs et les types, j'ai testé avec succès l'utilisation de StringIO + read_cvs qui accepte effectivement un dict pour la spécification dtype.

Je reçois habituellement chacun des fichiers (5 à 20k lignes) dans un tampon et crée les dictionnaires dtype dynamiquement.

Finalement, je concatène (de manière catégorique ... grâce à 0.19) ces images en un grand bloc de données que je sauvegarde en hdf5. 

Quelque chose dans ce sens

import pandas as pd
import io 

output = io.StringIO()
output.write('A,1,20,31\n')
output.write('B,2,21,32\n')
output.write('C,3,22,33\n')
output.write('D,4,23,34\n')

output.seek(0)


df=pd.read_csv(output, header=None,
        names=["A","B","C","D"],
        dtype={"A":"category","B":"float32","C":"int32","D":"float64"},
        sep=","
       )

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 4 columns):
A    5 non-null category
B    5 non-null float32
C    5 non-null int32
D    5 non-null float64
dtypes: category(1), float32(1), float64(1), int32(1)
memory usage: 205.0 bytes
None

Pas très pythonique .... mais fait le travail

J'espère que ça aide.

JC

0
Julian C