使用 Pandas 和/或 Numpy 进行读/写操作的最快文件格式 [关闭]

Posted

技术标签:

【中文标题】使用 Pandas 和/或 Numpy 进行读/写操作的最快文件格式 [关闭]【英文标题】:Fastest file format for read/write operations with Pandas and/or Numpy [closed] 【发布时间】:2014-05-21 09:24:18 【问题描述】:

我已经使用非常大的 DataFrame 工作了一段时间,并且一直在使用 csv 格式来存储输入数据和结果。我注意到读取和写入这些文件需要花费大量时间,例如,这会大大减慢数据的批处理速度。我想知道文件格式本身是否相关。有没有 更快地读取/写入 Pandas DataFrames 和/或 Numpy 数组的首选文件格式?

【问题讨论】:

【参考方案1】:

使用 HDF5。胜过编写平面文件。并且可以查询。文档是here

这是perf comparison vs SQL。更新以显示 SQL/HDF_fixed/HDF_table/CSV 写入和读取性能。

文档现在包含一个性能部分:

见here

【讨论】:

我不知道性能部分是否从 2014 年开始编辑,但现在那里的结果表明,feather 和 pickle 比 HDF 更快。但我认为 HDF 的采用范围更广? 链接移至https://pandas.pydata.org/pandas-docs/stable/io.html#performance-considerations【参考方案2】:

最近,pandas 使用库 pyarrow(由 Wes Mckinney 本人编写,使用他常用的 obsession for performance)作为后端添加了对 parquet 格式的支持。

您只需要安装pyarrow 库并使用方法read_parquetto_parquet。 Parquet 对于更大的数据集(超过几百兆字节或更多)的读写速度要快得多,并且它还跟踪 dtype 元数据,因此在从磁盘写入和读取时不会丢失数据类型信息。它实际上可以更有效地存储一些 HDF5 性能不高的数据类型(如字符串和时间戳:HDF5 没有这些数据类型的本机数据类型,因此它使用 pickle 对它们进行序列化,这对于大数据集来说很慢)。

Parquet 也是一种列格式,这使得做两件事变得非常容易:

快速过滤掉您不感兴趣的列。使用 CSV,您必须实际读取整个文件,然后才能丢弃不需要的列。使用镶木地板,您实际上可以只阅读您感兴趣的列。

使查询过滤掉行并仅读取您关心的内容。

最近另一个有趣的发展是 Feather 文件格式,它也是由 Wes Mckinney 开发的。它本质上只是一种直接写入磁盘的未压缩arrow 格式,因此它的写入速度可能比 Parquet 格式更快。缺点是文件大 2-3 倍。

【讨论】:

完全同意。 pyarrow 中可用的“快速”压缩非常棒! 同意。 Parquet 在速度和文件大小方面轻松击败 HDF。【参考方案3】:

为您的用例运行一些基准测试总是一个好主意。我通过 numpy 存储原始结构取得了很好的效果:

df.to_records().astype(mytype).tofile('mydata')
df = pd.DataFrame.from_records(np.fromfile('mydata', dtype=mytype))

它非常快并且占用磁盘空间更少。但是:您需要跟踪 dtype 以重新加载数据,它不能在架构之间移植,并且它不支持 HDF5 的高级功能。 (numpy 有一个 more advanced binary format,它旨在克服前两个限制,但我并没有成功让它工作。)

更新:感谢您要求我提供数字。我的基准测试表明 HDF5 确实获胜,至少在我的情况下是这样。它更快并且在磁盘上更小!这是我看到的大约 280k 行、7 个浮点列和一个字符串索引的数据框:

In [15]: %timeit df.to_hdf('test_fixed.hdf', 'test', mode='w')
10 loops, best of 3: 172 ms per loop
In [17]: %timeit df.to_records().astype(mytype).tofile('raw_data')
1 loops, best of 3: 283 ms per loop
In [20]: %timeit pd.read_hdf('test_fixed.hdf', 'test')
10 loops, best of 3: 36.9 ms per loop
In [22]: %timeit pd.DataFrame.from_records(np.fromfile('raw_data', dtype=mytype))
10 loops, best of 3: 40.7 ms per loop
In [23]: ls -l raw_data test_fixed.hdf
-rw-r----- 1 altaurog altaurog 18167232 Apr  8 12:42 raw_data
-rw-r----- 1 altaurog altaurog 15537704 Apr  8 12:41 test_fixed.hdf

【讨论】:

出于好奇,您是否比较过使用 HDF5 节省 .npz 的性能? 不,我没有,我很想看到一个。我们在生产中使用 postgresql。我只在开发过程中使用原始格式来传递数据。 我只是做了一个快速比较,我将其添加到我的答案中 有趣;我没用过.npz,不过看起来很简单! 没有比to_hdf()read_hdf() 更简单的方法了。唯一的复杂性是额外的依赖关系。【参考方案4】:

HDF 确实是一个很好的选择,你也可以使用 npy/npz 有一些注意事项:

这是一个使用随机浮点数填充的 25k 行和 1000 列数据框的基准:

Saving to HDF took 0.49s
Saving to npy took 0.40s
Loading from HDF took 0.10s
Loading from npy took 0.061s

如果不压缩数据,npy 的写入速度大约快 20%,读取速度大约快 40%。

用于生成上述输出的代码:

#!/usr/bin/python3

import pandas as pd
import random
import numpy as np
import time

start = time.time()
f = pd.DataFrame()
for i in range(1000):
  f['col_'.format(i)] = np.random.rand(25000)
print('Generating data took s'.format(time.time() - start))

start = time.time()
f.to_hdf('frame.hdf', 'main', format='fixed')
print('Saving to HDF took s'.format(time.time() - start))

start = time.time()
np.savez('frame.npz', f.index, f.values)
print('Saving to npy took s'.format(time.time() - start))

start = time.time()
pd.read_hdf('frame.hdf')
print('Loading from HDF took s'.format(time.time() - start))

start = time.time()
index, values = np.load('frame.npz')
pd.DataFrame(values, index=index)
print('Loading from npy took s'.format(time.time() - start))

【讨论】:

这并不完全清楚你在用numpy 做什么。请您详细说明您用于numpy 的库和相关方法以及您用于pandas 的库和方法 我添加了我在回复中使用的代码。我希望它能解决您的担忧。【参考方案5】:

如果优先考虑速度,我会推荐:

羽毛 - 最快的 parquet - 有点慢,但可以节省大量磁盘空间

【讨论】:

以上是关于使用 Pandas 和/或 Numpy 进行读/写操作的最快文件格式 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

numpy pandas读文件 numpy数值计算模块

带有 SKLEARN、PANDAS 和 NUMPY 问题的 Python 部署包?

使用 Pandas 或 NumPy 的 Python 滚动夏普比率

使用 Python(Pandas 和 Numpy)进行线性回归

使用 Python(Pandas 和 Numpy)进行线性回归

何时使用 pandas 系列、numpy ndarrays 或简单的 python 字典?