Weisen Sie pandas dataframe column dtypes zu


109

Ich möchte das dtypes mehrerer Spalten festlegen pd.Dataframe(Ich habe eine Datei, die ich manuell in eine Liste von Listen analysieren musste, da die Datei nicht zugänglich war pd.read_csv).

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

Ich bekomme

ValueError: entry not a 2- or 3- tuple

Die einzige Möglichkeit, sie festzulegen, besteht darin, jede Spaltenvariable zu durchlaufen und mit neu zu formulieren 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

Gibt es einen besseren Weg?


Dies wäre vielleicht eine gute Fehler- / Feature-Anfrage . Derzeit bin ich mir nicht sicher, was dtype arg tut (Sie können es als Skalar übergeben, aber es ist nicht streng) ...
Andy Hayden

2
Zu Ihrer Information: df = pd.DataFrame([['a','1'],['b','2']], dtype='int', columns=['x','y'])"funktioniert" ... aber: s
Andy Hayden

1
Ja, "funktioniert" tatsächlich; unvorhersehbar ...
Hatmatrix

Dieses GitHub-Problem könnte bald relevant werden: github.com/pydata/pandas/issues/9287
Amelio Vazquez-Reina

Antworten:


64

Seit 0.17 müssen Sie die expliziten Konvertierungen verwenden:

pd.to_datetime, pd.to_timedelta and pd.to_numeric

(Wie unten erwähnt, convert_objectswurde in 0.17 keine "Magie" mehr verworfen.)

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

Sie können diese auf jede Spalte anwenden, die Sie konvertieren möchten:

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

und bestätigen Sie, dass der dtype aktualisiert wurde.


ALTE / VERRINGERTE ANTWORT für Pandas 0.12 - 0.16: Sie können verwenden convert_objects, um bessere d-Typen abzuleiten:

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

Magie! (Traurig zu sehen, dass es veraltet ist.)


2
wie type.convertin R ein bisschen; nett, lässt aber in einigen Fällen explizite Angaben zu.
Hatmatrix

1
Seien Sie vorsichtig, wenn Sie eine Spalte haben, die eine Zeichenfolge sein muss, aber mindestens einen Wert enthält, der in einen int konvertiert werden kann. Alles was es braucht ist ein Wert und das gesamte Feld wird in float64 konvertiert
Michael David Watson

18
Ich habe festgestellt, dass convert_objects()es veraltet ist ... Ich bin nicht sicher, was es ersetzt hat?
Joe vom

6
Verwenden Sie DataFrame.infer_objects ()
James Tobin am

1
@smci okay, ich habe bearbeitet. Es gibt eine Menge veralteter Antworten. Ich muss einen Weg finden, um sie alle zu finden.
Andy Hayden

62

Für diejenigen, die von Google (usw.) kommen, wie ich:

convert_objects ist seit 0.17 veraltet - wenn Sie es verwenden, erhalten Sie eine Warnung wie diese:

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

Sie sollten etwa Folgendes tun:


Wenn Sie einige Beispiele pd.to_datetime, to_timedelta, to_numericdafür hineingeworfen haben, sollte dies die akzeptierte Antwort sein.
smci

41

Sie können die Typen explizit mit Pandas DataFrame.astype(dtype, copy=True, raise_on_error=True, **kwargs)festlegen und ein Wörterbuch mit den gewünschten dtypes übergebendtype

Hier ist ein Beispiel:

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

Jetzt können Sie sehen, dass es sich geändert hat

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

13

Eine andere Möglichkeit, die Spaltentypen festzulegen, besteht darin, zuerst ein Numpy-Datensatz-Array mit den gewünschten Typen zu erstellen, es auszufüllen und dann an einen DataFrame-Konstruktor zu übergeben.

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

vor einem ähnlichen Problem wie Sie. In meinem Fall habe ich Tausende von Dateien aus Cisco-Protokollen, die ich manuell analysieren muss.

Um mit Feldern und Typen flexibel zu sein, habe ich erfolgreich mit StringIO + read_cvs getestet, das tatsächlich ein Diktat für die dtype-Spezifikation akzeptiert.

Normalerweise bekomme ich jede der Dateien (5k-20k Zeilen) in einen Puffer und erstelle die dtype-Wörterbücher dynamisch.

Schließlich verkette ich diese Datenrahmen (mit kategorischen ... dank 0.19) zu einem großen Datenrahmen, den ich in hdf5 ablege.

Etwas in diese Richtung

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

Nicht sehr pythonisch ... aber macht den Job

Ich hoffe es hilft.

JC


0

Verwenden Sie besser typisierte np.arrays und übergeben Sie die Daten- und Spaltennamen als Wörterbuch.

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,
   }
 )
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.