如何在Parquet中存储和读取嵌套列表以避免类型异常?
解决Parquet存储嵌套数组时的类型异常问题
问题原因
当用pandas默认方式存储包含嵌套列表的DataFrame到Parquet时,嵌套列表列会被标记为object类型存储。读取时,pandas会自动把每个嵌套子列表转为numpy数组,再将这些数组封装到一个dtype=object的numpy数组中,导致最终的数组形状和类型不符合预期——无法直接当作标准二维numpy数组使用。
解决方案
以下几种方法可以避免这种异常,确保嵌套数组的结构和类型在存储/读取后符合预期:
方法1:使用PyArrow引擎并指定嵌套类型Schema
PyArrow对嵌套数据类型的支持更完善,通过显式定义Schema可以强制Parquet识别嵌套数组结构:
import pandas as pd import pyarrow as pa import pyarrow.parquet as pq import numpy as np values = [ [[1, 2], [3, 4]], [[5, 6], [7, 8]] ] # 定义嵌套数组的Schema:列表嵌套列表,元素为int64类型 schema = pa.schema([ ("lists", pa.list_(pa.list_(pa.int64()))) ]) # 将DataFrame转换为PyArrow Table并应用Schema table = pa.Table.from_pandas(pd.DataFrame({"lists": values}), schema=schema) # 写入Parquet文件 pq.write_table(table, "pq_file.parquet") # 读取文件并转回pandas DataFrame table_read = pq.read_table("pq_file.parquet") df_read = table_read.to_pandas() x = df_read["lists"][0] print(x) # 输出: [[1, 2], [3, 4]] print(type(x)) # 输出: <class 'list'> # 按需转换为标准二维numpy数组 y = np.array(x) print(y.shape) # 输出: (2, 2)
方法2:提前将嵌套列表转为标准numpy数组再存储
如果你的嵌套列表结构规整(每个子数组形状一致),可以先将其转换为numpy数组,再用PyArrow引擎存储:
import pandas as pd import numpy as np values = [ np.array([[1, 2], [3, 4]]), np.array([[5, 6], [7, 8]]) ] df = pd.DataFrame({"lists": values}) # 使用PyArrow引擎写入Parquet df.to_parquet("pq_file.parquet", engine="pyarrow") # 读取验证 df_read = pd.read_parquet("pq_file.parquet", engine="pyarrow") x = df_read["lists"][0] print(x.shape) # 输出: (2, 2) print(type(x)) # 输出: <class 'numpy.ndarray'>
方法3:使用FastParquet引擎时禁用对象转换(可选)
如果偏好使用FastParquet引擎,可以在读取时添加convert_objects=False参数,保留原始列表结构:
import pandas as pd df_read = pd.read_parquet("pq_file.parquet", engine="fastparquet", convert_objects=False) x = df_read["lists"][0] print(type(x)) # 输出: <class 'list'>
关于特殊object数组的说明
你手动构造时无法得到那种dtype=object的数组,是因为numpy会自动将形状统一的子数组合并为多维数组。而Parquet读取时的逻辑是逐个将嵌套子列表转为numpy数组,再将这些数组作为元素存入一个object数组中,这是pandas默认处理object类型列的机制导致的。
内容的提问来源于stack exchange,提问作者alexmolas
相关产品推荐
相关产品推荐

