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

Polars分组滚动峰度实现方案咨询与性能优化探讨

Polars 分组滚动峰度实现与相关问题解答

背景

Polars 目前没有内置的 rolling_kurtosis 函数,2022年提交的相关需求工单已停滞。基于现有API实现了两种分组滚动峰度计算方案:

  • 方案1:Expr.rolling_map + Expr.over,性能极差(耗时约12分钟)
  • 方案2:DataFrame.rolling(带分组).agg + Expr.kurt,耗时约2.47秒,但需手动处理索引列与min_periods

同时对比了内置滚动函数性能:rolling_std 耗时33.2ms;rolling_skew 比Pandas慢且无min_periods参数。


问题1:两种实现是否合理?性能瓶颈在哪?分组滚动最佳实践有哪些?

  1. 方案1的合理性与瓶颈:
    完全不合理,性能差是必然结果。rolling_map 本质是逐窗口调用Python自定义函数,属于Python层循环,再加上over分组逻辑,相当于每个分组都要遍历所有窗口,双重Python层开销直接拉低性能,完全没必要用这种方式实现内置聚合函数能搞定的逻辑。

  2. 方案2的合理性:
    这个方案是合理的,属于Polars推荐的向量化操作路径。DataFrame.rolling(by=...) 是原生支持分组滚动的API,配合内置的Expr.kurt聚合,完全走Rust层的向量化计算,所以性能远优于方案1。手动处理索引列和min_periods是当前API的局限性,属于可接受的临时解决方案。

  3. 分组滚动最佳实践:

    • 优先使用 DataFrame.rolling(by=...) 原生分组滚动API,避免用over结合窗口函数(除非是滚动窗口无法覆盖的分组逻辑)
    • 尽量用内置聚合函数(如kurt/std/mean),绝对避免用rolling_map这类Python UDF处理内置函数能覆盖的逻辑
    • 滚动窗口依赖有序数据,提前对分组键+排序键做排序(比如df.sort(["group", "idx"]))
    • 处理min_periods:可以通过窗口内计数过滤,比如agg(pl.col("value").kurt().filter(pl.col("value").count() >= min_periods))

问题2:Polars能否无需手动创建索引列实现按行数的滚动窗口?是否需提交新需求?

目前Polars的rolling API默认是基于时间/数值索引的滚动,按行数的窗口必须指定index_col。不过可以用with_row_index快速生成索引列,代码示例:

df = df.with_row_index("row_idx").rolling(
    index_col="row_idx",
    window_size=5,
    by="group"
).agg(pl.col("value").kurt())

这个操作成本极低,不算繁琐。如果确实希望原生支持无索引的行偏移滚动,可以提交新需求:在GitHub Issues里说明你的使用场景(比如不需要时间/数值索引,纯按行位置滚动),并补充现有方案的不便之处。不过社区会评估需求的普遍性,建议先确认是否有其他用户也有类似需求。

问题3:如何推动停滞的rolling_kurtosis功能需求落地?

  • 唤醒旧工单:找到2022年的那个需求工单,留言补充你的使用场景、性能测试数据(比如你自己实现的方案耗时,说明内置函数的性能提升空间),让维护者知道这个功能仍有用户需求。
  • 提交PR:如果有Rust基础,可以参考Polars现有滚动函数(如rolling_skew)的实现,自己编写rolling_kurtosis的Rust代码并提交PR,这是推动功能落地最快的方式。
  • 社区造势:在Polars的Discord社区或GitHub讨论区发起话题,收集其他用户对rolling_kurtosis的需求,形成共识后再反馈给维护者。
  • 赏金激励:如果自己没时间写PR,可以通过社区赏金平台发布赏金,吸引开发者帮忙实现。

问题4:是否支持在rolling+over场景中使用链式Polars表达式?

首先要明确:rolling和over的组合有两种形式,对应的支持情况不同:

  1. Expr.over("group").rolling_map(...):这种场景下rolling_map是Python UDF,无法使用链式Polars表达式,而且性能极差,不推荐。
  2. DataFrame.rolling(by="group").agg(...):这种原生分组滚动的场景下,agg内部完全支持链式Polars表达式。比如自定义实现标准差:
df.rolling(by="group", window_size=5).agg(
    pl.col("value").std().alias("std"),
    # 链式表达式示例:计算均值的平方
    pl.col("value").mean().pow(2).alias("mean_squared")
)

只要是Polars支持的列级表达式,都可以在agg里链式调用,完全走Rust向量化计算,性能有保障。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:53:16