はじめに
「Pythonでデータ前処理」と言ったら、多くの方が「...Pandas!」となると思います。しかしPandasは大きなデータを扱うときに処理速度が遅いなんてことがあります。
そこで色々と調べていたら「Pandasで行うデータ処理を100倍高速にするOut-of-CoreフレームワークVaex」という、あまりにもキャッチーなタイトルのサイトがあったので、Vaexを少し触ってみました。
以下では簡単に、
- Vaexとは何か?
- Pandasと比較してどのぐらい早いの?
- 結局PandasとVaexどっち使うの?
を記載します。
Vaexとは何か?
必要なデータを適宜読み出して処理したり(アウトオブコア)、分散処理(マルチコア)を行って、データ処理を行えるのがVaexらしいです。
確かにPandasだとメモリに乗らないほどの大規模データの処理が大変だったりするので、早いだけでなく大規模データを扱うにも適しているんですね。
あとVaexではデータファイルをhdf5に書き換えて読みます。hdf5というのは、[フォルダ+データファイル]をひとまとめにしたファイルのことだそうです。(HDF5形式のファイル (1) HDF5って?より引用)
hdf5に書き換えて読むので、必要なデータを適宜読み出して処理する(アウトオブコア)ことができるんですね。
Pandasと比較してどのぐらい早いの?
結論から述べます。Vaexで実行できる処理なら処理速度は「(感覚的に)1億倍早い」です。処理を待っている時間は、通常よりも長く感じるので、本当に「(感覚的に)1億倍早い」です。
では実際に試した処理について、どの程度時間がかかったか記載していきます。
今回はASHRAE-Great Energy Predictor IIIのtrain.csvとbuilding_metadata.csvを利用していきます。
train.csvは20,216,100行4列で686.8 MB、 building_metadata.csvは1,449行6列で49KBです。
実行処理 | Pandas | Vaex |
---|---|---|
データの読み込み | 10.2 | 0.0695 |
文字列をtimestampに変換 | 1.62 | 0.00368 |
データの結合 | 6.22 | 0.00102 |
timestampから年/月/日/曜日の情報抽出 | 5.55 | 0.0101 |
列同士の演算 | 3.93 | 0.00822 |
(仮)可視化 - ヒストグラム | 0.919 | 0.575 |
GROUPBY(一部データで実行) | 0.0032 | 0.00907 |
欠損値の確認 | 6.71 | 328!? |
(※時間は全て秒) | ||
(※Vaexでのデータの読み込みでは、hdf5ファイルを読み込んでいます。) |
上記確認していただくとお分かりのように、大体の処理が事実2兆倍ぐらい早いことがわかります。
しかし欠損値の確認はヤバイです。何が起きたんだという感じです。Vaexで全列の欠損を確認する際は、forループを回さなければいけなそうだったので、これはこれでしょうがないのですかね。(何かいい方法あったら教えてください。)
ということで以下にコードを記載しておきます。
データの読み込み
%%time
pd_train = pd.read_csv('train.csv')
pd_buildingmeta = pd.read_csv('building_metadata.csv')
%%time
vx_train = vx.open('train.hdf5')
vx_buildingmeta = vx.open('building_metadata.hdf5')
文字列をtimestampに変換
%%time
pd_train['timestamp'] = pd.to_datetime(pd_train["timestamp"])
# vaexにはpd.to_datetime関数みたいな便利機能がないのでdatetimeモジュールを利用
%%time
vx_train['timestamp'] = vx_train["timestamp"].apply(lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S'))
データの結合
%%time
pd_train_buildingmeta = pd_train.merge(pd_buildingmeta, left_on='building_id',
right_on='building_id')
%%time
vx_train_buildingmeta = vx_train.join(vx_buildingmeta, left_on='building_id',
right_on='building_id', lprefix='train', rprefix='building')
timestampから年/月/日/曜日の情報抽出
%%time
pd_train_buildingmeta["year"] = pd_train_buildingmeta["timestamp"].dt.year
pd_train_buildingmeta["month"] = pd_train_buildingmeta["timestamp"].dt.month
pd_train_buildingmeta["day"] = pd_train_buildingmeta["timestamp"].dt.day
pd_train_buildingmeta["hour"] = pd_train_buildingmeta["timestamp"].dt.hour
pd_train_buildingmeta["minute"] = pd_train_buildingmeta["timestamp"].dt.minute
pd_train_buildingmeta["weekofyear"] = pd_train_buildingmeta["timestamp"].dt.weekofyear
%%time
vx_train_buildingmeta["year"] = vx_train_buildingmeta["timestamp"].dt.year
vx_train_buildingmeta["month"] = vx_train_buildingmeta["timestamp"].dt.month
vx_train_buildingmeta["day"] = vx_train_buildingmeta["timestamp"].dt.day
vx_train_buildingmeta["hour"] = vx_train_buildingmeta["timestamp"].dt.hour
vx_train_buildingmeta["minute"] = vx_train_buildingmeta["timestamp"].dt.minute
vx_train_buildingmeta["weekofyear"] = vx_train_buildingmeta["timestamp"].dt.weekofyear
列同士の演算
%%time
pd_train_buildingmeta['age_of_a_building'] = pd_train_buildingmeta['year'] - pd_train_buildingmeta['year_built']
%%time
vx_train_buildingmeta['age_of_a_building'] = vx_train_buildingmeta['year'] - vx_train_buildingmeta['year_built']
(仮)可視化 - ヒストグラム
%%time
pd_train_buildingmeta["meter_reading"].hist()
%%time
vx_train_buildingmeta.plot1d(vx_train_buildingmeta["meter_reading"], what="count(*)")
GROUPBY(10,000行抽出して実行)
%%time
selected_pd_train.groupby("meter").agg({"meter_reading": "mean"})
%%time
selected_vs_train.groupby("meter").agg({"meter_reading": "mean"})
欠損値の確認
%%time
pd_buildingmeta.isnull().sum()
# forループを実装する以外の方法が見つからなかったため、forループを利用
%%time
for col in vx_buildingmeta.column_names:
print(vx_buildingmeta[col].isna().sum())
結局PandasとVaexどっち使うの?
まあ列同士の演算とか文字列操作等の限られた操作&大規模データならVaexはいいかも。
しかし
- multiple keyでのデータ結合ができない
- 可視化が微妙
- 欠損値の確認遅い
など一部歯痒いところがあったので、これからの改善に期待します。
参考サイト:
https://vaex.readthedocs.io/en/latest/
https://blog.ikedaosushi.com/entry/2019/04/14/173307
https://blog.ikedaosushi.com/entry/2019/04/14/003916
http://villageofsound.hatenadiary.jp/entry/2014/10/29/021605
http://www.nakl.t.u-tokyo.ac.jp/~masuda/papers/pnt07Symp.pdf