Pandas read_csv low_memory und dtype Optionen

320

Beim Anruf

df = pd.read_csv('somefile.csv')

Ich bekomme:

/Users/josh/anaconda/envs/py27/lib/python2.7/site-packages/pandas/io/parsers.py:1130: DtypeWarning: Spalten (4,5,7,16) haben gemischte Typen. Geben Sie beim Import die Option dtype an oder setzen Sie low_memory = False.

Warum hängt die dtypeOption zusammen low_memoryund warum Falsehilft sie bei diesem Problem?

Josh
quelle
2
Ich habe eine Frage zu dieser Warnung. Ist der Index der genannten Spalten 0-basiert? Zum Beispiel ist Spalte 4, die einen gemischten Typ hat, df [:, 4] oder df [:, 3]
maziar
@maziar Beim Lesen einer CSV wird standardmäßig ein neuer 0-basierter Index erstellt und verwendet.
Firelynx

Antworten:

431

Die veraltete Option low_memory

Die low_memoryOption ist nicht richtig veraltet, sollte es aber sein, da sie eigentlich nichts anderes macht [ Quelle ]

Der Grund, warum Sie diese low_memoryWarnung erhalten, ist, dass das Erraten von dtypes für jede Spalte sehr speicherintensiv ist. Pandas versucht zu bestimmen, welcher D-Typ festgelegt werden soll, indem die Daten in jeder Spalte analysiert werden.

Dtype Guessing (sehr schlecht)

Pandas können erst bestimmen, welchen Typ eine Spalte haben soll, wenn die gesamte Datei gelesen wurde. Dies bedeutet, dass vor dem Lesen der gesamten Datei nichts wirklich analysiert werden kann, es sei denn, Sie riskieren, den d-Typ dieser Spalte beim Lesen des letzten Werts ändern zu müssen.

Betrachten Sie das Beispiel einer Datei mit einer Spalte namens user_id. Es enthält 10 Millionen Zeilen, in denen die Benutzer-ID immer aus Zahlen besteht. Da Pandas nicht wissen können, dass es sich nur um Zahlen handelt, werden sie wahrscheinlich als Originalzeichenfolgen beibehalten, bis die gesamte Datei gelesen wurde.

Angabe von dtypes (sollte immer erfolgen)

Hinzufügen

dtype={'user_id': int}

Bei dem pd.read_csv()Aufruf werden Pandas wissen, wenn sie mit dem Lesen der Datei beginnen, dass dies nur Ganzzahlen sind.

Erwähnenswert ist auch, dass das Laden abstürzen würde , wenn die letzte Zeile in der Datei "foobar"in die user_idSpalte geschrieben worden wäre, wenn der obige dtype angegeben worden wäre.

Beispiel für fehlerhafte Daten, die beim Definieren von dtypes beschädigt werden

import pandas as pd
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO


csvdata = """user_id,username
1,Alice
3,Bob
foobar,Caesar"""
sio = StringIO(csvdata)
pd.read_csv(sio, dtype={"user_id": int, "username": "string"})

ValueError: invalid literal for long() with base 10: 'foobar'

dtypes sind normalerweise eine numpy Sache, lesen Sie mehr darüber hier: http://docs.scipy.org/doc/numpy/reference/generated/numpy.dtype.html

Welche dtypes gibt es?

Wir haben Zugriff auf numpy dtypes: float, int, bool, timedelta64 [ns] und datetime64 [ns]. Beachten Sie, dass die numpy Datum / Uhrzeit dtypes ist nicht bekannt , Zeitzone.

Pandas erweitert diesen Satz von dtypes um seine eigenen:

'datetime64 [ns,]' Dies ist ein zeitzonenabhängiger Zeitstempel.

