Assegna i dtypes di colonna dataframe panda


111

Voglio impostare gli dtypes di più colonne in pd.Dataframe(ho un file che ho dovuto analizzare manualmente in un elenco di elenchi, poiché il file non era suscettibile di pd.read_csv)

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

ottengo

ValueError: entry not a 2- or 3- tuple

L'unico modo in cui posso impostarli è scorrere ogni variabile di colonna e riformulare con 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

C'è un modo migliore?


Questa potrebbe forse essere una buona richiesta di bug / funzionalità , attualmente non sono sicuro di cosa stia facendo dtype arg (puoi passarlo uno scalare, ma non è rigoroso) ...
Andy Hayden

2
FYI: df = pd.DataFrame([['a','1'],['b','2']], dtype='int', columns=['x','y'])"funziona" ... ma: s
Andy Hayden

1
Sì, "funziona" davvero; imprevedibilmente ...
hatmatrix

Questo problema di GitHub potrebbe presto diventare rilevante: github.com/pydata/pandas/issues/9287
Amelio Vazquez-Reina

Risposte:


65

Dalla 0.17, devi usare le conversioni esplicite:

pd.to_datetime, pd.to_timedelta and pd.to_numeric

(Come accennato di seguito, niente più "magia", convert_objectsè stato deprecato nella 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

Puoi applicarli a ciascuna colonna che desideri convertire:

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

e confermare che dtype sia aggiornato.


RISPOSTA VECCHIA / DEPRECATA per i panda 0,12 - 0,16: puoi utilizzare convert_objectsper dedurre tipi migliori:

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

Magia! (Triste vederlo deprecato.)


2
come type.convertin R un po '; bello ma in alcuni casi lascia il desiderio di specifiche esplicite.
hatmatrix

1
Fai attenzione se hai una colonna che deve essere una stringa ma contiene almeno un valore che potrebbe essere convertito in un int. Tutto ciò che serve è un valore e l'intero campo viene convertito in float64
Michael David Watson

18
Ho notato che convert_objects()è stato deprecato ... non sono sicuro di cosa lo abbia sostituito?
joe dal

6
Per dedurre nuovamente i dtypes di dati per le colonne degli oggetti, utilizzare DataFrame.infer_objects ()
James Tobin

1
@smci va bene, ho modificato. Ci sono un sacco di risposte deprecate, devo trovare un modo per trovarle tutte.
Andy Hayden

62

Per chi proviene da Google (ecc.) Come me:

convert_objects è stato deprecato dalla 0.17 - se lo usi, ricevi un avviso come questo:

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

Dovresti fare qualcosa come il seguente:


Se hai inserito alcuni esempi, pd.to_datetime, to_timedelta, to_numericquesta dovrebbe essere la risposta accettata.
smci

41

puoi impostare i tipi esplicitamente con i panda DataFrame.astype(dtype, copy=True, raise_on_error=True, **kwargs)e passare in un dizionario con i dtypes che desideridtype

ecco un esempio:

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"})

ora puoi vedere che è cambiato

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

13

Un altro modo per impostare i tipi di colonna consiste nel costruire prima un array di record numpy con i tipi desiderati, compilarlo e quindi passarlo a un costruttore 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

0

affrontare un problema simile a te. Nel mio caso ho migliaia di file dai registri Cisco che devo analizzare manualmente.

Per essere flessibile con campi e tipi ho testato con successo usando StringIO + read_cvs che in effetti accetta un dict per la specifica dtype.

Di solito ottengo ciascuno dei file (5k-20k righe) in un buffer e creo dinamicamente i dizionari dtype.

Alla fine concateno (con categorico ... grazie a 0.19) questi dataframe in un grande data frame che scarico in hdf5.

Qualcosa in questo senso

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

Non molto pitonico ... ma fa il lavoro

Spero che sia d'aiuto.

JC


0

È meglio usare np.arrays digitato e quindi passare i dati ei nomi delle colonne come dizionario.

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,
   }
 )
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.