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

Polars中链式调用.over()时rolling_mean与分步执行结果不一致,sum表现正常

Polars链式窗口调用中rolling_mean与sum的差异问题解答

这是Polars当前已知的窗口函数链式调用行为限制,并非Bug。下面来拆解原因和解决方法:

问题原因

差异的核心在于两类窗口操作的执行逻辑不同:

  • sum().over()属于聚合窗口函数,它的计算基于分组内的所有行,结果在分组内恒定,链式调用第二个.over()时,Polars能正确识别前一步的聚合结果作为后续计算的输入。
  • rolling_mean().over()属于滑动窗口函数,它依赖分组内的行顺序和滑动窗口范围,结果逐行变化。当你在单个表达式中链式调用第二个.over()时,Polars的表达式优化器目前无法正确保留前一步滑动窗口的计算上下文,导致后续的rank().over()实际上是在原始列(而非滑动窗口的结果)上执行,最终返回null。

无临时列的解决方法

要保证正确的求值顺序,不需要引入临时列,可以使用.pipe()方法显式传递前一步的计算结果:

import polars as pl

pldf = pl.DataFrame({'grp': ['a', 'a', 'b', 'b'], 'date':[1,2,1,2], 'val': [0.5] * 4})

# 使用pipe控制求值顺序
result = pldf.with_columns(
    pl.col('val')
    .rolling_mean(2)
    .over('grp')
    .pipe(lambda rolling_result: rolling_result.rank().over('date'))
    .alias('rank')
)

print(result)

执行结果会和分步计算一致:

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  │
└─────┴──────┴─────┴──────┘

.pipe()的作用是把前一步的滑动窗口计算结果作为参数传给lambda函数,确保rank().over()是在正确的输入上执行,避免了上下文丢失的问题。

补充说明

这类窗口链式调用的限制是Polars开发团队已知的问题,后续版本可能会优化表达式优化器的逻辑,让滑动窗口的链式调用行为更符合直觉。在此之前,.pipe()是最简洁的无临时列解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 09:12:36