Najszybszy sposób zapisu plików HDF5 w Pythonie?

Biorąc pod uwagę duży (10 GB) plik CSV z mieszanym tekstem / liczbami, jaki jest najszybszy sposób na utworzenie pliku HDF5 o tej samej zawartości, przy zachowaniu rozsądnego wykorzystania pamięci?

Chciałbym użyć modułu h5py, jeśli to możliwe.

W poniższym przykładzie zabawek znalazłem niewiarygodnie powolny i niewiarygodnie szybki sposób zapisu danych do HDF5. Czy najlepszą praktyką byłoby pisanie do HDF5 w kawałkach po 10 000 wierszy? A może jest lepszy sposób na napisanie ogromnej ilości danych do takiego akta?

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
Author: Lii, 2011-03-29

3 answers

Unikałbym chunkingu danych i przechowywałby je jako serie pojedynczych zestawów danych (zgodnie z tym, co sugeruje Benjamin). Właśnie skończyłem wczytywać dane wyjściowe aplikacji korporacyjnej, nad którą pracowałem, do HDF5 i byłem w stanie spakować około 4,5 miliarda złożonych typów danych w 450 000 zestawów danych, z których każdy zawiera tablicę danych 10 000. Pisze i czyta teraz wydają się dość natychmiastowe, ale były boleśnie powolne, gdy początkowo próbowałem fragmentować dane.

Just a myślałem!

Aktualizacja:

To kilka fragmentów usuniętych z mojego rzeczywistego kodu (koduję w C VS. Python, ale powinieneś zrozumieć, co robię) i zmodyfikowanych dla jasności. Po prostu piszę długie niepodpisane liczby całkowite w tablicach (10 000 wartości na tablicę) i czytam je z powrotem, gdy potrzebuję rzeczywistej wartości

To mój typowy kod pisarski. W tym przypadku po prostu piszę długą, niepodpisaną sekwencję całkowitą do sekwencji tablic i ładuję każdą sekwencję tablicy do hdf5 jak są tworzone.
//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);

Jest to nieco zmodyfikowana wersja mojego kodu czytnika. Istnieją bardziej eleganckie sposoby na to (tj. mógłbym użyć hyperplanes, aby uzyskać wartość), ale było to najczystsze rozwiązanie w odniesieniu do mojego dość zdyscyplinowanego procesu rozwoju Agile / BDD.

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];
}

Głównym wyjściem jest wewnętrzna pętla w kodzie zapisu oraz operacje dzielenia liczb całkowitych i mod, aby uzyskać indeks tablicy dataset i indeks żądanej wartości w tej tablicy. Daj mi znać, jeśli jest to wystarczająco jasne, abyś mógł ułożyć coś podobnego lub lepszego w h5py. W C, to jest martwe proste i daje mi znacznie lepsze czasy odczytu/zapisu vs. chunked rozwiązanie dataset. Plus ponieważ i tak nie mogę używać kompresji ze złożonymi zestawami danych, pozorna zaleta chunkingu jest kwestią sporną, więc wszystkie moje związki są przechowywane w ten sam sposób.

 6
Author: Marc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-01 19:38:52

Użycie elastyczności numpy.loadtxt spowoduje pobranie danych z pliku do numpy array, co z kolei jest idealne do zainicjowania zbioru danych hdf5.

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
Author: toine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-27 09:27:15

Nie jestem pewien, czy jest to najbardziej efektywny sposób (i nigdy go nie używałem; po prostu zbieram kilka narzędzi, których używałem niezależnie), ale możesz odczytać plik csv do numpy recarray używając matplotlib helper metod dla csv.

Prawdopodobnie możesz znaleźć sposób na odczytanie plików csv w kawałkach, aby uniknąć załadowania całości na dysk. Następnie użyj recarray (lub plastrów w nim zawartych), aby zapisać całość (lub duże jego fragmenty) do zbioru danych h5py. Nie jestem pewna. jak h5py radzi sobie z recarrays, ale dokumentacja wskazuje, że powinno być ok.

Zasadniczo, jeśli to możliwe, spróbuj zapisać duże fragmenty danych naraz zamiast iteracji nad poszczególnymi elementami.

Kolejną możliwością odczytu pliku csv jest numpy.genfromtxt

Możesz pobrać kolumny, które chcesz użyć słowa kluczowego usecols, a następnie odczytać tylko w określonym zestawie wierszy, odpowiednio ustawiając słowa kluczowe skip_header i skip_footer.

 3
Author: JoshAdel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-07 09:09:05