'Kategorie', die im Wesentlichen eine Aufzählung ist (Zeichenfolgen, die durch zu speichernde Ganzzahlschlüssel dargestellt werden

'period []' Nicht zu verwechseln mit einem Zeitdelta, diese Objekte sind tatsächlich in bestimmten Zeiträumen verankert

'Sparse', 'Sparse [int]', 'Sparse [float]' steht für spärliche Daten oder 'Daten mit vielen Löchern'. Anstatt das NaN oder None im Datenrahmen zu speichern, werden die Objekte weggelassen, wodurch Platz gespart wird .

'Intervall' ist ein eigenes Thema, das hauptsächlich zur Indizierung verwendet wird. Sehen Sie hier mehr

'Int8', 'Int16', 'Int32', 'Int64', 'UInt8', 'UInt16', 'UInt32', 'UInt64' sind alles Pandas-spezifische Ganzzahlen, die im Gegensatz zur Numpy-Variante nullbar sind.

'string' ist ein spezifischer dtype für die Arbeit mit String-Daten und ermöglicht den Zugriff auf das .strAttribut in der Serie.

'boolean' ist wie das numpy 'bool', unterstützt aber auch fehlende Daten.

Lesen Sie hier die vollständige Referenz:

Pandas dtype Referenz

Fallstricke, Vorbehalte, Notizen

Durch die Einstellung dtype=objectwird die obige Warnung stummgeschaltet, aber nicht speichereffizienter, sondern nur prozesseffizienter, wenn überhaupt.

Die Einstellung dtype=unicodebewirkt nichts, da a für numpy unicodeals dargestellt wird object.

Verwendung von Konvertern

@sparrow weist korrekt auf die Verwendung von Konvertern hin, um zu vermeiden, dass Pandas explodieren, wenn sie 'foobar'in einer Spalte auftreten, die als angegeben ist int. Ich möchte hinzufügen, dass Konverter sehr schwer und ineffizient in Pandas zu verwenden sind und als letztes Mittel verwendet werden sollten. Dies liegt daran, dass der Prozess read_csv ein einzelner Prozess ist.

CSV-Dateien können zeilenweise verarbeitet werden und somit von mehreren Konvertern parallel effizienter verarbeitet werden, indem die Datei einfach in Segmente geschnitten und mehrere Prozesse ausgeführt werden, was Pandas nicht unterstützt. Aber das ist eine andere Geschichte.

Firelynx
quelle
6
Gibt es angesichts der Tatsache, dass das Einstellen von a dtype=objectnicht speichereffizienter ist, einen Grund, sich damit zu beschäftigen, außer den Fehler zu beseitigen?
zthomas.nc
6
@ zthomas.nc Ja, Pandas muss sich nicht die Mühe machen, zu testen, was in der Spalte steht. Theoretisch etwas Speicher während des Ladens speichern (aber keiner nach Abschluss des Ladevorgangs) und theoretisch einige CPU-Zyklen speichern (was Sie nicht bemerken werden, da Festplatten-E / A der Engpass sein wird.
Firelynx
5
"Erwähnenswert ist auch, dass das Laden abstürzen würde, wenn in der letzten Zeile der Datei" foobar "in die Spalte" user_id "geschrieben würde, wenn der obige dtype angegeben würde." Gibt es eine "Zwangs" -Option, die verwendet werden könnte, um diese Reihe wegzuwerfen, anstatt abzustürzen?
Spatz
5
@sparrow mag es geben, aber als ich es das letzte Mal benutzt habe, hatte es Fehler. Es kann in der neuesten Version von Pandas behoben werden. error_bad_lines=False, warn_bad_lines=Truesollte den Trick machen. Die Dokumentation besagt, dass es nur mit dem C-Parser gültig ist. Es heißt auch, dass der Standardparser None ist, was es schwierig macht zu wissen, welcher der Standard ist.
Firelynx
5
@nealmcb Sie können den Datenrahmen nrows=100als Argument lesen und dann df.dtypesdie dtypes anzeigen, die Sie erhalten. Wenn Sie jedoch den gesamten Datenrahmen mit diesen dtypes lesen, müssen Sie dies tun, try/exceptdamit Sie fehlerhafte dtype-Vermutungen abfangen. Daten sind schmutzig, wissen Sie.
Firelynx
50

Versuchen:

dashboard_df = pd.read_csv(p_file, sep=',', error_bad_lines=False, index_col=False, dtype='unicode')

Laut der Pandas-Dokumentation:

dtype: Typname oder Diktat der Spalte -> Typ

Low_memory ist standardmäßig True und noch nicht dokumentiert. Ich denke nicht, dass es relevant ist. Die Fehlermeldung ist generisch, daher sollten Sie sich sowieso nicht mit low_memory herumschlagen müssen. Hoffe das hilft und lass es mich wissen, wenn du weitere Probleme hast

hd1
quelle
1
Hinzufügen dtype=unicodeproduziert : NameError: name 'unicode' is not defined. Aber das Einfügen unicodevon Anführungszeichen (wie in 'Unicode') scheint zu funktionieren!
Sedeh
5
@sedeh Sie können dtypes entweder als Python-Typ oder als angeben numpy.dtype('unicode'). Wenn Sie der Option dtype eine Zeichenfolge geben, wird numpy.dtype()standardmäßig versucht, sie über die Factory zu übertragen. Die Angabe bewirkt 'unicode'eigentlich nichts, Unicodes werden nur auf gesendet objects. Sie erhaltendtype='object'
Firelynx
43
df = pd.read_csv('somefile.csv', low_memory=False)

Dies sollte das Problem lösen. Ich habe genau den gleichen Fehler beim Lesen von 1,8 Millionen Zeilen aus einer CSV erhalten.

Neal
quelle
51
Dies bringt den Fehler zum Schweigen, ändert aber nichts anderes.
Firelynx
2
Ich habe das gleiche Problem beim Ausführen von 1,5 GB Datendatei
Sitz Blogz
18

Wie bereits von firelynx erwähnt, stürzt das Laden ab, wenn dtype explizit angegeben wird und gemischte Daten vorhanden sind, die nicht mit diesem dtype kompatibel sind. Ich habe einen solchen Konverter als Problemumgehung verwendet, um die Werte mit inkompatiblem Datentyp so zu ändern, dass die Daten weiterhin geladen werden können.

def conv(val):
    if not val:
        return 0    
    try:
        return np.float64(val)
    except:        
        return np.float64(0)

df = pd.read_csv(csv_file,converters={'COL_A':conv,'COL_B':conv})
Spatz
quelle
2

Ich hatte ein ähnliches Problem mit einer ~ 400MB-Datei. Das Einstellen low_memory=Falsehat den Trick für mich getan. Machen Sie zuerst die einfachen Dinge, ich würde überprüfen, ob Ihr Datenrahmen nicht größer als Ihr Systemspeicher ist, neu starten, den RAM löschen, bevor Sie fortfahren. Wenn Sie immer noch auf Fehler stoßen, sollten Sie sicherstellen, dass Ihre .csvDatei in Ordnung ist, einen kurzen Blick in Excel werfen und sicherstellen, dass keine offensichtliche Beschädigung vorliegt. Gebrochene Originaldaten können Chaos anrichten ...

Dr. Nigel
quelle
1

Ich hatte ein ähnliches Problem bei der Verarbeitung einer riesigen CSV-Datei (6 Millionen Zeilen). Ich hatte drei Probleme: 1. Die Datei enthielt seltsame Zeichen (mithilfe der Codierung behoben) 2. Der Datentyp wurde nicht angegeben (mithilfe der Eigenschaft dtype behoben) definiert basierend auf dem Dateinamen (behoben mit try .. außer ..)

df = pd.read_csv(csv_file,sep=';', encoding = 'ISO-8859-1',
                 names=['permission','owner_name','group_name','size','ctime','mtime','atime','filename','full_filename'],
                 dtype={'permission':str,'owner_name':str,'group_name':str,'size':str,'ctime':object,'mtime':object,'atime':object,'filename':str,'full_filename':str,'first_date':object,'last_date':object})

try:
    df['file_format'] = [Path(f).suffix[1:] for f in df.filename.tolist()]
except:
    df['file_format'] = ''
Wim Folkerts
quelle
-1

Es hat bei mir low_memory = Falsebeim Importieren eines DataFrame funktioniert. Das ist die ganze Veränderung, die für mich funktioniert hat:

df = pd.read_csv('export4_16.csv',low_memory=False)
Rajat Saxena
quelle