Polars:如何规避「聚合中不允许窗口表达式」错误及原理解析
问题解答
1. 保留分步写法的错误修复方案
你的核心问题是把**分组聚合(group_by.agg)和窗口函数(.over())**的用法混在了一起,导致逻辑冲突。要保留分步链式的写法,直接在with_columns里给每个指标计算加上.over("company")即可,无需用group_by.agg——因为窗口函数本身就支持按指定字段分组逐行计算,完全符合你要的分步可读性:
import polars as pl # 假设你的原始数据包含 company、date、close 字段 df = ( df # 先按公司+日期排序,保证时间序列计算的正确性 .sort(["company", "date"]) .with_columns( # 按company分组计算收益率 收益率=pl.col("close").pct_change().over("company"), # 按company分组计算涨跌额 涨跌额=pl.col("close").diff().over("company"), # 按company分组计算5日移动平均 移动平均=pl.col("close").rolling_mean(window_size=5).over("company"), # 按company分组计算14日RSI RSI=pl.col("close").rsi(window_size=14).over("company") ) )
如果你的需求是每个公司只返回一行聚合结果(而非逐行保留原始数据),那就要放弃窗口函数,改用group_by.agg,但此时要使用聚合逻辑的函数(比如取最后值、均值等),而不是窗口类的计算:
df_agg = ( df .sort(["company", "date"]) .group_by("company") .agg( 最新收益率=pl.col("close").pct_change().last(), 最新移动平均=pl.col("close").rolling_mean(window_size=5).last(), 最新RSI=pl.col("close").rsi(window_size=14).last() ) )
2. 为什么聚合操作里不能用窗口表达式?
用通俗的话讲,这俩是完全相反的操作逻辑:
- 聚合操作(
group_by.agg)是「把一个分组里的多行数据“压缩”成一行结果」——比如把一个公司的所有交易日数据,变成一行该公司的汇总指标。 - 窗口函数(
.over())是「给每一行数据“附加”一个基于其所在分组的计算结果」——比如给每个交易日的数据,加上该公司的5日均线,最终行数和原始数据一样多。
如果在聚合里用窗口表达式,就相当于你一边要把一个班级的所有学生成绩“压缩”成一行班级平均分,一边又要给每个学生都算一遍班级平均分并保留所有行,这俩需求是矛盾的。Polars无法理解你到底要“缩成一行”还是“保留所有行”,所以直接报错禁止这种混用。
内容的提问来源于stack exchange,提问作者FredMaster
相关产品推荐
相关产品推荐

