Öffnen einer 20-GB-Datei zur Analyse mit Pandas

33

Ich versuche gerade, eine Datei mit Pandas und Python für maschinelles Lernen zu öffnen. Es wäre ideal, wenn ich sie alle in einem DataFrame hätte. Jetzt ist die Datei 18 GB groß und mein RAM ist 32 GB, aber ich bekomme immer wieder Speicherfehler.

Aus Ihrer Erfahrung ist es möglich? Wenn nicht, kennen Sie einen besseren Weg, um dies zu umgehen? (Hive-Tabelle - vergrößern Sie meinen RAM auf 64 - erstellen Sie eine Datenbank und greifen Sie über Python darauf zu)

Hari Prasad
quelle
Ich hatte das gleiche Problem, ich schlage vor, Sie erhöhen den Swap, die Paging-Größe Ihrer Festplatte.
Medien
Die Faustregel beim Laden von Daten pandasist, dass Sie 5-10 mal mehr RAM benötigen. Ich empfehle, inplaceOperationen garbage.collectorauszuführen und Objekte explizit aufzurufen, um die Zuordnung aufzuheben.
Kiritee Gak
4
Machen Sie diese Frage besser, indem Sie Ihr Endziel angeben. Führen Sie eine explorative Datenanalyse durch, bereinigen Sie Daten, trainieren Sie ein Modell oder was? Welche Art von Daten?
Pete
1
Haben Sie darüber nachgedacht, dask zu verwenden ?
Rpanai

Antworten:

32

Wenn es sich um eine CSV-Datei handelt und Sie beim Trainieren Ihres Algorithmus nicht auf alle Daten gleichzeitig zugreifen müssen, können Sie diese in Blöcken lesen. Mit dieser pandas.read_csvMethode können Sie eine Datei wie folgt in Blöcken lesen:

import pandas as pd
for chunk in pd.read_csv(<filepath>, chunksize=<your_chunksize_here>)
    do_processing()
    train_algorithm()

Hier ist die Dokumentation der Methode

Olel Daniel
quelle
Gilt dies auch für ZIP-Dateien?
James Wierzba
Wenn es sich bei der komprimierten Datei auch um eine CSV-Datei handelt, muss der Komprimierungstyp als Argument an die Methode übergeben werden
Olel Daniel,
22

Es gibt zwei Möglichkeiten: Entweder Sie müssen alle Ihre Daten im Speicher haben , für die Verarbeitung (zB Ihrer Maschine Lernalgorithmus möchte auf einmal alles konsumieren), oder Sie können , ohne es tun (zB Ihr Algorithmus benötigt nur Proben von Zeilen oder Spalten auf einmal).

Im ersten Fall müssen Sie ein Speicherproblem lösen . Erhöhen Sie die Speichergröße, mieten Sie einen Cloud-Computer mit hohem Speicherplatz, verwenden Sie Inplace-Vorgänge, geben Sie Informationen über die Art der Daten an, die Sie einlesen, löschen Sie alle nicht verwendeten Variablen und sammeln Sie Müll usw.

Es ist sehr wahrscheinlich, dass 32 GB RAM nicht ausreichen, damit Pandas Ihre Daten verarbeiten kann. Beachten Sie, dass die Ganzzahl "1" nur ein Byte ist, wenn sie als Text gespeichert wird, aber 8 Byte, wenn sie als dargestellt wird int64(dies ist die Standardeinstellung, wenn Pandas sie aus dem Text einliest). Sie können dasselbe Beispiel mit einer Gleitkommazahl "1.0" erstellen, die float64standardmäßig von einer 3-Byte-Zeichenfolge zu einer 8-Byte-Zeichenfolge erweitert wird. Sie können Platz gewinnen, indem Sie Pandas genau mitteilen, welche Typen für jede Spalte verwendet werden sollen, und die kleinstmöglichen Darstellungen erzwingen. Wir haben jedoch nicht einmal angefangen, hier über den Datenstruktur-Overhead von Python zu sprechen, der hier oder da leicht einen oder zwei zusätzliche Zeiger hinzufügen kann und Zeiger sind jeweils 8 Byte auf einem 64-Bit-Computer.

Zusammenfassend: Nein, 32 GB RAM reichen Pandas wahrscheinlich nicht aus, um eine 20 GB große Datei zu verarbeiten.

