2

私は、Python で大規模なデータセットにアクセスする最速の方法を見つけようとしていじっています。

私の現実のケースでは、主にドット積を取り、レベルを合計しているため、pandas MultiIndex DataFrame にロードしている約 10,000 x 10,000 の csv ファイルがあります。

この csv を pandas にロードするのに約 1 分かかるため、この速度を改善する方法を探していました。

調査の結果、このスレッドに出くわしました: Python でデータを保存/ロードすると、matlab よりも多くのスペース/時間がかかるのはなぜですか?

このスレッドから得たのは、.mat ファイルは hdf5 として保存されるため、読み込みが速くなるということです。そのため、ピクルのパフォーマンスと、h5py、pandas、および scypio (.mat ファイルからデータをロードする) を使用した hdf のパフォーマンスを評価したいと考えました。

私の実際のケースの結果は次のとおりです。

pickle 65.48222637176514
h5py 65.20841789245605
pandas 65.45801973342896
mat 20.857333660125732

ご覧のとおり、.mat ファイルの読み込みは、Python で生成された pickle と hdfs の 3 倍以上高速です。そのため、Python で生成された hdfs の読み込みにはこの利点がないため、.mat ファイルの読み込み時間の短縮は hdf によるものではないようです。

これに基づいて、ここに質問を投稿して、大規模なデータセットを Python にロードする最も簡単な方法を尋ねたいと思いました。このために、いくつかのランダム データを使用しておもちゃの例を作成しました。

import numpy as np
import pickle
import h5py
import pandas as pd

#create random numpy ndarray
array_foo = np.random.rand(10000,10000)

#save array to pickle
pickle.dump(array_foo, open('array_foo.pkl', 'wb'))

#save array to hdf through h5py
h5py_hdf_store = h5py.File('array_foo.h5')
h5py_hdf_store['array_foo'] = array_foo
h5py_hdf_store.close()

#save pandas to hdf
df = pd.DataFrame(array_foo)
df.to_hdf('df_foo.h5', 'df_foo')

#save to csv for conversion to mat
df.to_csv('df_foo.csv')

MATLAB で csv を mat に変換した後、読み込み時間を評価するために次のテストを行いました。

import pickle
import h5py
import pandas as pd
import scipy.io as sio
import time

#time pickle load
start_time = time.time()
pkl_array_foo = pickle.load(open('array_foo.pkl', 'rb'))
end_time = time.time()
delta_time = end_time - start_time
print('pickle', delta_time)

#time h5py load
start_time = time.time()
h5py_hdf_store = h5py.File('array_foo.h5')
h5py_array_foo = h5py_hdf_store['array_foo'][:,:]
end_time = time.time()
delta_time = end_time - start_time
print('h5py', delta_time)

#time pandas load
start_time = time.time()
df_array_foo = pd.read_hdf('df_foo.h5')
end_time = time.time()
delta_time = end_time - start_time
print('pandas', delta_time)

#time mat load
start_time = time.time()
dict_df_foo = sio.loadmat('mat_df_foo.mat')
mat_array_foo = dict_df_foo['mat_df_foo']
end_time = time.time()
delta_time = end_time - start_time
print('mat', delta_time)

結果は次のとおりです。

pickle 68.21923732757568
h5py 67.92283535003662
pandas 67.95403552055359
mat 67.09603023529053

興味深いことに、.mat ファイルはここで読み込みの利点を失ったようです。調査の結果、現実世界のデータは非常にまばらであることが判明しました。どのくらい疎かを把握するために、ゼロ以外の値をすべて 1 に置き換え、すべてを合計し、行列のサイズで割りました。これにより、約 0.28 の密度が得られました。この数値を使用して、おもちゃの例のランダム マトリックスをスパース マトリックスに置き換えました。

array_foo_sparse = sparse.random(10000,10000, density = 0.28)
array_foo = array_foo_sparse.todense()

実際、これがうまくいったようです:

pickle 69.06890630722046
h5py 68.73687291145325
pandas 69.12291169166565
mat 22.53125286102295

そのため、sparse として保存すると、pickle、pandas、および h5py の読み込み時間が短縮されるかどうかを調査したいと考えました。このために、スパース バージョンを直接 pickle に保存し、DataFrame のスパース バージョンを保存しました。

pickle.dump(array_foo_sparse, open('array_foo.pkl', 'wb'))
df_sparse = df.to_sparse()
df_sparse.to_hdf('df_foo.h5', 'df_foo')

h5py で保存しようとすると、エラーが発生しました。

TypeError: Object dtype dtype('O') has no native HDF5 equivalent

少し調査した結果、チャンク ストレージを使用する必要があるようですが、これをさらに調査することで当初の目標から遠ざかっていると感じました。

結果は次のとおりです。

pickle 38.300209283828735
pandas 470.5342836380005

pickle は高速化されているように見えましたが (それでも .mat ほど高速ではありませんでした)、pandas は大きな打撃を受け、読み込みに 8 分近くかかりました。

最後に、Python から直接マットに保存しようとしました。

array_foo_sparse = sparse.random(10000,10000, density = 0.28)
array_foo = array_foo_sparse.todense()

sio.savemat('array_foo.mat', {'array_foo':array_foo})

これをロードすると、次の結果が得られました。

mat 73.23888158798218

スパース バージョンを保存します。

array_foo_sparse = sparse.random(10000,10000, density = 0.28)
sio.savemat('array_foo.mat', {'array_foo':array_foo_sparse})

降伏

mat 29.749581336975098

高速ですが、MATLAB のマット ファイルよりも約 10 秒遅いです。

というわけで、ここからどこへ行こうか迷っています。MATLAB マット ファイルのパフォーマンスを達成する (または上回る) 方法はありますか? 可能であれば、同じ環境 (つまり、python、spyder) 内にとどまりたいです。

4

0 に答える 0