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

Polars滚动计算window_size参数差异及月窗口均值计算方案

Polars滚动窗口参数解析与金融时序场景解决方案

一、timedelta(days=2)与"2d"的核心区别

在Polars的滚动窗口计算中,这两种参数都属于时间类窗口,但计算逻辑存在本质差异:

  • "2d":日历周期窗口
    基于日历单位划分窗口范围,以当前日期的日历边界为基准。比如当前日期是2023-01-09(周一),"2d"窗口的范围是2023-01-07至2023-01-09(日历上的2天跨度),即使中间的周六、周日没有数据,窗口也会包含该时间范围内所有存在的观测值(比如仅2023-01-06的周五数据,因为07、08是周末无数据)。
    这类参数支持的单位包括:d(天)、h(小时)、m(分钟)、mo(月)等日历单位。

  • timedelta(days=2):固定时间差窗口
    基于精确的时间长度划分窗口,是绝对的时间跨度(比如48小时)。如果当前时间是2023-01-09 12:00:00,窗口范围是2023-01-07 12:00:00至当前时间;若数据仅保留天级时间戳(如00:00:00),则和"2d"效果一致,但在小时级及更细粒度数据中,两者的窗口范围会出现差异。

注:"2i"属于计数窗口,和前两者完全不同——它固定取最近的2条观测值,不管时间间隔多久,适合需要固定样本量的场景(比如最近21个交易日的均值)。

二、实现自然月回溯的滚动均值计算

要实现「当前日期回溯至上个月同一天(或最近交易日)」的滚动均值,不能直接用"1m"("1m"默认是当月内的日历周期,仅包含当月数据),需要通过自定义窗口范围来实现:

代码实现(基于测试DataFrame)

import polars as pl
import datetime as dt

# 加载测试数据(已确保date列排序)
df = pl.read_csv(b"""
date,open,high,low,close,volume,symbol
2023-01-03T00:00:00.000000000,129.39,130.01,123.32,124.22,112117500,AAPL
2023-01-04T00:00:00.000000000,126.02,127.78,124.23,125.5,89113600,AAPL
2023-01-05T00:00:00.000000000,126.26,126.9,123.91,124.17,80962700,AAPL
2023-01-06T00:00:00.000000000,125.15,129.4,124.04,128.74,87754700,AAPL
2023-01-09T00:00:00.000000000,129.58,132.5,129.0,129.26,70790800,AAPL
2023-01-10T00:00:00.000000000,129.37,130.36,127.25,129.84,63896200,AAPL
2023-01-11T00:00:00.000000000,130.35,132.6,129.57,132.58,69458900,AAPL
2023-01-12T00:00:00.000000000,132.97,133.34,130.54,132.5,71379600,AAPL
2023-01-13T00:00:00.000000000,131.13,134.0,130.76,133.84,57809700,AAPL
2023-01-17T00:00:00.000000000,133.91,136.35,133.21,135.01,63646600,AAPL
2023-01-18T00:00:00.000000000,135.89,137.66,134.11,134.29,69672800,AAPL
2023-01-19T00:00:00.000000000,133.16,135.32,132.86,134.35,58280400,AAPL
2023-01-20T00:00:00.000000000,134.36,137.08,133.3,136.93,80223600,AAPL
2023-01-23T00:00:00.000000000,137.18,142.34,136.96,140.15,81760300,AAPL
2023-01-24T00:00:00.000000000,139.35,142.18,139.34,141.56,66435100,AAPL
2023-01-25T00:00:00.000000000,139.93,141.46,137.86,140.89,65799300,AAPL
2023-01-26T00:00:00.000000000,142.19,143.27,140.93,142.98,54105100,AAPL
2023-01-27T00:00:00.000000000,142.18,146.23,142.1,144.93,70555800,AAPL
2023-01-30T00:00:00.000000000,143.97,144.56,141.87,142.02,64015300,AAPL
2023-01-31T00:00:00.000000000,141.73,143.35,141.31,143.31,65874500,AAPL
2023-02-01T00:00:00.000000000,142.99,145.61,140.36,144.44,77663600,AAPL
2023-02-02T00:00:00.000000000,147.88,150.15,147.16,149.79,118339000,AAPL
2023-02-03T00:00:00.000000000,147.02,156.31,146.82,153.45,154357300,AAPL
2023-02-06T00:00:00.000000000,151.53,152.05,149.75,150.69,69858300,AAPL
2023-02-07T00:00:00.000000000,149.61,154.17,149.61,153.59,83322600,AAPL
""".strip(), try_parse_dates=True)

# 生成回溯起始日(当前日期往前推1个月)
df = df.with_columns(
    pl.col("date").dt.offset_by("-1mo").alias("start_date"),
    pl.col("date").map_batches(lambda s: pl.Series(s.to_list())).alias("all_dates")
)

# 为每个start_date匹配最近的存在的交易日(若start_date无数据则取前一天)
df = df.with_columns(
    pl.struct(["start_date", "all_dates"])
    .map_elements(
        lambda x: max(d for d in x["all_dates"] if d <= x["start_date"]),
        return_dtype=pl.Date
    )
    .alias("valid_start_date")
)

# 计算指定区间内的close滚动均值
result = df.set_sorted("date").with_columns(
    pl.col("close")
    .rolling(
        index_column="date",
        start=pl.col("valid_start_date"),
        end=pl.col("date"),
        closed="both"
    )
    .mean()
    .alias("monthly_rolling_mean")
)

# 查看2023-02-07的结果(包含2023-01-06及之后的所有有效数据)
print(result.filter(pl.col("date") == "2023-02-07"))

代码说明

  • dt.offset_by("-1mo"):生成当前日期往前推1个月的基准日;
  • 自定义map_elements逻辑:匹配基准日之前最近的存在的交易日,解决节假日/周末无数据的问题;
  • rolling(start=..., end=...):指定每个行的自定义窗口范围,确保包含回溯期内的所有有效数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 08:10:53