Polars 中按“Life–Death”区间计算列最大值的完整教程

2次阅读

Polars 中按“Life–Death”区间计算列最大值的完整教程

本文介绍如何在 Polars 中为每个以 “Life” 开头、以 “Death” 结尾的连续数据段,提取指定列(如 column A)的最大值,并仅将该值填充至对应 “Life” 行的新增列中,其余行置为 NULL

本文介绍如何在 polars 中为每个以 “life” 开头、以 “death” 结尾的连续数据段,提取指定列(如 `column a`)的最大值,并仅将该值填充至对应 “life” 行的新增列中,其余行置为 `null`。

在 Polars 中实现“区间最大值映射”——即对由特定标记(如 “Life” 起始、”Death” 终止)界定的逻辑子段,分别计算某列的最大值并仅赋给起始行——不能直接使用常规窗口函数,而需通过构造分组标识(group ID)+ 分组聚合 + 条件赋值三步完成。其核心在于:将非连续的语义区间(Life → … → Death)转化为可被 .over() 操作识别的数值分组标签。

✅ 解决思路拆解

  1. 识别关键事件:用布尔表达式标记 “Life” 和 “Death” 出现的位置;
  2. 构建累积分组号:利用 .cum_sum() 生成随每个 “Life” 或 “Death” 递增的序列,再通过 .forward_fill() 填充空值,形成初步分组;
  3. 修正分组边界:因 “Death” 行本身不属于当前 Life 区间,需将其 group_id 向前平移(.shift()),使整个 Life→Death 区间(含中间 null 行)共享同一 ID;
  4. 条件聚合与赋值:仅对 “Life” 行应用 .max().over(group_id),其余行保持 null。

? 完整代码实现

import polars as pl  df = pl.DataFrame({     "Column A": [2, 3, 1, 4, 1, 3, 3, 2, 1, 0],     "Column B": ["Life", None, None, None, "Death", None, "Life", None, None, "Death"] })  # 步骤 1:定义事件布尔列 is_life = pl.col("Column B") == "Life" is_death = pl.col("Column B") == "Death"  # 步骤 2 & 3:构造精准 group_id(自动对齐 Life-Death 区间) group_id = (     (is_life.cum_sum() + is_death.cum_sum())     .forward_fill()     .fill_null(0)  # 防止首行为 null 导致 fill 失败(可选) ) group_id = pl.when(is_death).then(group_id.shift()).otherwise(group_id)  # 步骤 4:仅在 Life 行注入区间最大值,生成 Column C result = df.with_columns(     pl.when(is_life)       .then(pl.col("Column A").max().over(group_id))       .alias("Column C") )  print(result)

输出结果

shape: (10, 3) ┌──────────┬──────────┬──────────┐ │ Column A ┆ Column B ┆ Column C │ │ ---      ┆ ---      ┆ ---      │ │ i64      ┆ str      ┆ i64      │ ╞══════════╪══════════╪══════════╡ │ 2        ┆ Life     ┆ 4        │ │ 3        ┆ null     ┆ null     │ │ 1        ┆ null     ┆ null     │ │ 4        ┆ null     ┆ null     │ │ 1        ┆ Death    ┆ null     │ │ 3        ┆ null     ┆ null     │ │ 3        ┆ Life     ┆ 3        │ │ 2        ┆ null     ┆ null     │ │ 1        ┆ null     ┆ null     │ │ 0        ┆ Death    ┆ null     │ └──────────┴──────────┴──────────┘

⚠️ 注意事项与最佳实践

  • forward_fill() 必不可少:原始 cum_sum() 在 null 行处会生成 null,必须填充才能参与后续算术运算;
  • shift() 默认向前移位:.shift() 将当前行的 group_id 替换为上一行值,确保 “Death” 行不开启新区间;
  • 避免整列 .max() 泄露:务必使用 .over(group_id) 实现分组内聚合,否则会计算全列最大值;
  • 类型一致性:若 Column A 为浮点型,.max() 返回 f64;若需统一为 f64 输出(如示例目标),可显式 .cast(pl.Float64);
  • 扩展性提示:该模式可轻松适配其他起止标记(如 “Start”/”End”)、多列聚合(.agg([pl.col(“A”).max(), pl.col(“B”).first()])),或结合 .map_batches() 处理更复杂逻辑。

此方法完全向量化、无 Python 循环,符合 Polars 高性能设计哲学,适用于百万级数据的高效区间分析场景。

text=ZqhQzanResources