
本文介绍在 Polars 中高效地对多个数值列(如 x, y)在 group_by 后同步执行相同逻辑的聚合操作(如按 num_obs 加权平均),并支持与其他独立聚合(如 sum('num_obs'))无缝组合。
本文介绍在 polars 中高效地对多个数值列(如 `x`, `y`)在 `group_by` 后同步执行相同逻辑的聚合操作(如按 `num_obs` 加权平均),并支持与其他独立聚合(如 `sum('num_obs')`)无缝组合。
在 Polars 中,当需要对多个列应用完全相同的聚合逻辑(尤其是涉及跨列引用,如用 num_obs 对 x 和 y 加权求平均),最简洁、高效且符合惯用法的方式是:利用 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(),
# 独立聚合:num_obs 总和
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') 返回一个包含两列的表达式序列,后续所有算术操作(如 * pl.col('num_obs'))会自动广播到各列,无需循环或 map;
- 表达式完全惰性求值,底层由 Polars 查询引擎优化,性能远超 Python 层循环或 apply;
- 可与任意其他表达式(如 pl.col('num_obs').sum()、pl.count()、pl.first('other'))自由混搭在同一 agg() 中,语义清晰、结构紧凑。
⚠️ 注意事项:
- 列名必须全部存在且类型兼容(如 num_obs 需为数值型,否则 * 运算报错);
- 若需对不同列应用不同权重或逻辑,则应显式逐列书写(如 pl.col('x') * 0.8 + pl.col('y') * 0.2),而非依赖批量语法;
- pl.col(['x','y']) 写法等价,但 pl.col('x','y') 更简洁,推荐使用。
总结:避免手动遍历列名构造表达式,善用 pl.col(col1, col2, ...) 批量选择 + 向量化运算,是 Polars 中实现“多列同逻辑聚合”的最佳实践——兼具可读性、可维护性与高性能。











