
本文介绍如何在 Polars 中对多个数值列(如 x、y)在 group_by 后统一应用基于其他列(如 num_obs)的加权聚合,避免重复代码,并支持同时添加其他独立聚合(如求和、计数等)。
本文介绍如何在 polars 中对多个数值列(如 `x`、`y`)在 `group_by` 后统一应用基于其他列(如 `num_obs`)的加权聚合,避免重复代码,并支持同时添加其他独立聚合(如求和、计数等)。
在 Polars 中,当需要对多个列执行结构相同的聚合逻辑(例如:按 num_obs 加权求平均),无需逐列编写表达式或使用 Python 循环生成表达式列表。Polars 的 pl.col() 支持传入字符串列表,配合向量化运算,可天然实现“批量列操作”。
以示例数据为例:
import polars as pl
df = pl.DataFrame({
'group': [1, 1, 2, 2],
'other': ['a', 'b', 'a', 'b'],
'num_obs': [10, 5, 20, 10],
'x': [1, 2, 3, 4],
'y': [5, 6, 7, 8],
})目标是:按 'group' 分组,对 'x' 和 'y' 分别计算加权平均(权重为 'num_obs'),并同时汇总 'num_obs' 的总和。
✅ 推荐写法(简洁、高效、可扩展):
result = df.group_by('group').agg(
# 对 x 和 y 批量应用加权平均:(col * num_obs).sum() / num_obs.sum()
(pl.col('x', 'y') * pl.col('num_obs')).sum() / pl.col('num_obs').sum(),
# 同时添加其他独立聚合
pl.col('num_obs').sum().alias('total_num_obs'),
)
print(result)输出:
shape: (2, 4) ┌───────┬──────────┬──────────┬─────────────────┐ │ group ┆ x ┆ y ┆ total_num_obs │ │ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ f64 ┆ f64 ┆ i64 │ ╞═══════╪══════════╪══════════╪═════════════════╡ │ 1 ┆ 1.333333 ┆ 5.333333 ┆ 15 │ │ 2 ┆ 3.333333 ┆ 7.333333 ┆ 30 │ └───────┴──────────┴──────────┴─────────────────┘
? 原理说明:
- pl.col('x', 'y') 返回一个 列选择表达式序列,后续所有操作(如 *、.sum())会自动广播到每个匹配列,等价于分别对 x 和 y 执行 (x * num_obs).sum() 和 (y * num_obs).sum();
- 整个表达式 (pl.col('x','y') * pl.col('num_obs')).sum() / pl.col('num_obs').sum() 是纯惰性表达式,完全由 Polars 查询引擎优化执行,无 Python 层循环开销;
- 可自由混用其他聚合(如 pl.col('other').n_unique()、pl.count() 等),各表达式独立解析、并行计算。
⚠️ 注意事项:
- 列名必须全部存在且类型兼容(如 num_obs 需为数值型,否则 * 运算报错);
- 若需对不同列应用不同权重逻辑,则仍需显式列出各列表达式;
- pl.col() 接收元组/列表均可(pl.col(['x','y']) 效果一致),但推荐用括号语法更清晰;
- 如需重命名结果列,建议使用 .alias() 显式指定(如上例中 total_num_obs),避免默认列名歧义。
? 进阶提示:该模式同样适用于其他批量聚合场景,例如:
- 标准化:(pl.col('x','y') - pl.col('x','y').mean()).std()
- 条件加权:(pl.when(pl.col('other') == 'a').then(pl.col('x','y')).otherwise(0) * pl.col('num_obs')).sum()
综上,利用 pl.col(col_names) 批量选择 + 向量化表达式,是 Polars 中实现多列统一自定义聚合最简洁、高性能且符合惯用法的方式。

















