Ich möchte eine Tabelle, die als Liste von Listen dargestellt wird, in einen Pandas DataFrame konvertieren. Als extrem vereinfachtes Beispiel:
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a)
Wie konvertiere ich die Spalten am besten in die entsprechenden Typen, in diesem Fall die Spalten 2 und 3 in Floats? Gibt es eine Möglichkeit, die Typen bei der Konvertierung in DataFrame anzugeben? Oder ist es besser, zuerst den DataFrame zu erstellen und dann die Spalten zu durchlaufen, um den Typ für jede Spalte zu ändern? Idealerweise würde ich das gerne dynamisch tun, da es hunderte von Spalten geben kann und ich nicht genau angeben möchte, welche Spalten welchen Typs sind. Ich kann nur garantieren, dass jede Spalte Werte des gleichen Typs enthält.
Sie haben drei Hauptoptionen zum Konvertieren von Typen in Pandas:
to_numeric()
- Bietet Funktionen zum sicheren Konvertieren nicht numerischer Typen (z. B. Zeichenfolgen) in einen geeigneten numerischen Typ. (Siehe auch to_datetime()
und to_timedelta()
.)
astype()
- konvertiere (fast) jeden Typ in (fast) jeden anderen Typ (auch wenn das nicht unbedingt sinnvoll ist). Ermöglicht auch das Konvertieren in kategorial Typen (sehr nützlich).
infer_objects()
- eine Dienstprogrammmethode zum Konvertieren von Objektspalten, die Python Objekte enthalten, in einen pandas Typ, wenn möglich.
Lesen Sie weiter, um detailliertere Erklärungen und die Verwendung dieser Methoden zu erhalten.
to_numeric()
Am besten konvertieren Sie eine oder mehrere Spalten eines DataFrames in numerische Werte, indem Sie pandas.to_numeric()
verwenden.
Mit dieser Funktion wird versucht, nicht numerische Objekte (z. B. Zeichenfolgen) in Ganzzahlen oder Gleitkommazahlen umzuwandeln.
Die Eingabe für to_numeric()
ist eine Reihe oder eine einzelne Spalte eines DataFrames.
>>> 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
Wie Sie sehen, wird eine neue Serie zurückgegeben. Denken Sie daran, diese Ausgabe einem Variablen- oder Spaltennamen zuzuweisen, um sie weiterhin zu verwenden:
# convert Series
my_series = pd.to_numeric(my_series)
# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])
Sie können damit auch mehrere Spalten eines DataFrames mit der apply()
-Methode konvertieren:
# 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)
Solange Ihre Werte alle konvertiert werden können, ist das wahrscheinlich alles, was Sie brauchen.
Was aber, wenn einige Werte nicht in einen numerischen Typ konvertiert werden können?
to_numeric()
akzeptiert auch ein errors
- Schlüsselwortargument, mit dem Sie erzwingen können, dass nicht numerische Werte NaN
sind, oder Spalten, die diese Werte enthalten, einfach ignorieren.
Hier ist ein Beispiel mit einer Reihe von Zeichenfolgen s
mit dem Objekt dtype:
>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0 1
1 2
2 4.7
3 pandas
4 10
dtype: object
Das Standardverhalten ist das Erhöhen, wenn ein Wert nicht konvertiert werden kann. In diesem Fall kann die Zeichenfolge 'pandas' nicht verarbeitet werden:
>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string
Anstatt zu scheitern, möchten wir, dass 'Pandas' als fehlender/falscher numerischer Wert betrachtet werden. Mit dem Schlüsselwortargument NaN
können ungültige Werte wie folgt in errors
umgewandelt werden:
>>> pd.to_numeric(s, errors='coerce')
0 1.0
1 2.0
2 4.7
3 NaN
4 10.0
dtype: float64
Die dritte Option für errors
besteht darin, die Operation zu ignorieren, wenn ein ungültiger Wert auftritt:
>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched
Diese letzte Option ist besonders nützlich, wenn Sie Ihren gesamten DataFrame konvertieren möchten, aber nicht wissen, welche unserer Spalten zuverlässig in einen numerischen Typ konvertiert werden können. In diesem Fall schreiben Sie einfach:
df.apply(pd.to_numeric, errors='ignore')
Die Funktion wird auf jede Spalte des DataFrames angewendet. Spalten, die in einen numerischen Typ konvertiert werden können, werden konvertiert, während Spalten, die nicht konvertiert werden können (z. B. Zeichenfolgen oder Datumsangaben, die keine Ziffern enthalten), in Ruhe gelassen werden.
Standardmäßig erhalten Sie bei der Konvertierung mit to_numeric()
entweder einen D-Typ int64
Oder float64
(Oder eine ganzzahlige Breite, die für Ihre Plattform typisch ist).
Das ist normalerweise das, was Sie wollen, aber was, wenn Sie etwas Speicher sparen und einen kompakteren D-Typ wie float32
Oder int8
Verwenden möchten?
to_numeric()
gibt Ihnen die Möglichkeit, einen Downcast auf 'Integer', 'Signed', 'Unsigned' oder 'Float' durchzuführen. Hier ist ein Beispiel für eine einfache Reihe s
vom Typ Integer:
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
Beim Downcasting auf "Ganzzahl" wird die kleinstmögliche Ganzzahl verwendet, die die folgenden Werte enthalten kann:
>>> pd.to_numeric(s, downcast='integer')
0 1
1 2
2 -7
dtype: int8
Beim Downcasting zum 'Floaten' wird auf ähnliche Weise ein kleinerer als der normale Floating-Typ ausgewählt:
>>> pd.to_numeric(s, downcast='float')
0 1.0
1 2.0
2 -7.0
dtype: float32
astype()
Mit der astype()
-Methode können Sie explizit angeben, welchen D-Typ Ihr DataFrame oder Ihre Serie haben soll. Es ist sehr vielseitig, da Sie versuchen können, von einem Typ zum anderen zu wechseln.
Wählen Sie einfach einen Typ aus: Sie können einen NumPy-D-Typ (z. B. np.int16
), Einige Python Typen (z. B. bool) oder pandaspezifische Typen (wie den kategorialen D-Typ) verwenden.
Rufen Sie die Methode für das Objekt auf, das Sie konvertieren möchten, und astype()
wird versuchen, sie für Sie zu konvertieren:
# 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')
Beachten Sie, dass ich "try" gesagt habe - wenn astype()
nicht weiß, wie ein Wert in der Serie oder im DataFrame konvertiert wird, wird ein Fehler ausgelöst. Wenn Sie beispielsweise einen Wert für NaN
oder inf
haben, wird beim Versuch, ihn in eine Ganzzahl umzuwandeln, eine Fehlermeldung angezeigt.
Ab pandas 0.20.0) kann dieser Fehler durch Übergabe von errors='ignore'
Unterdrückt werden. Ihr ursprüngliches Objekt wird unberührt zurückgegeben.
astype()
ist mächtig, konvertiert aber manchmal Werte "falsch". Zum Beispiel:
>>> s = pd.Series([1, 2, -7])
>>> s
0 1
1 2
2 -7
dtype: int64
Dies sind kleine Ganzzahlen. Wie wäre es also mit der Konvertierung in einen 8-Bit-Typ ohne Vorzeichen, um Speicherplatz zu sparen?
>>> s.astype(np.uint8)
0 1
1 2
2 249
dtype: uint8
Die Umwandlung funktionierte, aber die -7 wurde auf 249 (d. H. 2) umbrochen8 - 7)!
Der Versuch, mit pd.to_numeric(s, downcast='unsigned')
einen Downcast durchzuführen, kann diesen Fehler verhindern.
infer_objects()
In Version 0.21.0 von pandas) wurde die Methode infer_objects()
zum Konvertieren von Spalten eines DataFrame mit einem Objektdatentyp in einen spezifischeren Typ (soft) eingeführt Umbauten).
Hier ist beispielsweise ein DataFrame mit zwei Spalten des Objekttyps. Einer enthält tatsächliche Ganzzahlen und der andere enthält Zeichenfolgen, die Ganzzahlen darstellen:
>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a object
b object
dtype: object
Mit infer_objects()
können Sie den Spaltentyp 'a' in int64 ändern:
>>> df = df.infer_objects()
>>> df.dtypes
a int64
b object
dtype: object
Die Spalte 'b' wurde alleine gelassen, da es sich bei den Werten um Zeichenfolgen und nicht um Ganzzahlen handelte. Wenn Sie versuchen möchten, die Konvertierung beider Spalten in einen Integer-Typ zu erzwingen, können Sie stattdessen df.astype(int)
verwenden.
Wie wäre es damit?
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
dieser Code ändert den Datentyp der Spalte.
df[['col.name1', 'col.name2'...]] = df[['col.name1', 'col.name2'..]].astype('data_type')
anstelle des Datentyps können Sie Ihrem Datentyp .Was möchten Sie wie Str, Float, Int usw.
Hier ist eine Funktion, die als Argument einen DataFrame und eine Liste von Spalten verwendet und alle Daten in den Spalten in Zahlen umwandelt.
# df is the DataFrame, and column_list is a list of columns as strings (e.g ["col1","col2","col3"])
# dependencies: pandas
def coerce_df_columns_to_numeric(df, column_list):
df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')
Also für dein Beispiel:
import pandas as pd
def coerce_df_columns_to_numeric(df, column_list):
df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')
a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col1','col2','col3'])
coerce_df_columns_to_numeric(df, ['col2','col3'])
Wie wäre es, zwei Datenrahmen mit jeweils unterschiedlichen Datentypen für ihre Spalten zu erstellen und diese dann zusammenzufügen?
d1 = pd.DataFrame(columns=[ 'float_column' ], dtype=float)
d1 = d1.append(pd.DataFrame(columns=[ 'string_column' ], dtype=str))
Ergebnisse
In[8}: d1.dtypes
Out[8]:
float_column float64
string_column object
dtype: object
Nach der Erstellung des Datenrahmens können Sie in der 1. Spalte Fließkomma-Variablen und in der 2. Spalte Zeichenfolgen (oder einen beliebigen Datentyp) angeben.
Wenn ich nur bestimmte Spalten angeben musste und explizit sein möchte, habe ich (per DOCS LOCATION ) Folgendes verwendet:
dataframe = dataframe.astype({'col_name_1':'int','col_name_2':'float64', etc. ...})
Also, die ursprüngliche Frage verwenden, aber Spaltennamen angeben ...
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'})
Ich dachte, ich hätte das gleiche Problem, aber tatsächlich habe ich einen kleinen Unterschied, der das Problem leichter zu lösen macht. Für andere, die sich diese Frage ansehen, sollten Sie das Format Ihrer Eingabeliste überprüfen. In meinem Fall handelt es sich bei den Zahlen zunächst um Floats und nicht um Strings wie in der Frage:
a = [['a', 1.2, 4.2], ['b', 70, 0.03], ['x', 5, 0]]
durch die Verarbeitung der Liste zu viel vor dem Erstellen des Datenrahmens verliere ich die Typen und alles wird zu einem String.
Erstellen des Datenrahmens über ein numpy-Array
df = pd.DataFrame(np.array(a))
df
Out[5]:
0 1 2
0 a 1.2 4.2
1 b 70 0.03
2 x 5 0
df[1].dtype
Out[7]: dtype('O')
gibt den gleichen Datenrahmen wie in der Frage an, wobei die Einträge in den Spalten 1 und 2 als Zeichenfolgen betrachtet werden. Jedoch tun
df = pd.DataFrame(a)
df
Out[10]:
0 1 2
0 a 1.2 4.20
1 b 70.0 0.03
2 x 5.0 0.00
df[1].dtype
Out[11]: dtype('float64')
gibt tatsächlich einen Datenrahmen mit den Spalten im richtigen Format