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

如何在Polars中按列分组计算带最小周期的高效滚动均值?

Polars实现分组滚动均值(带最小周期限制)

需求说明

现有一份每日每小时的价格数据集,需按Group和Hour分组,计算Price字段过去30天的滚动均值(即同组同时段的过去30条数据求平均)。当前使用rolling方法无法指定min_periods参数,而直接用rolling_mean效率偏低,需最优实现方案。

示例数据集

import polars as pl

df = pl.from_repr("""
┌─────────┬─────────────────────┬─────────┬──────┐
│ Group   ┆ Time                ┆ Price   ┆ Hour │
│ ---     ┆ ---                 ┆ ---     ┆ ---  │
│ str     ┆ datetime[ns]        ┆ f64     ┆ i8   │
╞═════════╪═════════════════════╪═════════╪══════╡
│ Group1  ┆ 2021-01-03 00:00:00 ┆ 15.6328 ┆ 0    │
│ Group1  ┆ 2021-01-03 05:00:00 ┆ 17.1562 ┆ 5    │
│ Group1  ┆ 2021-01-03 08:00:00 ┆ 13.9062 ┆ 8    │
│ Group2  ┆ 2021-01-03 10:00:00 ┆ 18.5625 ┆ 10   │
│ Group2  ┆ 2021-01-03 00:00:00 ┆ 28.375  ┆ 0    │
│ Group2  ┆ 2021-01-03 13:00:00 ┆ 15.4219 ┆ 13   │
└─────────┴─────────────────────┴─────────┴──────┘
""")

局限的现有实现

当前代码无法指定最小周期限制:

df.rolling('Time', group_by=['Group', 'Hour'], period='30d').agg(
    pl.col('Price').mean().alias('PriceAvg')
)

最优实现方案

方案一:滚动聚合结合条件过滤(灵活可控)

先通过滚动聚合统计数据量与均值,再通过条件判断过滤掉数据量不足的记录,实现min_periods的效果:

min_periods = 5  # 根据需求设置最小需要的样本数量

# 必须先按时间排序,滚动计算依赖有序序列
result = df.sort('Time').rolling(
    'Time',
    group_by=['Group', 'Hour'],
    period='30d'
).agg(
    pl.col('Price').count().alias('sample_count'),
    pl.col('Price').mean().alias('PriceAvg')
).with_columns(
    # 仅当样本数达标时保留均值,否则设为None
    PriceAvg=pl.when(pl.col('sample_count') >= min_periods)
               .then(pl.col('PriceAvg'))
               .otherwise(None)
).drop('sample_count')

print(result)

方案二:滚动求和+计数手动计算均值(大数据量更高效)

对于超大规模数据集,手动计算滚动求和与计数再推导均值,性能优于直接调用rolling_mean:

min_periods = 5

result = df.sort('Time').with_columns(
    # 计算滚动窗口内的价格总和与样本数
    rolling_sum=pl.col('Price').rolling_sum(
        window_size='30d',
        by='Time',
        group_by=['Group', 'Hour']
    ),
    rolling_count=pl.col('Price').rolling_count(
        window_size='30d',
        by='Time',
        group_by=['Group', 'Hour']
    )
).with_columns(
    # 样本数达标时计算均值,否则设为None
    PriceAvg=pl.when(pl.col('rolling_count') >= min_periods)
               .then(pl.col('rolling_sum') / pl.col('rolling_count'))
               .otherwise(None)
).drop(['rolling_sum', 'rolling_count'])

print(result)

关键注意事项

  • 所有滚动计算必须先对Time列排序,否则结果会出错。
  • min_periods可根据业务需求调整,比如设为30时,只有当窗口内有至少30条同组同时段数据时才计算均值。
  • 若使用Polars 0.19及以上版本,方案一的性能已足够优秀;大数据量场景优先选择方案二。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:24:58