如何减少 HDFStore 的大小开销?

Posted

技术标签:

【中文标题】如何减少 HDFStore 的大小开销?【英文标题】:How to decrease size overhead of HDFStore? 【发布时间】:2014-03-05 07:20:50 【问题描述】:

我正在试验不同的熊猫友好型存储方案来存储刻度数据。迄今为止最快的(就读写而言)是使用具有 blosc 压缩和“固定”格式的 HDFStore。

store = pd.HDFStore(path, complevel=9, complib='blosc')
store.put(symbol, df)
store.close()

我按股票代码索引,因为这是我常用的访问模式。但是,此方案每个符号增加了大约 1 MB 的空间。也就是说,如果一只微型股票的数据框只包含当天的一千个刻度,则该文件的大小将增加一兆字节。因此,对于大量小型股票,.h5 文件很快就会变得笨拙。

有没有办法在保持 blosc/固定格式的性能优势的同时减小尺寸?我尝试过“表格”格式,每个符号大约需要 285 KB。

store.append(symbol, df, data_columns=True)

但是,这种格式的读写速度要慢得多。

如果有帮助,我的数据框如下所示:

exchtime     datetime64[ns]
localtime    datetime64[ns]
symbol               object
country               int64
exch                 object
currency              int64
indicator             int64
bid                 float64
bidsize               int64
bidexch              object
ask                 float64
asksize               int64
askexch              object

blosc 压缩本身工作得很好,因为生成的.h5 文件每行只需要 30--35 个字节。所以现在我主要关心的是减少 HDFStore 中每个节点的大小损失。

【问题讨论】:

AFAIK 它们是 PyTables 中块大小的某个最小值;您可以查看ptrepack 文件的各种选项。至少 1MB 可能是合理的恕我直言。也可以尝试写成Table的格式,不用设置全部data_columns=True,直接传format='table'即可;它将写入表格格式(但您将无法通过索引查询);但它存储为单个块,因此应该几乎与固定一样快(但空间效率更高)。 @Jeff 我应该将任何选项特别传递给ptrepack?如果我不提供任何选项,则生成的文件大小相同。 你可以试试chunkshape;我不知道这是否会改变大小。 @Jeff chunkshape=auto 缩小文件!我将对此进行试验,看看效果如何。 真的吗?那太棒了。仅供参考,它们也是 PyTables 3.1(刚刚发布)中的一个新的 blosc 过滤器,请参见此处:pytables.github.io/release-notes/RELEASE_NOTES_v3.1.x.html;不确定更新后的 blosc 会做什么(我认为 pandas 将直接通过参数传递,如果它不起作用,请提交错误报告 - 目前 pandas 不验证压缩器) 【参考方案1】:

AFAIK PyTables 中的块大小有一定的最小值。

以下是一些建议:

您可以使用chunkshape='auto' 选项ptrepack 文件。这将使用通过查看所有数据计算得出的块形状来打包它,并且可以以更有效的块大小重新打包数据,从而导致更小的文件大小。原因是 PyTables 需要被告知最终数组/表大小的预期行数。

您可以通过传递expectedrows=(并且只进行一次追加)以Table 格式实现最佳块大小。但是,ptrepacking 在这里仍然会有好处。

也可以尝试用Table格式写,不用设置全部data_columns=True,直接传format='table'即可;它将写入表格格式(但您将无法通过索引查询);但它存储为单个块,因此应该几乎和固定一样快(但空间效率更高)

在 PyTables 3.1(刚刚发布)中,有一个新的 blosc 过滤器。这可能会减少文件大小。 见here

【讨论】:

对于那些缺乏背景的人:ptrepack 是PyTables 附带的命令行实用程序。请注意,Python 包安装为tables:python -m pip show tables。它是 pandas 的依赖项,所以它应该已经存在。使用压缩重新打包的示例调用:ptrepack --chunkshape=auto --complevel=9 --complib=blosc <path/to/infile.h5> <path/to/outfile.h5> 请注意,对于 PyTables 3.6.1,在我的情况下,仅启用压缩会导致实际文件大小减小(带 str 和 datetime 的 60x10 表;原始 .csv:17kB,原始 .h5:1.1MB,重新打包/压缩的.h5:25kB)。单独使用 chunkshape='auto' 并没有帮助。【参考方案2】:

这通过一些示例和解释来扩充previous answer。对于我的 Pandas (1.2.3) 和 PyTables (3.6.1) 版本,当writing 到 HDF 存储时,我看到以下行为:

import pandas as pd
df = pd.DataFrame([[1, "a"], [2, "b"], [3, "c"]])

# Create a store with fixed format: creates considerable memory overhead!
# File size store1.h5: 1.1MB
store = pd.HDFStore("store1.h5")
store.put(key="some/key", value=df, format="fixed")
store.close()

# Better: create a store with table format.
# File size store1.h5: 86kB!
store = pd.HDFStore("store2.h5")
store.put(key="some/key", value=df, format="table")
store.close()

注意:不要使用商店,直接使用DataFrame.to_hdf()

df = pd.DataFrame([[1, "a"], [2, "b"], [3, "c"]])
df.to_hdf("store1.h5", key="some/key", format="fixed")
df.to_hdf("store2.h5", key="some/key", format="table")

在本例中,第二种方法 (store2.h5) 显着减少了内存开销。在更现实的情况下,随着数据量的增加,这种开销将变得不那么重要。固定格式存储允许快速读/写操作,而表格式更灵活(有关详细信息,请参阅docs)。 例如,table 格式可以比固定格式更好地处理混合数据类型(每列)。例如,如果您在上述示例中使用df.T.to_hdf(...),会发生什么情况。固定格式将发出以下 PerformanceWarning(请参阅 SO 上的 this post 或 this pandas 问题),而表格格式可以正常工作。

PerformanceWarning: your performance may suffer as PyTables will pickle 
object types that it cannot map directly to c-types

ptrepack 是PyTables 附带的命令行实用程序(包名为tables)。要查看当前版本的 PyTables:python -m pip show tables

使用 ptrepack,我可以通过应用一些压缩来进一步减小我的虚拟示例的文件大小。 (使用选项--chunkshape=auto 没有明显效果。)

# store1.repack.h5: 1.1MB -> 22kB
ptrepack --complevel=9 --complib=blosc "store1.h5" "store1.repack.h5"
# store2.repack.h5: 86kB -> 9kB
ptrepack --complevel=9 --complib=blosc "store2.h5" "store2.repack.h5"

总之,以表格格式保存数据帧并使用压缩重新打包生成的存储可以减少存储的内存占用。最小化 HDF 存储的存储开销是否合理取决于您的应用程序。

【讨论】:

以上是关于如何减少 HDFStore 的大小开销?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Pan Gesture 增加/减少字体大小?

如何尽可能减少 UIImage 的大小

前端性能优化篇—资源合并与压缩减少HTTP请求

如何减少android应用程序的大小?

数据库索引

如何减少访问文件的增长大小?