Laut der Pandas-Dokumentation ist die Angabe von low_memory=False
so lange wie engine='c'
(was der Standardwert ist) eine vernünftige Lösung für dieses Problem.
Wenn low_memory=False
ist, werden zunächst ganze Spalten eingelesen und dann die entsprechenden Typen bestimmt. Zum Beispiel wird die Spalte als Objekte (Strings) beibehalten, um Informationen zu erhalten.
Wenn low_memory=True
(der Standardwert) ist, liest Pandas die Daten in Teilen von Zeilen ein und fügt sie dann zusammen. Dann könnten einige der Spalten wie gemischte Abschnitte von Ganzzahlen und Strings aussehen, je nachdem, ob Pandas während des Teils auf etwas gestoßen ist, das nicht in eine Ganzzahl umgewandelt werden konnte (sagen wir). Dies könnte später Probleme verursachen. Die Warnung gibt an, dass dies mindestens einmal beim Einlesen aufgetreten ist, daher sollten Sie vorsichtig sein. Die Einstellung von low_memory=False
verbraucht mehr Speicher, umgeht jedoch das Problem.
Persönlich denke ich, dass low_memory=True
ein schlechter Standardwert ist, aber ich arbeite in einem Bereich, der viele kleine Datensätze anstelle von großen verwendet, daher ist die Bequemlichkeit wichtiger als die Effizienz.
Der folgende Code veranschaulicht ein Beispiel, bei dem low_memory=True
gesetzt ist und eine Spalte mit gemischten Typen hereinkommt. Es baut auf der Antwort von @firelynx auf
import pandas as pd
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
# Erstelle eine große CSV-Datendatei, basierend auf dem früheren Ansatz von @firelynx
csvdata = """1,Alice
2,Bob
3,Caesar
"""
# Wir müssen die Spalte "Integer-Spalte" user_id viele Male reproduzieren, um
# pd.read_csv dazu zu bringen, tatsächlich in Teilen zu lesen. Andernfalls liest es einfach
# alles in einem Teil ein, weil es schneller ist, und wir bekommen kein "gemischter Typ"-Problem.
# Die 100000 unten wurde durch Experimente gewählt.
csvdatafull = ""
for i in range(100000):
csvdatafull = csvdatafull + csvdata
csvdatafull = csvdatafull + "foobar,Cthlulu\n"
csvdatafull = "user_id,username\n" + csvdatafull
sio = StringIO(csvdatafull)
# die folgende Zeile gibt mir die Warnung:
# C:\Users\rdisa\anaconda3\lib\site-packages\IPython\core\interactiveshell.py:3072: DtypeWarning: Columns (0) have mixed types.Specify dtype option on import or set low_memory=False.
# interactivity=interactivity, compiler=compiler, result=result)
# aber sie gibt mir nicht immer die Warnung, also denke ich, dass die internen Abläufe von read_csv von Hintergrundfaktoren abhängen
x = pd.read_csv(sio, low_memory=True) #, dtype={"user_id": int, "username": "string"})
x.dtypes
# das gibt:
# Out[69]:
# user_id object
# username object
# dtype: object
type(x['user_id'].iloc[0]) # int
type(x['user_id'].iloc[1]) # int
type(x['user_id'].iloc[2]) # int
type(x['user_id'].iloc[10000]) # int
type(x['user_id'].iloc[299999]) # str !!!! (obwohl es eine Zahl ist! Daher muss dieser Teil als String gelesen worden sein)
type(x['user_id'].iloc[300000]) # str !!!!!
Außerdem, um ein Beispiel zu geben, in dem dies ein Problem darstellt (und wo ich zum ersten Mal auf dieses ernsthafte Problem gestoßen bin), stellen Sie sich vor, Sie haben pd.read_csv()
auf eine Datei angewendet und dann Duplikate basierend auf einem Identifikator entfernen möchten. Sagen wir, der Identifikator ist manchmal numerisch, manchmal ein String. Eine Zeile könnte "81287" sein, eine andere "97324-32". Trotzdem handelt es sich um eindeutige Kennungen.
Mit low_memory=True
könnte Pandas den Identifikator so einlesen:
81287
81287
81287
81287
81287
"81287"
"81287"
"81287"
"81287"
"97324-32"
"97324-32"
"97324-32"
"97324-32"
"97324-32"
Nur weil es Dinge aufteilt und deshalb ist der Identifikator 81287 manchmal eine Zahl, manchmal ein String. Wenn ich versuche, Duplikate basierend darauf zu entfernen, nun,
81287 == "81287"
Out[98]: False