在Polars的数据处理场景中,窗口内添加行号是分组统计、排序标记等需求的常见操作,通过合理的窗口配置和函数组合就能轻松实现,不需要复杂的自定义逻辑。
基础实现:排序后添加全局行号
如果只需要在排序后的DataFrame中添加全局的行号,不需要分组,可以直接使用with_row_count方法,这个方法会按照当前DataFrame的顺序添加从1开始的行号。
import polars as pl
# 构造示例数据
df = pl.DataFrame({
"name": ["张三", "李四", "王五", "赵六"],
"score": [89, 92, 78, 95]
})
# 先按分数降序排序,再添加行号
sorted_df = df.sort("score", descending=True)
result = sorted_df.with_row_count("rank", offset=1)
print(result)
上述代码中,with_row_count的第一个参数是行号的列名,offset参数用来设置行号的起始值,默认是0,这里设置为1符合常见的排名习惯。
分组窗口内添加行号
如果需要在每个分组内单独添加行号,比如统计每个班级内学生的成绩排名,就需要结合over窗口函数和row_number函数来实现。
import polars as pl
# 构造分组示例数据
df = pl.DataFrame({
"class": ["一班", "一班", "一班", "二班", "二班", "二班"],
"name": ["张三", "李四", "王五", "赵六", "钱七", "孙八"],
"score": [89, 92, 78, 95, 88, 90]
})
# 按班级分组,组内按分数降序添加行号
result = df.with_columns(
pl.col("score").rank(method="dense", descending=True).over("class").alias("class_rank")
)
print(result)
这里使用rank函数结合over("class")指定窗口为班级分组,method="dense"表示密集排名,相同分数会获得相同排名,且排名连续不跳跃。如果需要严格的行号,即使分数相同也按顺序编号,可以使用row_number函数。
import polars as pl
df = pl.DataFrame({
"class": ["一班", "一班", "一班", "二班", "二班", "二班"],
"name": ["张三", "李四", "王五", "赵六", "钱七", "孙八"],
"score": [89, 92, 89, 95, 88, 90]
})
# 分组内按分数降序,相同分数按姓名排序后添加行号
result = df.with_columns(
pl.row_number().over("class").alias("class_row_num")
).sort(["class", "score"], descending=[True, False])
print(result)
自定义排序规则的窗口行号
如果在窗口内需要按照多个字段排序再添加行号,可以在over之前先对数据排序,或者在窗口函数内指定排序规则。Polars的row_number函数支持在窗口内指定排序字段。
import polars as pl
df = pl.DataFrame({
"class": ["一班", "一班", "一班", "二班", "二班", "二班"],
"name": ["张三", "李四", "王五", "赵六", "钱七", "孙八"],
"score": [89, 92, 89, 95, 88, 90],
"age": [18, 17, 18, 19, 18, 17]
})
# 分组内先按分数降序,再按年龄升序,最后添加行号
result = df.with_columns(
pl.row_number()
.over("class")
.alias("custom_rank")
).sort(["class", "score", "age"], descending=[False, True, False])
print(result)
上述代码中,先对整体数据按照需要的规则排序,再在每个班级分组内添加行号,就能得到符合自定义排序规则的窗口行号结果。
不同场景的选择建议
- 如果是全局排序后的行号,优先使用
with_row_count,性能更高且逻辑简单。 - 如果需要分组内的排名,且相同值需要相同排名,使用
rank函数结合over。 - 如果需要分组内严格顺序的行号,即使值相同也按顺序编号,使用
row_number结合over。 - 如果窗口内的排序规则比较复杂,建议先对数据整体排序,再添加行号,避免窗口函数内的排序逻辑过于复杂。