CSV无可厚非的是一种良好的通用文件存储方式,几乎任何一款工具或者编程语言都能对其进行读写,但是当文件特别大的时候,CSV这种存储方式就会变得十分缓慢且低效。本文将介绍几种在Python中能够代替CSV这种格式的其他文件格式,并对比每种文件存储的时间与大小。
先说结论,parquet 是最好的文件存储格式,具体对比见下文。
生成随机数据
导入依赖
import random
import string
import pickle
import numpy as np
import pandas as pd
import tables
import pyarrow as pa
import pyarrow.feather as feather
import pyarrow.parquet as pq
import fastparquet as fp
生成随机数据
这里使用pandas的dataframe来存储数据
row_num = int(1e7)
col_num = 5
str_len = 4
str_nunique = 10
int_matrix = np.random.randint(0, 100, size=(row_num, col_num))
df = pd.DataFrame(int_matrix, columns=['int_%d' % i for i in range(col_num)])
float_matrix = np.random.rand(row_num, col_num)
df = pd.concat(
(df, pd.DataFrame(float_matrix, columns=['float_%d' % i for i in range(col_num)])), axis=1)
str_list = [''.join(random.sample(string.ascii_letters, str_len))
for _ in range(str_nunique)]
for i in range(col_num):
sr = pd.Series(str_list*(row_num//str_nunique)
).sample(frac=1, random_state=i)
df['str_%d' % i] = sr
print(df.info())
生成100w行数据,其中整型,浮点型和字符串各5列,数据大小在内存里大概为1GB+
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000000 entries, 0 to 9999999
Data columns (total 15 columns):
--- ------ -----
0 int_0 int64
1 int_1 int64
2 int_2 int64
3 int_3 int64
4 int_4 int64
5 float_0 float64
6 float_1 float64
7 float_2 float64
8 float_3 float64
9 float_4 float64
10 str_0 object
11 str_1 object
12 str_2 object
13 str_3 object
14 str_4 object
dtypes: float64(5), int64(5), object(5)
memory usage: 1.1+ GB
保存文件
csv
CSV的保存方式很简单,直接使用pandas自带的to_csv() 方法即可 ```python在这里插入代码片
写入
df.to_csv(’./df_csv.csv’, index=False)
读取
df = pd.read_csv(’./df_csv.csv’)
写入时间花费:78 s
读取时间花费:11.8 s
所需存储空间:1.3GB
## csv + gz
基于自带的压缩方法,对保存的csv文件使用gzip算法进行压缩
```python
# 写入
df.to_csv('./df_csv.csv.gz', index=False, compression='gzip')
# 读取
df = pd.read_csv('./df_csv.csv.gz', compression='gzip')
写入时间花费:259 s
读取时间花费:22.8 s
所需存储空间:508M
csv + zip
基于自带的压缩方法,对保存的csv文件使用zip算法进行压缩
df.to_csv('./df_csv.csv.zip', index=False, compression='zip')
df = pd.read_csv('./df_csv.csv.zip', compression='zip')
写入时间花费:177 s
读取时间花费:20.7 s
所需存储空间:511M
pkl
pkl文件需要用到built-in 的pickle包
with open('./df_pkl.pkl', 'wb') as f:
pickle.dump(df, f)
with open('./df_pkl.pkl', 'rb') as f:
df = pickle.load(f)
写入时间花费:2.89 s
读取时间花费:2.61 s
所需存储空间:858M
npy
npy是numpy自带的一种保存格式,唯一的缺点是只能保存numpy的格式,所以需要将pandas先转成numpy才行,为了公平,这里我们会算上转换的时间
with open('./df_npy.npy', "wb") as f:
np.save(f, arr=df.values)
with open('./df_npy.npy', "rb") as f:
df_array = np.load(f, allow_pickle=True)
df = pd.DataFrame(df_array)
hdf
层次数据格式(HDF)是自描述的,允许应用程序在没有外部信息的情况下解释文件的结构和内容。一个HDF文件可以包含一系列相关对象,这些对象可以作为一个组或单个对象进行访问。
这里将使用pandas自带的to_hdf() 方法,该方法默认是用的HDF5 格式
df.to_hdf('df_hdf.h5', key='df')
df = pd.read_hdf('df_hdf.h5', key='df')
写入时间花费:3.96 s
读取时间花费:4.13 s
所需存储空间:1.5G
已废弃 msgpack
pandas支持msgpack格式的对象序列化。他是一种轻量级可移植的二进制格式,同二进制的JSON类似,具有高效的空间利用率以及不错的写入(序列化)和读取(反序列化)性能。
从0.25版本开始,不推荐使用msgpack格式,并且之后的版本也将删除它。推荐使用pyarrow对pandas对象进行在线的转换。 read_msgpack() (opens new window)仅在pandas的0.20.3版本及以下版本兼容。
parquet
Apache Parquet为数据帧提供了分区的二进制柱状序列化。它的设计目的是使数据帧的读写效率,并使数据共享跨数据分析语言容易。Parquet可以使用多种压缩技术来尽可能地缩小文件大小,同时仍然保持良好的读取性能。
这里需要使用到pyarrow 里面的方法来进行操作
pq.write_table(pa.Table.from_pandas(df), 'df_parquet.parquet')
df = pq.read_table('df_parquet.parquet').to_pandas()
写入时间花费:3.47 s
读取时间花费:1.85 s
所需存储空间:426M
feature
Feather是一种可移植的文件格式,用于存储内部使用Arrow IPC格式的Arrow表或数据帧(来自Python或R等语言)。Feather是在Arrow项目早期创建的,作为Python和R的快速、语言无关的数据帧存储概念的证明。
这里需要使用到pyarrow 里面的方法来进行操作
feather.write_feather(df, 'df_feather.feather')
df = feather.read_feather('df_feather.feather')
写入时间花费:1.9 s
读取时间花费:1.52 s
所需存储空间:715M
总结
对比表格
时间对比
空间对比
可以看出parquet 会是一个保存文件的最好选择,虽然时间上比feature略慢一点,但空间上有着更大的优势。
最后,感谢您的阅读。您的每个点赞、留言、分享都是对我们最大的鼓励,笔芯~
如有疑问,欢迎在评论区一起讨论!
|