用pandas.DataFrame.to_parquet()需显式指定engine="pyarrow"、compression="snappy"、partition_cols,并清洗列名、统一混合类型、数值列用Int64/float64;大数据量应分块调用pyarrow写入并复用schema;读取时必用filters才能加速。

用 pandas.DataFrame.to_parquet() 最快上手,但默认行为容易踩坑
直接调用 to_parquet() 看似简单,但默认使用 pyarrow 引擎、不压缩、不指定 partition_cols,会导致文件体积大、后续查询慢。尤其当数据含大量重复字符串(如分类字段)时,未启用字典编码会浪费空间。
实操建议:
- 显式指定
engine="pyarrow"(避免fastparquet在某些类型上出错) - 加上
compression="snappy"(平衡速度与压缩率,"zstd"更省空间但稍慢) - 对高频过滤字段(如
"date","region")用partition_cols=["date", "region"],让下游pd.read_parquet()可跳过无关分区 - 若列名含空格或特殊字符,提前用
df.columns = df.columns.str.replace(r'[^a-zA-Z0-9_]', '_', regex=True)清洗,否则 PyArrow 可能报ArrowInvalid: Invalid field name
处理缺失值和混合类型列时,PyArrow 会静默转换类型
pandas 的 object 列含 None、数字、字符串混杂时,to_parquet() 默认按 PyArrow 的类型推断规则处理:可能转成 string,也可能崩成 large_string 或报错 ArrowTypeError: Could not convert ... with type ...: did not recognize Python value type。
稳妥做法:
- 对疑似混合列,先用
df[col].apply(type).unique()检查实际类型分布 - 强制统一类型:
df["col"] = df["col"].astype("string")(pandas 1.0+ 推荐)或df["col"] = df["col"].astype(str)(兼容旧版) - 数值列含
NaN时,避免用int64—— 改用Int64(nullable integer)或float64,否则写入 Parquet 会失败
大数据量分块写入需手动控制 pyarrow.parquet.write_table()
当 DataFrame 超过内存 1/3(比如 5GB 数据配 12GB 内存),直接 to_parquet() 易触发 MemoryError。这时得绕过 pandas 封装,用底层 PyArrow 分批写入。
关键步骤:
- 用
pa.Table.from_pandas(df_chunk)把每批转为 Arrow Table - 首次写入用
pa.parquet.write_table(table, "data.parq", use_dictionary=True, compression="snappy")
- 后续批次用
pa.parquet.write_to_dataset() 并指定 <code>existing_schema,否则不同批次字段类型不一致会报ArrowInvalid: Schema at position X was different - 务必在循环外预先调用
schema = pa.Table.from_pandas(first_chunk).schema,传给后续write_to_dataset(schema=schema)
读取时指定 filters 才能真正发挥 Parquet 分区和统计信息优势
只把数据存成 Parquet 不够,不利用其元数据就等于白存。例如分区目录 date=2024-01-01/region=US/ 下有 100 个文件,但 pd.read_parquet("data/", filters=[("date", "==", "2024-01-01")]) 能跳过其他日期目录,快 5–10 倍。
注意点:
-
filters语法是嵌套列表:单条件写成[("col", ">=", 100)],多条件用[("col1", "==", "A"), ("col2", "(AND 关系) - 仅对分区列或 Parquet 文件内建统计信息(min/max)生效;非分区列上的
filters仍需全量扫描,除非配合use_pandas_metadata=True和列裁剪 - 若写入时没开
use_dictionary=True,字符串列的 min/max 统计可能不准,导致过滤失效
Parquet 的高效依赖“写入时设计”——分区策略、类型对齐、字典编码这些动作没法靠读取时补救。很多人卡在最后一步:以为存完就结束了,其实真正省时间的是读取时那行 filters。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











