为了账号安全,请及时绑定邮箱和手机立即绑定

将 pandas 写入 HDF5 时是否可以指定 pickle 协议?

将 pandas 写入 HDF5 时是否可以指定 pickle 协议?

慕侠2389804 2022-07-19 15:15:28
有没有办法告诉 Pandas在编写 HDF5 文件时使用特定的 pickle 协议(例如 4) ?这是情况(非常简化):客户端 A 正在使用python=3.8.1(以及pandas=1.0.0和pytables=3.6.1)。A 使用df.to_hdf(file, key).客户端 B 正在使用python=3.7.1(并且,正如它发生的那样,pandas=0.25.1并且pytables=3.5.2——但这无关紧要)。B 尝试使用 读取 A 写入的数据,但以pd.read_hdf(file, key)失败ValueError: unsupported pickle protocol: 5。请注意,纯数字 DataFrame 不会发生这种情况(例如pd.DataFrame(np.random.normal(size=(10,10)))。所以这是一个可重现的示例:(base) $ conda activate py38(py38) $ pythonPython 3.8.1 (default, Jan  8 2020, 22:29:32)[GCC 7.3.0] :: Anaconda, Inc. on linuxType "help", "copyright", "credits" or "license" for more information.>>> import pandas as pd>>> df = pd.DataFrame(['hello', 'world']))>>> df.to_hdf('foo', 'x')>>> exit()(py38) $ conda deactivate(base) $ pythonPython 3.7.4 (default, Aug 13 2019, 20:35:49)[GCC 7.3.0] :: Anaconda, Inc. on linuxType "help", "copyright", "credits" or "license" for more information.>>> import pandas as pd>>> df = pd.read_hdf('foo', 'x')Traceback (most recent call last):  File "<stdin>", line 1, in <module>  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/io/pytables.py", line 407, in read_hdf    return store.select(key, auto_close=auto_close, **kwargs)  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/io/pytables.py", line 782, in select    return it.get_result()  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/io/pytables.py", line 1639, in get_result    results = self.func(self.start, self.stop, where)  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/io/pytables.py", line 766, in func    return s.read(start=_start, stop=_stop, where=_where, columns=columns)  File "/opt/anaconda3/lib/python3.7/site-packages/pandas/io/pytables.py", line 3206, in readpandas=1.0.0注意:我也尝试pytables=3.6.1在python=3.7.4. 这也失败了,所以我相信它只是导致问题的 Python 版本(3.8 writer vs 3.7 reader)。这是有道理的,因为 pickle 协议 5 是作为Python 3.8的PEP-574引入的。
查看完整描述

3 回答

?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

PyTable默认使用最高协议,这里硬编码:https ://github.com/PyTables/PyTables/blob/50dc721ab50b56e494a5657e9c8da71776e9f358/tables/atom.py#L1216


作为一种解决方法,您可以pickle在编写 HDF 文件的客户端 A 上对模块进行猴子补丁。您应该在导入之前执行此操作pandas:


import pickle

pickle.HIGHEST_PROTOCOL = 4

import pandas


df.to_hdf(file, key)

现在 HDF 文件已使用 pickle 协议版本 4 而不是版本 5 创建。


查看完整回答
反对 回复 2022-07-19
?
吃鸡游戏

TA贡献1829条经验 获得超7个赞

更新:我错误地认为这是不可能的。事实上,基于@PiotrJurkiewicz 的优秀“monkey-patch”建议,这里有一个简单的上下文管理器,可以让我们临时更改最高的 pickle 协议。它:

  1. 隐藏猴子补丁,并且

  2. 在上下文之外没有副作用;它可以随时使用,无论之前是否进口泡菜,无论是在熊猫之前还是之后。

这是代码(例如在文件中pickle_prot.py):

import importlib

import pickle



class PickleProtocol:

    def __init__(self, level):

        self.previous = pickle.HIGHEST_PROTOCOL

        self.level = level


    def __enter__(self):

        importlib.reload(pickle)

        pickle.HIGHEST_PROTOCOL = self.level


    def __exit__(self, *exc):

        importlib.reload(pickle)

        pickle.HIGHEST_PROTOCOL = self.previous



def pickle_protocol(level):

    return PickleProtocol(level)

writer中的用法示例:


import pandas as pd

from pickle_prot import pickle_protocol



pd.DataFrame(['hello', 'world']).to_hdf('foo_0.h5', 'x')


with pickle_protocol(4):

    pd.DataFrame(['hello', 'world']).to_hdf('foo_1.h5', 'x')


pd.DataFrame(['hello', 'world']).to_hdf('foo_2.h5', 'x')

并且,使用一个简单的测试阅读器:


import pandas as pd

from glob import glob


for filename in sorted(glob('foo_*.h5')):

    try:

        df = pd.read_hdf(filename, 'x')

        print(f'could read {filename}')

    except Exception as e:

        print(f'failed on {filename}: {e}')

现在,在用 py38 编写后尝试在 py37 中读取,我们得到:


failed on foo_0.h5: unsupported pickle protocol: 5

could read foo_1.h5

failed on foo_2.h5: unsupported pickle protocol: 5

但是,使用相同的版本(37 或 38)进行读写,我们当然也不例外。


查看完整回答
反对 回复 2022-07-19
?
繁华开满天机

TA贡献1816条经验 获得超4个赞

我(曾经)面临同样的问题......我“知道”如何解决它,我认为你也这样做......解决方案是将整个数据重新处理为泡菜(或 csv)并重新转换它在 python3.7 到 hdf5(只知道协议 4)。

流程是这样的:python3.8 -> hdf5 -> python3.8 -> csv/pickle -> python3.7 -> hdf5(与两个版本兼容)

我避开了这条路线,因为我导出了数据框的大量数据,从而创建了大量文件。

您实际上仅限于使用 python3.7 吗?我受到 tensorflow 的限制,它目前仅支持 3.7(官方),但您可以安装 tensorflow-nightly-build,它适用于 python 3.8

检查您是否可以迁移到 3.8,这肯定会解决您的问题。:)


查看完整回答
反对 回复 2022-07-19
  • 3 回答
  • 0 关注
  • 163 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信