猿问

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

有没有办法告诉 Pandas在编写 HDF5 文件时使用特定的 pickle 协议(例如 4) ?

这是情况(非常简化):

  • 客户端 A 正在使用python=3.8.1(以及pandas=1.0.0pytables=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) $ python

Python 3.8.1 (default, Jan  8 2020, 22:29:32)

[GCC 7.3.0] :: Anaconda, Inc. on linux

Type "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) $ python

Python 3.7.4 (default, Aug 13 2019, 20:35:49)

[GCC 7.3.0] :: Anaconda, Inc. on linux

Type "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 read


pandas=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引入的。


慕侠2389804
浏览 164回答 3
3回答

梵蒂冈之花

PyTable默认使用最高协议,这里硬编码:https ://github.com/PyTables/PyTables/blob/50dc721ab50b56e494a5657e9c8da71776e9f358/tables/atom.py#L1216作为一种解决方法,您可以pickle在编写 HDF 文件的客户端 A 上对模块进行猴子补丁。您应该在导入之前执行此操作pandas:import picklepickle.HIGHEST_PROTOCOL = 4import pandasdf.to_hdf(file, key)现在 HDF 文件已使用 pickle 协议版本 4 而不是版本 5 创建。

吃鸡游戏

更新:我错误地认为这是不可能的。事实上,基于@PiotrJurkiewicz 的优秀“monkey-patch”建议,这里有一个简单的上下文管理器,可以让我们临时更改最高的 pickle 协议。它:隐藏猴子补丁,并且在上下文之外没有副作用;它可以随时使用,无论之前是否进口泡菜,无论是在熊猫之前还是之后。这是代码(例如在文件中pickle_prot.py):import importlibimport pickleclass PickleProtocol:&nbsp; &nbsp; def __init__(self, level):&nbsp; &nbsp; &nbsp; &nbsp; self.previous = pickle.HIGHEST_PROTOCOL&nbsp; &nbsp; &nbsp; &nbsp; self.level = level&nbsp; &nbsp; def __enter__(self):&nbsp; &nbsp; &nbsp; &nbsp; importlib.reload(pickle)&nbsp; &nbsp; &nbsp; &nbsp; pickle.HIGHEST_PROTOCOL = self.level&nbsp; &nbsp; def __exit__(self, *exc):&nbsp; &nbsp; &nbsp; &nbsp; importlib.reload(pickle)&nbsp; &nbsp; &nbsp; &nbsp; pickle.HIGHEST_PROTOCOL = self.previousdef pickle_protocol(level):&nbsp; &nbsp; return PickleProtocol(level)writer中的用法示例:import pandas as pdfrom pickle_prot import pickle_protocolpd.DataFrame(['hello', 'world']).to_hdf('foo_0.h5', 'x')with pickle_protocol(4):&nbsp; &nbsp; pd.DataFrame(['hello', 'world']).to_hdf('foo_1.h5', 'x')pd.DataFrame(['hello', 'world']).to_hdf('foo_2.h5', 'x')并且,使用一个简单的测试阅读器:import pandas as pdfrom glob import globfor filename in sorted(glob('foo_*.h5')):&nbsp; &nbsp; try:&nbsp; &nbsp; &nbsp; &nbsp; df = pd.read_hdf(filename, 'x')&nbsp; &nbsp; &nbsp; &nbsp; print(f'could read {filename}')&nbsp; &nbsp; except Exception as e:&nbsp; &nbsp; &nbsp; &nbsp; print(f'failed on {filename}: {e}')现在,在用 py38 编写后尝试在 py37 中读取,我们得到:failed on foo_0.h5: unsupported pickle protocol: 5could read foo_1.h5failed on foo_2.h5: unsupported pickle protocol: 5但是,使用相同的版本(37 或 38)进行读写,我们当然也不例外。

繁华开满天机

我(曾经)面临同样的问题......我“知道”如何解决它,我认为你也这样做......解决方案是将整个数据重新处理为泡菜(或 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,这肯定会解决您的问题。:)
随时随地看视频慕课网APP

相关分类

Python
我要回答