如何保存pandas DataFrame以兼容旧版本pandas正常读取
背景
我使用的环境为Python 3.9.6和Pandas 1.3.0。
我的同事使用的环境为Python 3.6.12和Pandas 1.1.5。
我需要将生成的DataFrame共享给同事,且不希望要求对方更新环境(该操作会带来额外麻烦)。
问题
我如何在新版本Python/Pandas环境下将DataFrame导出为文件,使得旧版本Python/Pandas环境可以正常读取该文件为DataFrame格式?
已尝试或调研的方案
- 默认
.to_pickle()方法
我在新版本环境执行代码:
df.to_pickle(r"C:\somepath\file.bz2")
同事在旧版本环境执行代码:
pd.read_pickle(r"C:\somepath\file.bz2")
报错信息:
ValueError: unsupported pickle protocol: 5
- 在
.to_pickle()方法中指定protocol版本
尝试指定不同protocol版本:
df.to_pickle(r"C:\somepath\file.bz2", protocol=3)
旧版本加载仍报错:
AttributeError: module 'pandas.core.internals.blocks' has no attribute 'new_block'
protocol从0到5的所有版本都会触发该错误。
关于protocol版本的既往问题
查询到的同类问题仅得到「pandas版本必须匹配」的答案,但该方案不符合需求。关于
new_block属性的既往问题
同类报错问题给出的解决方案仍是升级pandas版本,无法采用。降级新版本Python/Pandas
理论可行,但属于最后备选方案,不想为了对接单个同事单独维护低版本环境。导出为CSV
该方案可行,但会丢失数据类型、NaN值等DataFrame特有属性,不符合需求。直接使用pickle库序列化
直接调用pickle库指定protocol=3写入文件:
import pickle with open('file.pkl', 'wb') as f: pickle.dump(df, f, 3)
旧版本环境读取:
import pickle with open('file.pkl', 'rb') as f: df = pickle.load(f)
仍触发报错:
AttributeError: module 'pandas.core.internals.blocks' has no attribute 'new_block'
- 转dict后再pickle
尝试将DataFrame转为dict后再序列化:
ddf = df.to_dict() with open('file.pkl', 'wb') as f: pickle.dump(ddf, f, 3)
旧版本环境读取时触发报错:
AttributeError: Can't get attribute '_unpickle_timestamp' on <module 'pandas._libs.tslibs.timestamps'
问题原因是DataFrame包含timestamp列,旧版本pandas无法反序列化该类型。
解决方案
补充说明:你遇到的pickle不兼容问题和Python的pickle协议版本无关,是因为Pandas不同版本的内部类结构发生了变化,低版本不存在高版本里的内部方法/属性,所以无论怎么调整pickle协议版本都无法直接反序列化高版本生成的DataFrame对象。
推荐以下几种跨版本兼容的方案,均能完整保留DataFrame的所有属性:
方案1:使用Feather格式(首选)
Feather是专门为DataFrame设计的跨语言跨版本存储格式,读写速度极快,无额外兼容性问题。
首先两边环境安装依赖:
pip install pyarrow
新版本环境导出代码:
df.to_feather(r"C:\somepath\file.feather")
旧版本环境读取代码:
import pandas as pd df = pd.read_feather(r"C:\somepath\file.feather")
方案2:使用Parquet格式
如果需要更高的压缩率、更小的文件体积,可以选择Parquet格式,同样需要安装pyarrow依赖:
新版本环境导出代码:
df.to_parquet(r"C:\somepath\file.parquet", engine="pyarrow")
旧版本环境读取代码:
import pandas as pd df = pd.read_parquet(r"C:\somepath\file.parquet", engine="pyarrow")
方案3:使用内置HDF5格式(无需额外依赖可选)
如果两边环境都无法安装新的第三方库,可以使用Pandas内置支持的HDF5格式(大部分标准Pandas安装都会自带tables依赖):
新版本环境导出代码:
df.to_hdf(r"C:\somepath\file.h5", key="df", mode="w")
旧版本环境读取代码:
import pandas as pd df = pd.read_hdf(r"C:\somepath\file.h5", key="df")
内容的提问来源于stack exchange,提问作者Saaru Lindestøkke

