Polars中链式.over()调用rolling_mean结果异常,sum无此问题
Polars中链式
.over()调用下rolling_mean与sum的行为差异及解决方案 问题原因
这是Polars当前表达式执行逻辑的已知限制,并非bug。核心差异源于两类函数的计算特性:
- 聚合类函数(如
sum):sum().over('grp')会为每个grp分组生成常量值,后续.over('date')仅对这些常量值按date分组排名,不会改变之前的聚合结果,因此单表达式与分步执行结果一致。 - 滚动类函数(如
rolling_mean):rolling_mean(2).over('grp')需要在grp分组内按行顺序计算窗口均值,但当链式调用第二个.over('date')时,Polars会重置计算上下文,将滚动窗口的分组逻辑替换为date,导致原grp分组的滚动计算失效,最终返回全null。
不使用临时列的解决方案
通过子表达式嵌套的方式,强制先完成grp分组的滚动计算,再对结果执行date分组的排名,避免上下文被覆盖:
pldf = pl.DataFrame({'grp': ['a', 'a', 'b', 'b'], 'date':[1,2,1,2], 'val': [0.5] * 4}) # 正确的单表达式写法 expr_fixed = pl.col(pl.col('val').rolling_mean(2).over('grp')).rank().over('date') pldf.with_columns(expr_fixed.alias('rank'))
执行后会得到与分步执行一致的正确结果:
shape: (4, 4) ┌─────┬──────┬─────┬──────┐ │ grp ┆ date ┆ val ┆ rank │ │ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ f64 ┆ f64 │ ╞═════╪══════╪═════╪══════╡ │ a ┆ 1 ┆ 0.5 ┆ 1.5 │ │ a ┆ 2 ┆ 0.5 ┆ 1.5 │ │ b ┆ 1 ┆ 0.5 ┆ 1.5 │ │ b ┆ 2 ┆ 0.5 ┆ 1.5 │ └─────┴──────┴─────┴──────┘
补充说明
另一种等价写法是用pl.select()包裹滚动计算步骤,同样能强制计算顺序:
expr_fixed = pl.select(pl.col('val').rolling_mean(2).over('grp')).rank().over('date')
内容的提问来源于stack exchange,提问作者noob_191
相关产品推荐
相关产品推荐

