You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Polars按ID和Action分组取最大值的实现问题及优化

Polars分组筛选最大值记录的正确实现方法

问题场景

现有包含ID、Action、Where、Value字段的Polars DataFrame,示例数据如下:

data = {
    "ID" : [1, 1, 2,2,3,3],
    "Action" : ["A", "A", "B", "B", "A", "A"],
    "Where" : ["Office", "Home", "Home", "Office", "Home", "Home"],
    "Value" : [1, 2, 3, 4, 5, 6]
}

df = pl.DataFrame(data)

需求:按ID和Action分组,筛选每组中Value最大的记录,以此获取用户偏好的操作地点。

现有实现的问题

当前实现通过窗口函数添加TOP列后,按所有字段降序排序再去重,但输出不符合预期:ID=1的Where字段错误显示为Office(预期应为Home)。

现有代码:

(
    df
    .select(
        pl.col("ID"),
        pl.col("Action"),
        pl.col("Where"),
        TOP = pl.col("Value").max().over(["ID", "Action"]))
    .sort(
        pl.col("*"), descending =True
    )
    .unique(
        subset = ["ID", "Action"],
        maintain_order = True,
        keep = "first"
    )
)

问题根源:排序时使用pl.col("*")会包含Where字段,字符串"Office"字典序大于"Home",导致ID=1的组中,Value更小的Office记录排在了前面,去重时被错误保留。

正确且高效的实现方法

方法1:窗口函数直接过滤(推荐)

直接筛选每组中Value等于组内最大值的行,逻辑清晰且性能最优:

result = (
    df
    .filter(pl.col("Value") == pl.col("Value").max().over(["ID", "Action"]))
    .with_columns(TOP=pl.col("Value"))
)
print(result)

输出符合预期:

shape: (3, 4)
┌─────┬────────┬────────┬─────┐
│ ID  ┆ Action ┆ Where  ┆ TOP │
│ --- ┆ ---    ┆ ---    ┆ --- │
│ i64 ┆ str    ┆ str    ┆ i64 │
╞═════╪════════╪════════╪═════╡
│ 1   ┆ A      ┆ Home   ┆ 2   │
│ 2   ┆ B      ┆ Office ┆ 4   │
│ 3   ┆ A      ┆ Home   ┆ 6   │
└─────┴────────┴────────┴─────┘

方法2:分组聚合

如果组内存在多个相同最大值的记录,可通过分组聚合指定保留第一条匹配的Where:

result = (
    df
    .group_by(["ID", "Action"], maintain_order=True)
    .agg(
        # 筛选组内Value最大的Where,取第一条
        Where=pl.col("Where").filter(pl.col("Value") == pl.col("Value").max()).first(),
        TOP=pl.col("Value").max()
    )
)
print(result)

方法3:修正排序逻辑的去重法

若坚持使用排序去重,需调整排序优先级,确保Value降序优先级高于Where:

result = (
    df
    .with_columns(TOP=pl.col("Value").max().over(["ID", "Action"]))
    # 先按ID、Action分组,再按Value降序排序
    .sort(["ID", "Action", "Value"], descending=[False, False, True])
    .unique(subset=["ID", "Action"], maintain_order=True, keep="first")
)
print(result)

性能对比

  • 方法1(窗口过滤):无需全量排序,仅做组内比较,性能最优,适合大数据集。
  • 方法2(分组聚合):逻辑清晰,适合需要对聚合结果做更多自定义处理的场景。
  • 方法3(排序去重):性能略逊于前两者,仅在特定场景下适用。

内容的提问来源于stack exchange,提问作者Simon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:43:12