テキストと数字が混在する大きな(数十GB)CSVファイルがある場合、メモリ使用量を適切に保ちながら、同じコンテンツでHDF5ファイルを作成する最速の方法は何ですか?
可能であればh5py
モジュールを使用したいと思います。
以下のおもちゃの例では、HDF5にデータを書き込むための信じられないほど遅くて信じられないほど速い方法を見つけました。 10,000行程度のチャンクで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
データのチャンク化を避け、データを一連の単一配列データセットとして保存します(Benjaminが提案している内容に沿って)。作業中のエンタープライズアプリの出力をHDF5にロードし終えたところ、約45億の複合データ型を45万のデータセットとしてパックでき、それぞれに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);
これは私のリーダーコードのわずかに変更されたバージョンです。これを行うにはもっとエレガントな方法があります(つまり、超平面を使用して値を取得できます)が、これは私のかなり訓練されたアジャイル/ 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では、これは非常に単純であり、チャンク化されたデータセットソリューションと比較して、読み取り/書き込み時間が大幅に短縮されます。さらに、とにかく化合物データセットで圧縮を使用できないため、チャンク化の明らかな利点は重要なポイントであり、すべての化合物は同じ方法で保存されます。
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)
これが最も効率的な方法かどうかはわかりませんが(使用したことはありません。個別に使用したいくつかのツールをまとめているだけです)、-を使用してcsvファイルをnumpy再配列に読み込むことができます。 csvのmatplotlibヘルパーメソッド 。
すべてをディスクにロードしないように、csvファイルをチャンクで読み取る方法を見つけることもできます。次に、recarray(またはその中のスライス)を使用して、全体(またはその大きなチャンク)をh5pyデータセットに書き込みます。 h5pyがどのように再配列を処理するかは正確にはわかりませんが、ドキュメントには問題がないことが示されています。
基本的に、可能であれば、個々の要素を反復処理するのではなく、一度に大きなデータのチャンクを書き込むようにしてください。
Csvファイルを読み取るもう1つの可能性は、 numpy.genfromtxt
です。
キーワードusecols
を使用して必要な列を取得し、skip_header
およびskip_footer
キーワードを適切に設定することにより、指定された行のセットのみを読み取ることができます。