最近Parquetというファイルフォーマットを知りました。S3にデータを置いてDWHを作ったりする際などに使うようです。
pyarrowパッケージをインストールしていればpandasからFeatherやParquetにお手軽に保存できることに気づいたので試してみてCSVと比較してみます。
比較方法
以下のようなランダムな値を入れたレコードを生成させてテストデータに使用します。
import random
from time import time
from string import ascii_letters
import pandas as pd
from pathlib import Path
def random_datetime():
return pd.Timestamp(
year=int(random.uniform(1990, 2020)),
month=int(random.uniform(1, 12)),
day=int(random.uniform(1, 28)),
hour=int(random.uniform(1, 23)),
minute=int(random.uniform(1, 59)),
)
def gen_data(n=100):
return pd.DataFrame({
"int": list(range(n)),
"float": [random.random() for _ in range(n)],
"bool": [random.choice([True, False]) for _ in range(n)],
"string": [''.join(random.choices(ascii_letters, k=10)) for _ in range(n)],
"date": [random_datetime().date() for _ in range(n)],
"datetime": [random_datetime() for _ in range(n)]
})
そして、
- ファイルの保存(ディスクの書き込み)にかかった時間
- ファイルの読み込みにかかった時間
- ファイルサイズ
を比較してみます。
保存と読み込みは10回繰り返して平均をとります。
レコード数は [10_000, 100_000, 1_000_000, 10_000_000, 20_000_000]
で試します。
保存時のオプション引数はデフォルトから変更せず(圧縮アルゴリズムなどは変えず)以下のように保存します。
df.to_csv('df.csv', index=False)
df.to_feather('df.feather')
df.to_parquet('df.parquet', index=False)
なお検証時のバージョンは以下の通りです。
- python == 3.8
- pyarrow == 7.0.0
- pandas == 1.2.0
結果
保存速度
ファイルの保存にかかった時間は実数では上のグラフのようになりました。
CSVに比べた変化率は以下の表のようになります。
n |
feather |
parquet |
10,000 |
-78.4% |
-69.6% |
100,000 |
-95.0% |
-90.1% |
1,000,000 |
-95.9% |
-93.9% |
10,000,000 |
-96.0% |
-94.8% |
20,000,000 |
-96.0% |
-94.8% |
featherで78%~96%削減、parquetで70%~95%削減されました。レコード数が10,000のときが最も削減効率が悪かったです。
featherもparquetもcsvに比べると段違いに速いですが、featherのほうがparquetよりも若干速いですね。
読み込み速度
読み込みにかかった時間は次のグラフのようになります。
CSVに比べた変化率は以下の表のようになります。featherもparquetもcsvに比べると段違いに速いです。featherのほうがparquetより速いですね。
n |
feather |
parquet |
10,000 |
-48.9% |
-22.0% |
100,000 |
-73.0% |
-66.9% |
1,000,000 |
-73.4% |
-71.3% |
10,000,000 |
-70.0% |
-65.1% |
20,000,000 |
-68.1% |
-53.4% |
ファイルサイズ
ファイルサイズはCSVの半分程度になりました。
parquetはレコード数が増えるほどファイルサイズの削減効率が高まるようです。
n |
feather |
parquet |
10,000 |
-47.2% |
-39.1% |
100,000 |
-48.0% |
-41.9% |
1,000,000 |
-48.7% |
-52.7% |
10,000,000 |
-49.4% |
-54.6% |
20,000,000 |
-49.8% |
-55.0% |
(参考)グラフの元データ
上記のグラフの元となった具体的な数値の表も載せておきます。
n |
format |
write_mean |
write_std |
read_mean |
read_std |
size |
10000 |
csv |
0.044 |
0.001 |
0.013 |
0.001 |
0.683 |
10000 |
feather |
0.010 |
0.009 |
0.007 |
0.000 |
0.360 |
10000 |
parquet |
0.014 |
0.009 |
0.010 |
0.008 |
0.416 |
100000 |
csv |
0.425 |
0.005 |
0.101 |
0.003 |
6.929 |
100000 |
feather |
0.021 |
0.001 |
0.027 |
0.001 |
3.606 |
100000 |
parquet |
0.042 |
0.002 |
0.033 |
0.004 |
4.024 |
1000000 |
csv |
4.268 |
0.030 |
1.060 |
0.018 |
70.248 |
1000000 |
feather |
0.175 |
0.007 |
0.282 |
0.004 |
36.026 |
1000000 |
parquet |
0.261 |
0.008 |
0.304 |
0.006 |
33.239 |
10000000 |
csv |
43.220 |
0.294 |
11.146 |
0.245 |
711.997 |
10000000 |
feather |
1.709 |
0.023 |
3.346 |
0.108 |
360.235 |
10000000 |
parquet |
2.257 |
0.050 |
3.895 |
0.106 |
323.421 |
20000000 |
csv |
86.777 |
0.370 |
26.038 |
1.720 |
1434.600 |
20000000 |
feather |
3.458 |
0.054 |
8.299 |
0.439 |
720.470 |
20000000 |
parquet |
4.518 |
0.137 |
12.126 |
0.866 |
645.739 |
まとめ
データ分析時に前処理済みの訓練データの保存を行う際はcsvよりもfeatherやparquetのほうが良さそうですね。
「レコード数が極端に多いデータで、書き込み・読み込みの速度よりもファイルサイズの圧縮を重視したい」という場合はparquetのほうが良さそうですが、そうでない場合はfeatherが扱いやすそうです。