2014-11-29 17 views
19

Ho un file csv di 100 milioni di righe (in realtà molti file CSV separati) per un totale di 84 GB. Ho bisogno di convertirlo in un file HDF5 con un set di dati float singolo. Ho usato h5py in testing senza problemi, ma ora non posso fare il set di dati finale senza esaurire la memoria.Convert csv grande a hdf5

Come posso scrivere su HDF5 senza dover memorizzare l'intero set di dati in memoria? Mi aspetto un codice reale qui, perché dovrebbe essere abbastanza semplice.

Stavo solo esaminando pytables, ma non sembra che la classe dell'array (che corrisponde a un set di dati HDF5) possa essere scritta in modo iterativo. Allo stesso modo, panda ha metodi read_csv e to_hdf nel suo io_tools, ma non riesco a caricare l'intero set di dati in una volta, in modo che non funzioni. Forse puoi aiutarmi a risolvere il problema correttamente con altri strumenti in pytables o panda.

risposta

25

Use append=True nella chiamata a 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')) 

cede

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 

Si noti che è necessario utilizzare format='table' nella prima chiamata a df.to_hdf per rendere l'appendable tavolo. Altrimenti, il formato è 'fixed' per impostazione predefinita, che è più veloce per la lettura e la scrittura, ma crea una tabella che non può essere aggiunta.

Pertanto, è possibile elaborare ciascun CSV uno alla volta, utilizzare append=True per creare il file hdf5. Quindi sovrascrivere DataFrame o utilizzare del df per consentire al vecchio DataFrame di essere sottoposto a Garbage Collection.


In alternativa, invece di chiamare df.to_hdf, si potrebbe 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() 

rendimenti

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

Questo dovrebbe essere possibile con PyTables. Dovrai comunque utilizzare la classe EArray.

Ad esempio, il seguente è uno script che ho scritto per importare i dati di allenamento chunked memorizzati come file .npy in un singolo file .h5.

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))) 

Date un'occhiata alla documentazione per le istruzioni dettagliate, ma molto brevemente, la funzione create_earray prende 1) una radice di dati o nodo padre; 2) un nome di array; 3) un atomo di tipo di dati; 4) una forma con un 0 nella dimensione che si desidera espandere; 5) un descrittore dettagliato; 6) a compression filter; e 7) un numero previsto di righe lungo la dimensione espandibile. Sono richiesti solo i primi due, ma probabilmente ne userai tutti e sette in pratica. La funzione accetta anche alcuni altri argomenti facoltativi; di nuovo, vedi i documenti per i dettagli.

Una volta creata la matrice, è possibile utilizzare il suo metodo append nel modo previsto.