Polars是一款基于Rust开发的高性能Python数据处理库,在处理大规模结构化数据时性能表现优异。很多数据分析场景中,我们需要先按某个字段分组,再在组内筛选符合特定条件的记录,最后提取每组中分数最高的一条对应的目标值,这类需求用Polars可以高效实现。
基础数据准备
首先我们需要构造示例数据,模拟常见的业务场景数据,包含分组字段、匹配条件字段、分数字段和目标值字段。以下是构造示例数据的代码:
import polars as pl
# 构造示例数据
data = {
"group_id": ["A", "A", "A", "B", "B", "B", "C", "C"],
"match_flag": [1, 0, 1, 1, 1, 0, 0, 1],
"score": [85, 90, 78, 92, 88, 76, 89, 95],
"target_value": ["val_a1", "val_a2", "val_a3", "val_b1", "val_b2", "val_b3", "val_c1", "val_c2"]
}
df = pl.DataFrame(data)
print("原始数据:")
print(df)
按组筛选匹配项并提取最高分对应值
方法一:使用group_by结合filter和max
首先按group_id分组,然后在每个组内筛选match_flag为1的记录,再找到这些记录中score最高的那条,提取对应的target_value。代码如下:
result = (
df.group_by("group_id")
.agg(
# 筛选组内match_flag为1的记录
pl.col("target_value").filter(pl.col("match_flag") == 1)
# 按score降序排序,取第一个值即最高分对应的target_value
.sort_by(pl.col("score"), descending=True)
.first()
.alias("max_score_target")
)
)
print("方法一结果:")
print(result)
方法二:先全局筛选再分组处理
也可以先全局筛选出match_flag为1的记录,再按group_id分组取每个组的最高分对应值,这种方式在匹配项较少时性能更优。代码如下:
# 先筛选匹配项
filtered_df = df.filter(pl.col("match_flag") == 1)
# 按组取最高分对应的目标值
result2 = (
filtered_df.group_by("group_id")
.agg(
pl.col("target_value")
.sort_by(pl.col("score"), descending=True)
.first()
.alias("max_score_target")
)
)
print("方法二结果:")
print(result2)
结果验证与说明
上述两种方法的输出结果一致,以方法一为例,输出内容如下:
shape: (3, 2) ┌──────────┬──────────────────┐ │ group_id ┆ max_score_target │ │ --- ┆ --- │ │ str ┆ str │ ╞══════════╪══════════════════╡ │ A ┆ val_a1 │ │ B ┆ val_b1 │ │ C ┆ val_c2 │ └──────────┴──────────────────┘
结果说明:
- 组A中match_flag为1的记录是第一条和第三条,分数分别为85和78,最高分85对应target_value为val_a1
- 组B中match_flag为1的记录是第一条和第二条,分数分别为92和88,最高分92对应target_value为val_b1
- 组C中match_flag为1的记录是第二条,分数95对应target_value为val_c2
性能对比与选择建议
两种方法的适用场景不同:
- 如果大部分分组都有匹配项,方法一的分组后筛选逻辑更直观,代码可读性更高
- 如果匹配项占比很低,方法二先全局筛选可以减少后续分组处理的数据量,性能更优
当数据量达到百万级以上时,建议通过实际测试选择更适合当前数据特征的方法。如果需要在提取最高分对应值的同时保留其他字段,可以在agg中添加更多字段的提取逻辑,例如同时提取最高分本身:
result3 = (
df.group_by("group_id")
.agg(
pl.col("target_value").filter(pl.col("match_flag") == 1)
.sort_by(pl.col("score"), descending=True)
.first()
.alias("max_score_target"),
pl.col("score").filter(pl.col("match_flag") == 1)
.max()
.alias("max_score")
)
)
print("带最高分的结果:")
print(result3)
PolarsDataFramegroup_byfiltermax_score修改时间:2026-07-14 13:45:40