Подтвердить что ты не робот

Самый быстрый способ написать файл hdf5 с Python?

Учитывая большой (10s of GB) CSV файл смешанного текста/чисел, какой самый быстрый способ создать файл hdf5 с тем же контентом, при этом разумное использование памяти? Я хотел бы использовать модуль h5py, если это возможно.

В приведенном ниже примере игрушек я нашел невероятно медленный и невероятно быстрый способ записи данных в hdf5. Будет ли лучше всего писать hdf5 в кусках в 10 000 строк или около того? Или есть лучший способ написать массивный объем данных в такой файл?

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
4b9b3361

Ответ 1

Я бы избегал чередования данных и сохранял данные как серию наборов данных одного массива (в соответствии с тем, что предлагает Бенджамин). Я только что закончил загрузку продукта корпоративного приложения, над которым я работал в HDF5, и смог собрать около 4,5 миллиардов составных типов данных в виде 450 000 наборов данных, каждый из которых содержит 10 000 массивов данных. Записи и чтения теперь кажутся довольно мгновенными, но были мучительно медленными, когда я изначально пытался обрезать данные.

Просто мысль!

Update:

Это несколько фрагментов, снятых с моего фактического кода (я кодируюсь на C или Python, но вы должны понять, что я делаю) и модифицированы для ясности. Я просто пишу длинные целые числа без знака в массивах (10 000 значений на массив) и читаю их обратно, когда мне нужно фактическое значение

Это мой типичный код. В этом случае я просто пишу длинную целую последовательность без знака в последовательность массивов и загружая каждую последовательность массивов в hdf5 по мере их создания.

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

Это немного измененная версия моего кода читателя. Есть более элегантные способы сделать это (например, я мог бы использовать гиперплоскости для получения значения), но это было самое чистое решение в отношении моего довольно дисциплинированного процесса разработки 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];
}

Основным выводом является внутренний цикл в коде записи и операции с целым делением и по модулю для получения индекса массива набора данных и индекса желаемого значения в этом массиве. Дайте мне знать, если это достаточно ясно, чтобы вы могли собрать что-то похожее или лучше в h5py. В C это мертво просто и дает мне значительно лучшее время чтения/записи по сравнению с решением для пакетного набора данных. Плюс, так как я не могу использовать компрессию с составными наборами данных в любом случае, кажущийся потенциал роста - спорный момент, поэтому все мои соединения хранятся одинаково.

Ответ 2

Я не уверен, что это самый эффективный способ (и я никогда не использовал его, я просто собираю некоторые инструменты, которые я использовал самостоятельно), но вы можете прочитать файл csv в виде многократного повторения используя вспомогательные методы matplotlib для csv.

Вероятно, вы можете найти способ чтения файлов csv в кусках, чтобы избежать загрузки всего на диск. Затем используйте recarray (или фрагменты в нем), чтобы записать целые (или большие куски) в набор данных h5py. Я не совсем уверен, как h5py обрабатывает ремарки, но документация указывает, что это должно быть нормально.

В принципе, если это возможно, попробуйте написать большие куски данных одновременно, а не итерировать отдельные элементы.

Другая возможность для чтения файла csv - numpy.genfromtxt

Вы можете захватить нужные столбцы с помощью ключевого слова usecols, а затем читать только в указанном наборе строк, правильно задав ключевые слова skip_header и skip_footer.

Ответ 3

используя гибкость numpy.loadtxt, вы получите данные из файла в numpy array, что в свою очередь идеально подходит для инициализации набора данных 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)