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

Polars中为何需要第二个over?哪些函数会打破窗口上下文?

按分组新增列的窗口函数逻辑解析

原始数据

import polars as pl

df = pl.DataFrame({
    'year': [ 5, 5, 5, 
             10, 10, 
             15, 15, 
             30, 30, 30 ],
    'usage': ['farm', 'best', '',
               'manual', 'best',
               'best',  'city',
               'random', 'best', 'farm'  ],
    'value': [0.825, 0.83, 0.85,
              0.935, 0.96,
              1.12, 1.305,
              1.34, 1.34, 1.455],       
    'source': ['wood', 'metal', 'water',
               'metal', 'water',
               'wood',  'water',
               'wood', 'metal', 'water'  ]})

原始输出

┌──────┬────────┬───────┬────────┐
│ year ┆ usage  ┆ value ┆ source │
│ ---  ┆ ---    ┆ ---   ┆ ---    │
│ i64  ┆ str    ┆ f64   ┆ str    │
╞══════╪════════╪═══════╪════════╡
│ 5    ┆ farm   ┆ 0.825 ┆ wood   │
│ 5    ┆ best   ┆ 0.83  ┆ metal  │
│ 5    ┆        ┆ 0.85  ┆ water  │
│ 10   ┆ manual ┆ 0.935 ┆ metal  │
│ 10   ┆ best   ┆ 0.96  ┆ water  │
│ 15   ┆ best   ┆ 1.12  ┆ wood   │
│ 15   ┆ city   ┆ 1.305 ┆ water  │
│ 30   ┆ random ┆ 1.34  ┆ wood   │
│ 30   ┆ best   ┆ 1.34  ┆ metal  │
│ 30   ┆ farm   ┆ 1.455 ┆ water  │
└──────┴────────┴───────┴────────┘

需求

新增一列best,取值为每个year分组中usage等于"best"对应的source字段值。

用户疑问与解决方案

用户给出的可行代码如下,但存在两个疑问:

df.with_columns(
    pl.col('source').gather(pl.col('usage').eq('best').cast(pl.Int8).arg_max().over('year')).over('year').alias('best')
)
  1. 为什么需要两个over窗口?去掉第二个over后分组逻辑失效,原以为第一个over会作用于整个表达式。
  2. gather函数会打破窗口上下文,还有哪些函数有这类特性?

问题解析

一、为什么需要两个over?

1. 第一个over的作用

pl.col('usage').eq('best').cast(pl.Int8).arg_max().over('year')这部分是在每个year分组内定位目标行索引:

  • eq('best')把符合条件的行转成1,其他为0
  • arg_max()取最大值(即1)所在的行索引
  • .over('year')限定计算范围为每个year分组

这一步得到的是每个分组对应的单个索引值,但还只是分组级别的标量,没有对应到原数据的每一行。

2. gather的特性

gather是按索引提取元素的函数,它不会继承之前的窗口上下文——也就是说,当你用pl.col('source').gather(索引值)时,它只会用这个索引去取整个source列的对应值,而非当前分组内的source列。如果没有第二个over,gather只会返回和分组数一致的结果,无法匹配原数据的10行,导致分组逻辑失效。

3. 第二个over的作用

第二个.over('year')的核心是广播:把gather得到的单个分组值,复制到该year分组的每一行,确保原数据的每一行都能拿到对应分组的best来源值。

二、哪些函数会打破窗口上下文?

这类函数的共性是将整个列作为操作对象,而非保留分组后的局部上下文,常见的有:

  • gather/take:按索引提取元素,默认操作整个列
  • first/last(无窗口时):取整个列的首尾,而非分组内的首尾
  • sum/mean等聚合函数(无窗口时):计算整个列的聚合值,而非分组内聚合
  • sort_by:对整个列排序,不会保留分组内的排序逻辑
  • reverse:反转整个列,而非分组内反转

简单来说,所有不需要依赖窗口就能独立完成计算的函数,在窗口表达式内部使用时,都会打破之前的分组上下文,需要再次通过over明确分组范围。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 05:54:52