
本文介绍使用 Polars 的 selectors、sum()、sum_horizontal() 和 concat() 一行式构建总计行与百分比行的高效方法,避免冗长的中间变量和手动拼接,显著提升代码可读性与维护性。
本文介绍使用 polars 的 selectors、sum()、sum_horizontal() 和 concat() 一行式构建总计行与百分比行的高效方法,避免冗长的中间变量和手动拼接,显著提升代码可读性与维护性。
在数据汇总分析中,常需在 DataFrame 末尾追加“总计(Total)”和“占比(Percentage)”两行——前者是各数值列的列和,后者是各列总和占所有列总和之和的百分比(四舍五入取整)。传统做法易陷入繁琐的 Series 拼接、类型转换与列对齐,而 Polars 提供了更函数式、声明式的解决方案。
核心思路是:
- 使用
cs.numeric().sum()一键获取所有数值列的列总和; - 利用
pl.sum_horizontal(pl.all())计算所有数值列总和的全局和(即所有列总和之和),再通过广播除法与cast(pl.Int64)得到整数百分比; - 用
with_columns(pl.lit(...).alias("Col Ind"))统一注入标识列值; - 最后通过
pl.concat(..., how="diagonal_relaxed")安全合并原始表与新增行(自动对齐列名,容忍缺失列)。
以下是完整、可直接运行的示例代码:
import polars as pl
import polars.selectors as cs
df = pl.DataFrame({
"Col Ind": ["A", "B", "C", "D", "E"],
"Col A": [1, 2, 3, 4, 5],
"Col B": [2, 4, 6, 8, 10],
"Col C": [1, 3, 5, 7, 9],
"Col D": [5, 4, 3, 2, 1],
})
# 一步生成总计行(所有数值列求和)
totals = df.select(cs.numeric().sum())
# 一步生成百分比行:每列总和 ÷ 全局总和 × 100 → 取整
percentage = totals.select(
(pl.all() * 100 / pl.sum_horizontal(pl.all())).cast(pl.Int64)
)
# 合并原始数据 + 总计行 + 百分比行,并插入标识列
result = pl.concat(
[df] +
[
dfx.with_columns(pl.lit(namex).alias("Col Ind"))
for dfx, namex in [(totals, "Total"), (percentage, "Percentage")]
],
how="diagonal_relaxed"
)
print(result)✅ 关键优势说明:
-
how="diagonal_relaxed"是 Polars 0.20+ 推荐的合并方式,能自动对齐列名、填充缺失列(值为null),比旧版vertical更健壮; -
cs.numeric()自动识别数值列,无需硬编码列名,增强代码通用性; -
pl.sum_horizontal(pl.all())避免手动sum(rowlist),语义清晰且向量化高效; -
pl.lit()确保"Col Ind"列值类型一致(字符串),避免类型推断歧义。
⚠️ 注意事项:
- 若原始 DataFrame 中存在非数值列(如分类列、时间列),
cs.numeric()会自动跳过,确保计算安全; - 百分比计算中若全局和为 0,将触发除零警告(可加
pl.when(...).then(...).otherwise(0)做兜底); - 如需保留小数位,将
.cast(pl.Int64)替换为.round(1)即可。
该方案将原需 10+ 行的逻辑压缩至 5 行核心代码,兼具表达力、性能与可维护性,是 Polars 函数式风格的典型实践。

















