web-dev-qa-db-fra.com

Convertir un grand csv en hdf5

J'ai un fichier csv de ligne 100M (en fait de nombreux fichiers csv séparés) totalisant 84 Go. J'ai besoin de le convertir en un fichier HDF5 avec un seul jeu de données flottant. J'ai utilisé h5py lors des tests sans aucun problème, mais maintenant je ne peux pas faire le jeu de données final sans manquer de mémoire.

Comment puis-je écrire sur HDF5 sans avoir à stocker l'ensemble de données en mémoire? J'attends du code réel ici, car il devrait être assez simple.

Je regardais juste pytables, mais il ne semble pas que la classe de tableau (qui correspond à un ensemble de données HDF5) puisse être écrite de manière itérative. De même, pandas a read_csv et to_hdf méthodes dans son io_tools, mais je ne peux pas charger l'ensemble de données en même temps, cela ne fonctionnera donc pas. Peut-être pouvez-vous m'aider à résoudre correctement le problème avec d'autres outils dans des pytables ou des pandas.

25
jmilloy

tilisation append=True dans l'appel à 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'))

les rendements

    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

Notez que vous devez utiliser format='table' lors du premier appel à df.to_hdf pour rendre le tableau annexable. Sinon, le format est 'fixed' par défaut, qui est plus rapide pour la lecture et l'écriture, mais crée une table qui ne peut pas être ajoutée à.

Ainsi, vous pouvez traiter chaque CSV un par un, utilisez append=True pour construire le fichier hdf5. Remplacez ensuite le DataFrame ou utilisez del df pour permettre à l'ancien DataFrame d'être récupéré.


Alternativement, au lieu d'appeler df.to_hdf, vous pourriez ajouter à un 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()

les rendements

    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
33
unutbu

Cela devrait être possible avec PyTables. Vous devrez cependant utiliser la classe EArray .

À titre d'exemple, voici un script que j'ai écrit pour importer des données d'entraînement fragmentées stockées sous la forme .npy fichiers en un seul .h5 fichier.

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

Jetez un œil à la documentation pour obtenir des instructions détaillées, mais très brièvement, le create_earray la fonction prend 1) une racine de données ou un nœud parent; 2) un nom de tableau; 3) un atome de type de données; 4) une forme avec un 0 dans la dimension que vous souhaitez développer; 5) un descripteur détaillé; 6) a filtre de compression ; et 7) un nombre attendu de lignes le long de la dimension extensible. Seuls les deux premiers sont requis, mais vous utiliserez probablement les sept dans la pratique. La fonction accepte également quelques autres arguments facultatifs; encore une fois, consultez la documentation pour plus de détails.

Une fois le tableau créé, vous pouvez utiliser sa méthode append de la manière attendue.

6
senderle