Im zweiten Fall (der realistischer ist und wahrscheinlich auf Sie zutrifft) müssen Sie ein Datenverwaltungsproblem lösen . In der Tat kann es ein Zeichen für eine schlechte Datenverwaltung sein, alle Daten laden zu müssen, wenn Sie wirklich nur Teile für die Verarbeitung benötigen. Hier gibt es mehrere Möglichkeiten:

  1. Verwenden Sie eine SQL-Datenbank. Wenn Sie können, ist es fast immer die erste Wahl und eine anständige komfortable Lösung. 20 GB klingt wie die Größe, mit der die meisten SQL-Datenbanken gut umgehen würden, ohne dass sie selbst auf einem (High-End-) Laptop verteilt werden müssten. Sie werden in der Lage sein, Spalten zu indizieren, grundlegende Aggregationen über SQL durchzuführen und die erforderlichen Unterproben für eine komplexere Verarbeitung in Pandas mit einem einfachen Befehl abzurufen pd.read_sql. Durch das Verschieben der Daten in eine Datenbank können Sie auch über die tatsächlichen Datentypen und -größen Ihrer Spalten nachdenken .

  2. Wenn Ihre Daten überwiegend numerisch sind (z. B. Arrays oder Tensoren), können Sie sie in einem HDF5-Format speichern (siehe PyTables ), damit Sie bequem nur die erforderlichen Segmente großer Arrays von der Festplatte lesen können. Mit den grundlegenden Funktionen numpy.save und numpy.load wird der gleiche Effekt erzielt, indem die Arrays auch auf der Festplatte gespeichert werden. Für GIS und verwandte Rasterdaten gibt es dedizierte Datenbanken , die möglicherweise nicht so direkt wie SQL eine Verbindung zu Pandas herstellen, aber Sie sollten auch Slices und Abfragen relativ bequem ausführen können.

  3. Pandas unterstützt meines Wissens keine solchen "partiellen" Speicherzuordnungen von HDF5- oder Numpy-Arrays. Wenn Sie dennoch eine Art "reine Pandas" -Lösung wünschen, können Sie versuchen, dies durch "Sharding" zu umgehen: Speichern Sie entweder die Spalten Ihrer riesigen Tabelle separat (z. B. in separaten Dateien oder in separaten "Tabellen" eines einzelnen HDF5 Datei) und laden Sie nur die erforderlichen nach Bedarf oder speichern Sie die Zeilenblöcke separat. Sie müssten dann jedoch die Logik zum Laden der erforderlichen Blöcke implementieren und so die in den meisten SQL-Datenbanken bereits implementierten Fahrräder neu erfinden. Daher wäre Option 1 hier möglicherweise noch einfacher. Wenn Ihre Daten jedoch in einer CSV-Datei vorliegen, können Sie sie in Blöcken verarbeiten, indem Sie den chunksizeParameter auf angeben pd.read_csv.

KT.
quelle
5
Was im "ersten Fall" erwähnt werden sollte, ist, dass, wenn das OP viele Einträge mit dem gleichen Wert in den Daten hat (wie Nullen), die Daten als spärlich bezeichnet werden und eine spärliche Scipy-Matrix anstelle von a verwendet werden könnte pandas dataframe - spärliche Daten benötigen viel weniger Speicher.
Ricardo Cruz
9

Ich hatte gerade dieses Problem vor ein paar Tagen! Ich bin mir nicht sicher, ob dies in Ihrem speziellen Fall hilfreich ist, da Sie nicht so viele Details angeben. Meine Situation bestand jedoch darin, an einem 'großen' Datensatz offline zu arbeiten. Die Daten wurden als CSV-Dateien mit 20 GB Gzip von Energiezählern erhalten, Zeitreihendaten in Intervallen von mehreren Sekunden.

Datei IO:

data_root = r"/media/usr/USB STICK"
fname = r"meters001-050-timestamps.csv.gz"
this_file = os.path.join(data_root,fname)
assert os.path.exists(this_file), this_file
this_file

Erstellen Sie einen Chunk-Iterator direkt über der gzip-Datei (nicht entpacken!)

cols_to_keep = [0,1,2,3,7]
column_names = ['METERID','TSTAMP','ENERGY','POWER_ALL','ENERGY_OUT',]
parse_dates = ['TSTAMP']
dtype={'METERID': np.int32, 
       'ENERGY': np.int32,
       'POWER_ALL': np.int32,
       'ENERGY_OUT': np.int32,
      }
df_iterator = pd.read_csv(this_file, 
                        skiprows=0, 
                        compression='gzip',
                        chunksize=1000000, 
                        usecols=cols_to_keep,
                        delimiter=";",
                        header=None,
                        names = column_names,
                      dtype=dtype,
                     parse_dates=parse_dates,
                     index_col=1,
                     )

Iteriere über die Stücke

new_df = pd.DataFrame()
count = 0
for df in df_iterator:
    chunk_df_15min = df.resample('15T').first()
    #chunk_df_30min = df.resample('30T').first()
    #chunk_df_hourly = df.resample('H').first()
    this_df = chunk_df_15min
    this_df = this_df.pipe(lambda x: x[x.METERID == 1])
    #print("chunk",i)
    new_df = pd.concat([new_df,chunk_df_15min])
    print("chunk",count, len(chunk_df_15min), 'rows added')
    #print("chunk",i, len(temp_df),'rows added')
    #break
    count += 1

Innerhalb der Chunk-Schleife mache ich pünktlich einige Filter- und Neuabtastungen. Auf diese Weise habe ich die Größe von 20 GB auf einige hundert MB HDF5 für die weitere Offline-Datenexploration reduziert.

Marcus Jones
quelle
5

Nach meiner Erfahrung hilft das Initialisieren read_csv()mit Parametern low_memory=Falsebeim Einlesen großer Dateien. Ich glaube nicht, dass Sie den Dateityp erwähnt haben, in dem Sie lesen, daher bin ich mir nicht sicher, wie dies auf Ihre Situation zutrifft.

chainD
quelle
1

Wenn es sich bei Ihrer Datei um eine CSV handelt, können Sie dies einfach in Chunk by Chunk tun. Sie können einfach tun:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
Abdul
quelle