La manière la plus rapide d'écrire des fichiers HDF5 avec Python?

étant donné un grand fichier CSV (10s de GB) de texte/nombres mélangés, Quel est le moyen le plus rapide pour créer un fichier HDF5 avec le même contenu, tout en gardant l'utilisation de la mémoire raisonnable?

je voudrais utiliser le h5py module si possible.

dans l'exemple de jouet ci-dessous, j'ai trouvé un moyen incroyablement lent et incroyablement rapide d'écrire des données à HDF5. Serait-il préférable d'écrire à HDF5 en morceaux de 10 000 lignes ou plus? Ou est-il une meilleure façon d'écrire une quantité massive de les données de ce fichier?

import h5py

n = 10000000
f = h5py.File('foo.h5','w')
dset = f.create_dataset('int',(n,),'i')

# this is terribly slow
for i in xrange(n):
  dset[i] = i

# instantaneous
dset[...] = 42
19
demandé sur Lii 2011-03-29 05:37:08

3 réponses

j'éviterais de découper les données et je stockerais les données sous forme de séries d'ensembles de données à un seul tableau (suivant les lignes de ce que Benjamin suggère). Je viens de terminer le chargement de la sortie d'une application d'entreprise sur laquelle j'ai travaillé dans HDF5, et j'ai été capable d'emballer environ 4,5 milliards de types de données composés en 450.000 ensembles de données, chacun contenant un tableau de 10.000 données. Ecrit et lit maintenant semblent assez instantanés, mais étaient douloureusement lents quand j'ai d'abord essayé de fractionner les données.

un la pensée!

mise à Jour:

voici quelques extraits de mon code actuel (je code en C vs. Python, mais vous devriez vous faire une idée de ce que je fais) et modifiés pour plus de clarté. J'écris juste de longs entiers non signés dans des tableaux (10.000 valeurs par tableau) et je les relis quand j'ai besoin d'une valeur réelle

c'est mon code d'écriture typique. Dans ce cas, j'écris simplement une longue séquence entière non signée dans une séquence de tableaux et je charge chaque tableau. séquence en hdf5 au fur et à mesure de leur création.

//Our dummy data: a rolling count of long unsigned integers
long unsigned int k = 0UL;
//We'll use this to store our dummy data, 10,000 at a time
long unsigned int kValues[NUMPERDATASET];
//Create the SS adata files.
hid_t ssdb = H5Fcreate(SSHDF, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
//NUMPERDATASET = 10,000, so we get a 1 x 10,000 array
hsize_t dsDim[1] = {NUMPERDATASET};
//Create the data space.
hid_t dSpace = H5Screate_simple(1, dsDim, NULL);
//NUMDATASETS = MAXSSVALUE / NUMPERDATASET, where MAXSSVALUE = 4,500,000,000
for (unsigned long int i = 0UL; i < NUMDATASETS; i++){
    for (unsigned long int j = 0UL; j < NUMPERDATASET; j++){
        kValues[j] = k;
        k += 1UL;
    }
    //Create the data set.
    dssSet = H5Dcreate2(ssdb, g_strdup_printf("%lu", i), H5T_NATIVE_ULONG, dSpace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
    //Write data to the data set.
    H5Dwrite(dssSet, H5T_NATIVE_ULONG, H5S_ALL, H5S_ALL, H5P_DEFAULT, kValues);
    //Close the data set.
    H5Dclose(dssSet);
}
//Release the data space
H5Sclose(dSpace);
//Close the data files.
H5Fclose(ssdb);

ceci est une version légèrement modifiée de mon code de lecteur. Il y a des façons plus élégantes de le faire (c.-à-d., je pourrais utiliser des hyperplanes pour obtenir la valeur), mais c'était la solution la plus propre en ce qui concerne mon processus de développement Agile/BDD assez discipliné.

unsigned long int getValueByIndex(unsigned long int nnValue){
    //NUMPERDATASET = 10,000
    unsigned long int ssValue[NUMPERDATASET];
    //MAXSSVALUE = 4,500,000,000; i takes the smaller value of MAXSSVALUE or nnValue
    //to avoid index out of range error 
    unsigned long int i = MIN(MAXSSVALUE-1,nnValue);
    //Open the data file in read-write mode.
    hid_t db = H5Fopen(_indexFilePath, H5F_ACC_RDONLY, H5P_DEFAULT);
    //Create the data set. In this case, each dataset consists of a array of 10,000
    //unsigned long int and is named according to its integer division value of i divided
    //by the number per data set.
    hid_t dSet = H5Dopen(db, g_strdup_printf("%lu", i / NUMPERDATASET), H5P_DEFAULT);
    //Read the data set array.
    H5Dread(dSet, H5T_NATIVE_ULONG, H5S_ALL, H5S_ALL, H5P_DEFAULT, ssValue);
    //Close the data set.
    H5Dclose(dSet);
    //Close the data file.
    H5Fclose(db);
    //Return the indexed value by using the modulus of i divided by the number per dataset
    return ssValue[i % NUMPERDATASET];
}

le principal take-away est la boucle interne dans le code d'écriture et les opérations integer division et mod pour obtenir l'index du tableau de données et l'index de la valeur désirée dans ce tableau. Faites-moi savoir si c'est assez clair pour que vous puissiez assembler quelque chose de similaire ou mieux dans h5py. En C, c'est très simple et me donne des temps de lecture/écriture significativement meilleurs par rapport à une solution d'ensemble de données tronquées. De plus, puisque je ne peux pas utiliser la compression avec des ensembles de données composés de toute façon, l'envers apparent du chunking est un point discutable, donc tous mes composés sont stockés de la même façon.

6
répondu Marc 2014-02-01 19:38:52

utilisation de la flexibilité des numpy.loadtxt obtiendra les données du fichier dans un numpy array, qui à son tour est parfait pour initialiser l' hdf5 ensemble de données.

import h5py
import numpy as np

d = np.loadtxt('data.txt')
h = h5py.File('data.hdf5', 'w')
dset = h.create_dataset('data', data=d)
3
répondu toine 2014-06-27 09:27:15

Je ne suis pas sûr que ce soit le moyen le plus efficace (et je ne l'ai jamais utilisé; je suis juste en train de rassembler quelques outils que j'ai utilisés indépendamment), mais vous pourriez lire le fichier csv dans un numpy recarray en utilisant le matplotlib méthodes d'aide pour csv.

Vous pouvez probablement trouver un moyen de lire les fichiers csv en morceaux ainsi pour éviter de charger le tout sur le disque. Ensuite, utilisez le recarray (ou les tranches qui s'y trouvent) pour écrire l'ensemble (ou de grands morceaux de celui-ci) à l'ensemble de données h5py. Je suis pas exactement comment h5py poignées recarrays, mais la documentation indique qu'il devrait être ok.

fondamentalement si possible, essayez d'écrire de gros morceaux de données à la fois au lieu d'itérer sur des éléments individuels.

une autre possibilité pour lire le fichier csv est juste numpy.genfromtxt

Vous pouvez saisir les colonnes que vous voulez en utilisant le mot-clé usecols, et alors seulement lire dans un ensemble spécifié de lignes en définissant correctement les skip_header et skip_footer mot.

3
répondu JoshAdel 2016-12-07 09:09:05