2011-03-29 35 views
19

給定一個大的(10s GB)混合文本/數字CSV文件,創建具有相同內容的hdf5文件的最快方式是什麼,同時保持內存使用合理?如果可能,我想使用h5py模塊。用Python編寫hdf5文件的最快方法?

在下面的玩具例子中,我發現了一個非常緩慢且令人難以置信的快速寫入數據到hdf5的方法。以10000行左右的數據塊寫入hdf5會是最佳實踐嗎?還是有更好的方法將大量數據寫入這樣的文件?

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 
+0

讀入一個numpy的陣列,並通過發送整個數組 – Benjamin 2011-03-29 01:49:36

+1

@Benjamin避免循環:如果什麼數組是過大的內存來保存? – 2011-03-29 02:02:06

+0

我想你需要給我們一個想法,你想如何你的hdf5文件結構化 – 2011-03-29 02:22:04

回答

5

我會避免分塊數據,並將數據存儲爲一系列單個數組數據集(按照本傑明的建議)。我剛剛完成將我一直在研究的企業應用程序的輸出加載到HDF5中,並且能夠將約45億個複合數據類型打包爲450,000個數據集,每個數據集包含10,000個數據陣列。現在寫入和讀取看起來相當迅速,但當我最初試圖分塊數據時,速度非常緩慢。

只是一個念頭!

更新:

這是一對夫婦從我的實際代碼(我編碼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中,這是非常簡單的,並且使我的讀/寫次數明顯更好一個分塊的數據集解決方案。另外,因爲無論如何我都無法使用化合物數據集壓縮,所以組塊的明顯好處是一個爭論點,所以我所有的化合物都以相同的方式存儲。

+0

如果可能,您是否介意擴展一些關於數據結構的信息?如果你能提供一個具體的(代碼)例子,我會很樂意接受這個答案。 – 2011-04-11 00:25:10

+0

我用代碼更新了我的回覆。讓我知道如果這有幫助! – Marc 2011-04-12 04:49:14

3

我不知道這是否是最有效的方式(我從來沒有使用過它;我只是彙集了一些工具,我已經獨立使用),但你可以讀取csv文件進入一個使用matplotlib helper methods for csv的numpy recarray。

您或許可以找到一種方法來讀取塊中的csv文件,以避免將整個文件加載到磁盤。然後使用recarray(或其中的片)將整個(或其大塊)寫入h5py數據集。我不確定h5py如何處理recarrays,但文檔表明它應該沒問題。

基本上,如果可能的話,嘗試一次性寫入大塊數據,而不是遍歷各個元素。

另一種可能性讀取csv文件只是numpy.genfromtxt

你可以抓住你想要使用關鍵字usecols列,然後只通過適當地設定skip_headerskip_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) 
相關問題