
本文详解如何在 polars 中通过 `.pivot()` 方法对 dataframe 按列值展开(unstack),完成分组聚合后的宽表转换,并处理缺失值填充,替代 pandas 中的 `groupby().sum().unstack()` 模式。
在数据处理中,将长格式(long format)DataFrame 转换为宽格式(wide format)——即按某一列的唯一值生成新列,并对对应行进行聚合——是常见需求。Pandas 中常用 groupby(...).agg(...).unstack(fill_value=0) 实现;而在 Polars 中,这一操作由 .pivot() 方法统一承载,兼具灵活性与高性能。
以下以实际示例说明完整流程:
✅ 输入数据准备
import polars as pl
df = pl.DataFrame({
"left": ["One", "One", "One", "One", "Two"],
"center": ["P", "P", "I", "I", "I"],
"right": [100, 100, 100, 100, 100]
})该 DataFrame 包含 5 行,需按 "left" 分组、按 "center" 列的值("P"/"I")展开为列,并对 "right" 求和。
✅ 核心操作:使用 .pivot()
result = df.pivot(
values="right", # 待聚合的数值列(等价于 Pandas 中 agg column)
index="left", # 作为新表索引(行标识)的列(等价于 groupby key)
columns="center", # 展开为列头的分类列(等价于 unstack level)
aggregate_function="sum" # 聚合方式;也支持 pl.sum(), pl.element().sum() 等
)? 注意:values、index、columns 是 .pivot() 的三个必需参数(Polars ≥ 0.20.0),语义清晰,类比 Pandas pivot_table(index=..., columns=..., values=..., aggfunc=...)。
执行后输出:
shape: (2, 3) ┌──────┬──────┬─────┐ │ left ┆ P ┆ I │ │ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ i64 │ ╞══════╪══════╪═════╡ │ One ┆ 200 ┆ 200 │ │ Two ┆ null ┆ 100 │ └──────┴──────┴─────┘
可见 "Two" 在 "P" 列下无对应数据,结果为 null —— 这与 Pandas 默认行为一致(unstack 不自动填 0)。
✅ 填充缺失值:.fill_null(0)
若需严格匹配预期输出(P 列中 "Two" 对应 0),链式调用 .fill_null(0) 即可:
result = (
df.pivot(values="right", index="left", columns="center", aggregate_function="sum")
.fill_null(0)
)最终得到:
shape: (2, 3) ┌──────┬─────┬─────┐ │ left ┆ P ┆ I │ │ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ i64 │ ╞══════╪═════╪═════╡ │ One ┆ 200 ┆ 200 │ │ Two ┆ 0 ┆ 100 │ └──────┴─────┴─────┘
⚠️ 注意事项与最佳实践
- 列值必须可哈希且唯一性明确:columns 参数指定的列中,每个值将成为新列名;若含重复或非法字符(如空格、.),建议提前 .alias() 或 .str.replace_all() 清洗。
- 聚合函数选择:除 "sum" 外,还支持 "mean"、"count"、"first"、"max" 等字符串简写,或传入 Polars 表达式(如 pl.col("right").sum())以实现复杂逻辑。
- 性能提示:.pivot() 是惰性求值友好的操作,在 LazyFrame 中同样可用,适合大规模数据管道。
- 与 .melt() 对称:.pivot() 和 .melt() 构成宽长互转的标准组合,推荐优先使用二者而非手动 group_by().agg() + join() 拼接。
掌握 .pivot(),你就能高效、声明式地完成 Polars 中的“unstack”任务,代码更简洁,语义更直观,性能更可控。










