2014-11-29 13 views
19

Ich habe eine 100M Linie CSV-Datei (eigentlich viele separate CSV-Dateien) mit insgesamt 84 GB. Ich muss es in eine HDF5-Datei mit einem einzigen Float-Datensatz konvertieren. Ich habe h5py im Test ohne irgendwelche Probleme verwendet, aber jetzt kann ich den endgültigen Datensatz nicht mehr ausführen, ohne den Arbeitsspeicher zu verlassen.Convert große csv zu hdf5

Wie kann ich in HDF5 schreiben, ohne den ganzen Datensatz im Speicher ablegen zu müssen? Ich erwarte hier tatsächlichen Code, weil es ziemlich einfach sein sollte.

Ich habe gerade in pytables untersucht, aber es sieht nicht wie die Array-Klasse (die einem HDF5-Datensatz entspricht) kann iterativ geschrieben werden. Ähnlich Pandas hat read_csv und to_hdf Methoden in seiner io_tools, aber ich kann nicht den gesamten Datensatz auf einmal laden, so dass es nicht funktioniert. Vielleicht können Sie mir helfen, das Problem mit anderen Tools in Pytables oder Pandas korrekt zu lösen.

Antwort

25

Use append=True im Aufruf von to_hdf:

import numpy as np 
import pandas as pd 

filename = '/tmp/test.h5' 

df = pd.DataFrame(np.arange(10).reshape((5,2)), columns=['A', 'B']) 
print(df) 
# A B 
# 0 0 1 
# 1 2 3 
# 2 4 5 
# 3 6 7 
# 4 8 9 

# Save to HDF5 
df.to_hdf(filename, 'data', mode='w', format='table') 
del df # allow df to be garbage collected 

# Append more data 
df2 = pd.DataFrame(np.arange(10).reshape((5,2))*10, columns=['A', 'B']) 
df2.to_hdf(filename, 'data', append=True) 

print(pd.read_hdf(filename, 'data')) 

ergibt

A B 
0 0 1 
1 2 3 
2 4 5 
3 6 7 
4 8 9 
0 0 10 
1 20 30 
2 40 50 
3 60 70 
4 80 90 

Beachten Sie, dass Sie benötigen format='table' im ersten Aufruf zu verwenden, um df.to_hdf, um die Tabelle appendable zu machen. Ansonsten ist das Format standardmäßig 'fixed', das zum Lesen und Schreiben schneller ist, aber eine Tabelle erstellt, an die nicht angehängt werden kann.

So können Sie jede CSV einzeln verarbeiten, verwenden Sie append=True, um die hdf5-Datei zu erstellen. Überschreiben Sie dann den DataFrame oder verwenden Sie , damit der alte DataFrame als Garbage Collected behandelt werden kann.


Alternativ kann statt df.to_hdf aufzurufen, könnten Sie append to a HDFStore:

import numpy as np 
import pandas as pd 

filename = '/tmp/test.h5' 
store = pd.HDFStore(filename) 

for i in range(2): 
    df = pd.DataFrame(np.arange(10).reshape((5,2)) * 10**i, columns=['A', 'B']) 
    store.append('data', df) 

store.close() 

store = pd.HDFStore(filename) 
data = store['data'] 
print(data) 
store.close() 

Ausbeuten

A B 
0 0 1 
1 2 3 
2 4 5 
3 6 7 
4 8 9 
0 0 10 
1 20 30 
2 40 50 
3 60 70 
4 80 90 
6

Dies sollte mit PyTables möglich sein. Sie müssen jedoch die Klasse EArray verwenden.

Als Beispiel ist das folgende ein Skript, das ich geschrieben habe, um Chunked Trainingsdaten, die als .npy Dateien gespeichert sind, in eine einzige .h5 Datei zu importieren.

import numpy 
import tables 
import os 

training_data = tables.open_file('nn_training.h5', mode='w') 
a = tables.Float64Atom() 
bl_filter = tables.Filters(5, 'blosc') # fast compressor at a moderate setting 

training_input = training_data.create_earray(training_data.root, 'X', a, 
              (0, 1323), 'Training Input', 
              bl_filter, 4000000) 
training_output = training_data.create_earray(training_data.root, 'Y', a, 
              (0, 27), 'Training Output', 
              bl_filter, 4000000) 

for filename in os.listdir('input'): 
    print "loading {}...".format(filename) 
    a = numpy.load(os.path.join('input', filename)) 
    print "writing to h5" 
    training_input.append(a) 

for filename in os.listdir('output'): 
    print "loading {}...".format(filename) 
    training_output.append(numpy.load(os.path.join('output', filename))) 

Schauen Sie sich auf die Dokumentation für die detaillierte Anweisungen, aber sehr kurz, die create_earray Funktion nimmt 1) eine Daten Wurzel oder übergeordneten Knoten; 2) ein Array-Name; 3) ein Datentyp atom; 4) eine Form mit einem 0 in der Dimension, die Sie erweitern möchten; 5) ein ausführlicher Deskriptor; 6) a compression filter; und 7) eine erwartete Anzahl von Reihen entlang der expandierbaren Dimension. Nur die ersten beiden werden benötigt, aber Sie werden wahrscheinlich alle sieben in der Praxis verwenden. Die Funktion akzeptiert auch einige andere optionale Argumente. Weitere Informationen finden Sie in der Dokumentation. Nachdem das Array erstellt wurde, können Sie die Methode append in der erwarteten Weise verwenden.