PyArrow 本身不压缩数据,但通过合理配置 Parquet 编码、类型精简和分块策略可将 CSV 或 Pandas 数据体积压缩至 1/5~1/10;关键在于用 Parquet 替代 CSV/Pickle,启用字典编码、snappy/zstd 压缩,收窄数据类型,并设置合适 row_group_size。

PyArrow 本身不压缩数据,但通过选择合适的 parquet 编码、类型精简和分块策略,能轻松把原始 CSV 或 Pandas DataFrame 占用空间压到 1/5~1/10。关键不在“用不用 PyArrow”,而在“怎么配”。
用 parquet 替代 csv 或 pickle 是前提
CSV 没类型、没压缩、全字符串;Pickle 有类型但不可跨语言、压缩弱、且不支持按列读取。Parquet 是列式存储,天然支持字典编码、位图压缩、页级统计——这些才是省空间的根基。
-
pyarrow.parquet.write_table()默认用snappy压缩,比gzip快很多,压缩率也够用;若追求极致体积,可换zstd(需安装pyarrow[with-zstd]) - 别直接
pa.table(df)后就写:先用cast()把冗余类型收窄——比如把int64列转成int32或int16,把长字符串列中重复值多的转成dictionary类型 - 写入时设
row_group_size=100_000(而非默认的 1M+),小 row group 更利于跳过无关数据,也提升压缩率(尤其配合字典编码)
dictionary 编码对高基数字符串无效,但对低基数极有效
PyArrow 的 dictionary 编码本质是把字符串映射为整数 ID,再对 ID 列做高效压缩。它只在值重复率高(比如国家名、状态码、分类标签)时才显著省空间;若每行都不同(如 UUID、长文本),反而多一层映射开销,体积可能更大。
- 检查重复率:
df["category"].nunique() / len(df)dictionary - 手动启用:
pa.dictionary(pa.string(), pa.int32()),然后用pa.array(..., type=...)构造列 - 自动推导?别依赖
use_dictionary=True默认行为——它只对str列试探性启用,且阈值不透明;显式 cast 更可控
避免 object 列隐式转成 string 导致膨胀
Pandas 里混合类型列(比如含 None + 数字)常被存成 object,PyArrow 读进来默认变成 string ——一个 int64 原本占 8 字节,转成字符串“1234567890”就占 10 字节,还失去数值操作能力。
立即学习“Python免费学习笔记(深入)”;
- 写入前清理:
df[col] = pd.to_numeric(df[col], errors="coerce")或df[col].astype("Int64")(Pandas nullable int) - 用
pa.Schema显式声明类型,例如pa.field("score", pa.int64(), nullable=True),防止 PyArrow 自作聪明 - 特别注意时间列:Pandas
datetime64[ns]写 Parquet 默认存为timestamp[ns],体积合理;但若混入 NaT 或转成字符串,就会爆炸
真正省空间的点从来不在“调用哪个函数”,而在类型定义是否精准、编码是否匹配数据分布、以及 row group 是否与查询模式对齐。一个 int8 列和一个 dictionary 字符列,可能比整个原始 CSV 还小;但加错一个 object 列,就能让文件翻倍——这种细节,跑完 benchmark 才看得见。


















