客至汲泉烹茶, 抚琴听者知音

数据存储格式选择:Parquet、HDF还是Feather?

前言

最近在写的策略框架需要对数据进行频繁读取,传统的sqlite肯定不考虑,因为数据量比较大,读取速度太慢,所以考虑使用其他格式存储数据。常见的df存储格式有csv,hdf5,feather,Parquet,本文将对这几种格式进行测试,看看哪一种格式最适合我。

测试代码

参考了以下代码:https://github.com/stefan-jansen/machine-learning-for-trading/blob/master/02_market_and_fundamental_data/05_storage_benchmark/storage_benchmark.ipynb

from pathlib import Path
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import random
import string

results = {}

def generate_test_data(nrows=1000, numerical_cols=200, text_cols=0, text_length=10):
    s = "".join([random.choice(string.ascii_letters)
                 for _ in range(text_length)])
    data = pd.concat([pd.DataFrame(np.random.random(size=(nrows, numerical_cols))),
                      pd.DataFrame(np.full(shape=(nrows, text_cols), fill_value=s))],
                     axis=1, ignore_index=True)
    data.columns = [str(i) for i in data.columns]
    return data

data_type = 'Numeric'

df = generate_test_data(numerical_cols=200, text_cols=10) # 数据生成
df.info()

parquet_file = Path('test.parquet') # 以parquet为例
df.to_parquet(parquet_file)
size = parquet_file.stat().st_size

%%timeit -o
df = pd.read_parquet(parquet_file) # 读取
read = _
parquet_file.unlink()

%%timeit -o
df.to_parquet(parquet_file) # 写入
parquet_file.unlink()
write = _

results['Parquet'] = {'read': np.mean(read.all_runs), 'write': np.mean(write.all_runs), 'size': size}
results['Parquet'] # 测试结果保存

pandas读取写入这些格式的代码:

df = pd.read_parquet(parquet_file) # parquet读取
df.to_parquet(parquet_file) # parquet写入

with pd.HDFStore(test_store) as store:
    store.get(key)       # HDF Fixed、HDF Table、HDF Select读取

with pd.HDFStore(test_store) as store:
    store.put(key, df)   # HDF Fixed写入
    store.append('file', df, format='t') # HDF Table写入
    store.append('file', df, format='t', data_columns=['company', 'form'])  # HDF Select写入

pd.read_csv(test_csv) # csv读取
df.to_csv(test_csv) # csv写入

pd.read_feather(test_feather) # feather读取
df.to_feather(test_feather) # feather写入

测试结果

共测试了三个不同大小的数据集,其中表头为数据集占用内存大小,因为电脑性能原因,我没办法测试更大的数据了(实际上HDF Table和Select就因为内存爆了所以没有测试结果)。测试结果如下。

1.6+MB152.6+ MB1.5+ GB
ReadParquet22.5 ms697 ms5.14 s
HDF Fixed9.9 ms3.21 s81 s
HDF Table16.1 ms7.41 s
HDF Select15.6 ms7.36 s
csv47.5 ms3.92 s41.9 s
feather3.79 ms390 ms4.14 s
WriteParquet34.4 ms3.71 s33.7 s
HDF Fixed11.9 ms3.23 s51 s
HDF Table17.9 ms8.49 s
HDF Select17.8 ms8.49 s
csv301 ms18.3 s191 s
feather13 ms1.98 s17.2 s
SizeParquet1.88MB94.12MB966.96MB
HDF Fixed2.67MB201.41MB2004.86MB
HDF Table1.76MB172MB
HDF Select1.76MB172MB
csv3.79MB288.74MB2887.42MB
feather1.67MB209.95MB2098.23MB

可以看到,三种不同大小的数据集中,feather读写速度都一枝独秀,大小占用中规中矩。Parquet在小数据集上表现较差,但随着数据量的增加,其读写速度相比与其他格式就有了很大优势,在大数据集上,Parquet的读取速度甚至能和feather一较高下,可以想象数据量突破2G后,Parquet的读取速度可能就是最快的了。但是在写方面,Parquet一直没有表现出超越feather的势头。Parquet另外一个优势就是压缩率高,占用空间相比于其他格式一直是比较小的。hdf比较尴尬,在小数据集上打不过feather,在大数据集上的读取速度甚至比不上csv。至于csv就不用说了,各方面拉跨。

值得注意的是,feather虽然快,但是它不支持dataframe的index,也就是说你传入带index的df它会报错……

看了测试结果,相信你心中已经有了各个格式的应用场景。尴尬的是,我的单个数据集刚好只有40M,这个场景下用Parquet感觉没啥必要……

添加新评论