pandas DataFrame存储列表:读写Parquet后赋值报错的解决与替代方案
1. 报错原因与解决方法
原因
初始代码中,给空DataFrame的单元格直接赋值列表时,pandas会自动将该列的 dtype 设为 object,允许存储任意Python对象。但当你先给单元格赋值整数1,此时列的 dtype 变为数值型(int),保存为Parquet后再读取,列的类型依然保持数值型。此时尝试给数值型列的单元格赋值列表,会触发类型不兼容报错——pandas无法将列表转换为数值类型存入该列。你尝试的astype(int)完全没用,反而强化了数值类型,问题根源是要把列改成能存储任意对象的类型。
解决方法
读取Parquet文件后,先将目标列的 dtype 改为object,再赋值列表:
import pandas as pd df1 = pd.DataFrame(index = ['R1'], columns = ['C1']) df1.loc['R1', 'C1'] = 1 df1.to_parquet('exampleTable.parquet') df2 = pd.read_parquet('exampleTable.parquet') # 先转换列类型为object df2['C1'] = df2['C1'].astype('object') # 再赋值列表 df2.loc['R1', 'C1'] = [1, 2] print(df2.loc['R1', 'C1']) # 输出 [1, 2]
如果一开始就需要存储列表,建议直接用pandas的ListDtype定义列类型,这样写入Parquet时能保留列表结构,无需后续转换:
import pandas as pd # 用ListDtype定义列类型 df1 = pd.DataFrame({'C1': pd.Series([[1,2]], dtype=pd.ListDtype(int))}, index=['R1']) df1.to_parquet('exampleTable.parquet') df2 = pd.read_parquet('exampleTable.parquet') # 可以直接修改或赋值列表 df2.loc['R1', 'C1'] = [3,4] print(df2.loc['R1', 'C1']) # 输出 [3,4]
2. 存储复杂数据结构的替代方案
如果需要存储列表、元组、字典、numpy数组甚至子DataFrame这类复杂结构,有几种可靠方案:
Pickle格式:直接保存整个DataFrame为pickle文件,完全保留所有Python对象类型,无需转换。缺点是文件不可读,且仅支持Python读取:
# 保存 df.to_pickle('data.pkl') # 读取 df = pd.read_pickle('data.pkl')JSON序列化:将复杂结构转为JSON字符串存入
object类型列,读取时再解析回原结构。优点是文件可读,跨语言兼容:import json import pandas as pd # 存入时转JSON df = pd.DataFrame({'C1': [json.dumps([1,2]), json.dumps({'key': 'value'})]}) df.to_parquet('data.parquet') # 读取时解析 df = pd.read_parquet('data.parquet') df['C1'] = df['C1'].apply(json.loads)HDF5格式:pandas支持用HDFStore存储复杂结构,适合大型数据集,支持增量读写:
# 保存 df.to_hdf('data.h5', key='df', mode='w') # 读取 df = pd.read_hdf('data.h5', key='df')嵌套友好的Parquet配置:如果坚持用Parquet,确保列的 dtype 是
object或pandas专用嵌套类型(如ListDtype、DictDtype),写入时使用pyarrow引擎,能直接保留复杂结构。
内容的提问来源于stack exchange,提问作者pkj

