如何在Polars中为原DataFrame添加滚动KPI?无索引关联问题
在Polars中保留原始列添加分组滚动KPI的正确姿势
你遇到的核心问题是误用了Polars的group_by().agg()方式做滚动计算——这种聚合操作会把每个组的结果打包成列表,没法和原DataFrame的行一一对应。Polars提供了更简洁的窗口函数方案,结合over子句就能直接在原DataFrame上添加滚动指标,完全不需要额外的合并操作。
先看你的Pandas实现参考
假设你的Pandas代码是这样的:
import pandas as pd # 测试数据 df_pd = pd.DataFrame({ "group_id": ["A", "A", "A", "B", "B", "B"], "value": [1, 3, 5, 2, 4, 6], "other_col": ["x", "y", "z", "p", "q", "r"] }) # Pandas 分组滚动中位数 + 合并回原表 rolling_median_pd = df_pd.groupby("group_id")["value"].rolling(window=2, min_periods=1).median().reset_index() df_pd = df_pd.merge(rolling_median_pd.rename(columns={"value": "rolling_median"}), on=["group_id", "level_1"])
Polars的正确实现
Polars的窗口函数可以直接通过over指定分组,然后对目标列应用滚动计算,自动为每一行生成对应值,同时保留所有原始列:
import polars as pl # 测试数据 df_pl = pl.DataFrame({ "group_id": ["A", "A", "A", "B", "B", "B"], "value": [1, 3, 5, 2, 4, 6], "other_col": ["x", "y", "z", "p", "q", "r"] }) # 直接添加分组滚动中位数列,保留所有原始列 df_pl = df_pl.with_columns( pl.col("value") .rolling_median(window_size=2, min_periods=1) .over("group_id") .alias("rolling_median") ) print(df_pl)
输出结果:
shape: (6, 4) ┌──────────┬───────┬───────────┬────────────────┐ │ group_id ┆ value ┆ other_col ┆ rolling_median │ │ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ str ┆ f64 │ ╞══════════╪═══════╪═══════════╪════════════════╡ │ A ┆ 1 ┆ x ┆ 1.0 │ │ A ┆ 3 ┆ y ┆ 2.0 │ │ A ┆ 5 ┆ z ┆ 4.0 │ │ B ┆ 2 ┆ p ┆ 2.0 │ │ B ┆ 4 ┆ q ┆ 3.0 │ │ B ┆ 6 ┆ r ┆ 5.0 │ └──────────┴───────┴───────────┴────────────────┘
为什么之前的尝试失败?
你之前用group_by().agg()的方式,会把每个组的滚动结果聚合为一个列表(比如组A的滚动中位数是[1.0,2.0,4.0]),这种结构和原DataFrame的行级数据无法直接关联。而over子句是Polars的窗口分组机制,它会为每一行计算其所在分组内的滚动值,结果维度和原DataFrame完全一致,自然不需要额外的合并操作。
扩展:其他滚动KPI的实现
如果需要其他滚动指标(比如滚动均值、滚动最大值),只需要替换对应的滚动函数即可,比如:
df_pl = df_pl.with_columns( pl.col("value").rolling_mean(window_size=2, min_periods=1).over("group_id").alias("rolling_mean"), pl.col("value").rolling_max(window_size=2, min_periods=1).over("group_id").alias("rolling_max") )
内容的提问来源于stack exchange,提问作者r ram
相关产品推荐
相关产品推荐

