2次元のnumpy
array
sをdtype=float
および(1e3, 1e6)
のオーダーで生成するスクリプトがあります。現在、np.save
とnp.load
を使用して、配列でIO操作を実行しています。ただし、これらの関数は配列ごとに数秒かかります。配列全体を保存およびロードする(つまり、その内容について仮定せずにそれらを削減する)?データが正確に保持されている限り、保存する前にarray
sを別のタイプに変換できます。
本当に大きなアレイの場合、いくつかのソリューションについて聞いたことがありますが、それらは主にI/Oで怠け者です。
ndarray
の透過的な置換(ndarrayを受け入れるクラスはmemmap
を受け入れます)Python HDF5のバインディング、 PyTables または h5py などのビッグデータ対応ファイル形式
Pythonのpickling system(レースではなく、速度ではなくPythonicityで言及)
NumPy.memmap のドキュメントから:
ディスク上のバイナリファイルに格納されている配列へのメモリマップを作成します。
メモリマップファイルは、ファイル全体をメモリに読み込まずに、ディスク上の大きなファイルの小さなセグメントにアクセスするために使用されます
Memmapオブジェクトは、ndarrayが受け入れられる場所であればどこでも使用できます。任意のmemmap
fp
を指定すると、isinstance(fp, numpy.ndarray)
はTrueを返します。
h5py doc から
大量の数値データを保存し、NumPyからそのデータを簡単に操作できます。たとえば、実際のNumPyアレイであるかのように、ディスクに保存されたマルチテラバイトデータセットにスライスできます。何千ものデータセットを単一のファイルに保存し、必要に応じて分類およびタグ付けすることができます。
この形式はさまざまな方法でデータの圧縮をサポートします(同じI/O読み取りに対してより多くのビットがロードされます)が、これはデータが個別にクエリするのが難しくなることを意味しますが、あなたの場合(純粋に配列をロード/ダンプする)は効率的かもしれません
以下はPyTablesとの比較です。
(int(1e3), int(1e6)
メモリ制限のため。したがって、より小さな配列を使用しました。
data = np.random.random((int(1e3), int(1e5)))
NumPy save
:
%timeit np.save('array.npy', data)
1 loops, best of 3: 4.26 s per loop
NumPy load
:
%timeit data2 = np.load('array.npy')
1 loops, best of 3: 3.43 s per loop
PyTablesの作成:
%%timeit
with tables.open_file('array.tbl', 'w') as h5_file:
h5_file.create_array('/', 'data', data)
1 loops, best of 3: 4.16 s per loop
PyTablesの読み取り:
%%timeit
with tables.open_file('array.tbl', 'r') as h5_file:
data2 = h5_file.root.data.read()
1 loops, best of 3: 3.51 s per loop
数字は非常に似ています。したがって、ここではPyTablesに本当の利益はありません。しかし、SSDの最大書き込み速度と読み取り速度にかなり近づいています。
書き込み:
Maximum write speed: 241.6 MB/s
PyTables write speed: 183.4 MB/s
読書:
Maximum read speed: 250.2
PyTables read speed: 217.4
データのランダム性のため、圧縮は実際には役立ちません。
%%timeit
FILTERS = tables.Filters(complib='blosc', complevel=5)
with tables.open_file('array.tbl', mode='w', filters=FILTERS) as h5_file:
h5_file.create_carray('/', 'data', obj=data)
1 loops, best of 3: 4.08 s per loop
圧縮データの読み取りが少し遅くなります。
%%timeit
with tables.open_file('array.tbl', 'r') as h5_file:
data2 = h5_file.root.data.read()
1 loops, best of 3: 4.01 s per loop
これは通常のデータとは異なります。
reg_data = np.ones((int(1e3), int(1e5)))
書き込みは非常に高速です。
%%timeit
FILTERS = tables.Filters(complib='blosc', complevel=5)
with tables.open_file('array.tbl', mode='w', filters=FILTERS) as h5_file:
h5_file.create_carray('/', 'reg_data', obj=reg_data)
1ループ、ベスト3:ループあたり849ミリ秒
同じことが読書にも当てはまります。
%%timeit
with tables.open_file('array.tbl', 'r') as h5_file:
reg_data2 = h5_file.root.reg_data.read()
1 loops, best of 3: 1.7 s per loop
結論:データがより規則的になればなるほど、PyTablesを使用して速くなるはずです。
私の経験によると、np.save()&np.load()は、これまでにハードディスクとメモリ間でデータを転送する際の最速のソリューションです。この結論に気付く前に、データベースとHDFSシステムにデータをロードすることに大きく依存していました。私のテストでは、データベースデータの読み込み(ハードディスクからメモリ)の帯域幅は約50 MBps(Byets/Second)ですが、np.load()帯域幅は私のハードディスクの最大帯域幅とほぼ同じです:2GBps(Byets/2番目)。両方のテスト環境は、最も単純なデータ構造を使用します。
そして、形状のある配列をロードするのに数秒を使うことは問題ではないと思います:(1e3、1e6)。例えば。配列の形状は(1000、1000000)、データ型はfloat128、純粋なデータサイズは(128/8)* 1000 * 1,000,000 = 16,000,000,000 = 16GBytesで、4秒かかる場合、データロード帯域幅は16GBytes/4秒= 4GBps。 SATA3の最大帯域幅は600MBps = 0.6GBpsであり、データ読み込み帯域幅は既に6倍です。データ読み込みパフォーマンスはほとんど競合する可能性があります DDRの最大帯域幅 、他に何が必要ですか?
私の最終的な結論は次のとおりです。
np.save()およびnpを使用できる場合、pythonのPickleを使用しないでください。データベースを使用せず、ビッグデータシステムを使用してデータをハードディスクに保存しないでください。 。負荷()。これら2つの機能は、これまでにハードディスクとメモリ間でデータを転送するための最速のソリューションです。
HDF5 もテストしましたが、np.load()およびnp.save()よりも遅いことがわかったので、np.save()&np.load()を使用している場合は、プラットフォームに十分なDDRメモリ。