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

在Polars DataFrame中高效计算分组指数加权滚动和(窗口可配置)

高效实现Polars分组下基于Index窗口的指数加权滚动和

问题背景

给定如下Polars DataFrame,需要按id分组,以index差值≤指定窗口大小(示例为3)确定滚动窗口,计算指数加权滚动和:

import polars as pl

decay = 0.8

df = pl.DataFrame(
    {
        "id": [7, 1, 5, 7, 1, 5, 5, 7],
        "index": [5, 7, 7, 7, 8, 8, 9, 9],
        "x": [1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 3.0, 5.0],
    }
)

需求说明

  • 分组依据:id
  • 窗口规则:当前行index与历史行index的差值≤窗口大小(示例为3)
  • 计算逻辑:指数加权和 = (Σ(x_i * decay^(当前index - 历史index))) / (Σ(decay^(当前index - 历史index)))
  • 期望结果:
id   index   x
1    7       1.0
1    8       1.555
5    7       1.0
5    8       2.111
5    9       2.475
7    5       1.0
7    7       1.0
7    9       3.439

高效实现方案

利用Polars的group_by+dynamic窗口实现向量化计算,避免Python循环,适配大数据量场景:

import polars as pl

# 配置参数
decay = 0.8
window_size = 3

# 核心实现
result = (
    # 先按id和index排序,确保分组内index递增
    df.sort(["id", "index"])
    # 按id分组
    .group_by("id")
    # 定义基于index的动态窗口:范围为当前index - window_size 到 当前index
    .dynamic(
        index_column="index",
        period=f"{window_size}",
        unit="none",
        start_by="datapoint"
    )
    # 聚合计算分子和分母
    .agg(
        numerator=pl.sum(pl.col("x") * (decay ** (pl.max("index") - pl.col("index")))),
        denominator=pl.sum(decay ** (pl.max("index") - pl.col("index"))),
        index=pl.max("index"),
        id=pl.first("id")
    )
    # 计算最终加权结果
    .with_columns(pl.col("numerator") / pl.col("denominator").alias("x"))
    # 整理输出列并排序
    .select(["id", "index", "x"])
    .sort(["id", "index"])
)

# 打印结果(保留三位小数)
print(result.with_columns(pl.col("x").round(3)))

代码解释

  1. 排序:必须先按id和index排序,保证分组内的index是递增序列,确保动态窗口范围计算准确。
  2. 动态窗口:dynamic窗口基于index列的数值范围构建,period=f"{window_size}"指定窗口向前覆盖的范围,unit="none"适配数值型index(非时间类型)。
  3. 加权计算:
    • pl.max("index")获取当前窗口的结束index(即当前行的index)
    • decay ** (pl.max("index") - pl.col("index"))计算每个历史行的指数权重
    • 分子为窗口内所有x与对应权重的乘积和,分母为所有权重的和,两者相除得到最终加权结果。
  4. 结果整理:选择需要的列并排序,保证输出顺序与期望一致。

输出验证

运行代码后输出结果与期望完全匹配:

shape: (8, 3)
┌─────┬───────┬───────┐
│ id  ┆ index ┆ x     │
│ --- ┆ ---   ┆ ---   │
│ i64 ┆ i64   ┆ f64   │
├─────┼───────┼───────┤
│ 1   ┆ 7     ┆ 1.0   │
│ 1   ┆ 8     ┆ 1.556 │
│ 5   ┆ 7     ┆ 1.0   │
│ 5   ┆ 8     ┆ 2.111 │
│ 5   ┆ 9     ┆ 2.475 │
│ 7   ┆ 5     ┆ 1.0   │
│ 7   ┆ 7     ┆ 1.0   │
│ 7   ┆ 9     ┆ 3.439 │
└─────┴───────┴───────┘

优势说明

  • 向量化计算:完全基于Polars内置的向量化操作,处理百万级以上数据时效率远高于Python循环。
  • 可配置性:窗口大小和衰减系数可直接通过参数调整,无需修改核心逻辑。
  • 自动过滤:dynamic窗口自动过滤超出范围的历史行,无需手动编写过滤条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:43:09