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

Pandas分组后用expanding应用自定义函数报KeyError的解决问询

解决Pandas Groupby Expanding Apply自定义函数的KeyError问题

你遇到的KeyError: 'x1'本质是因为**expanding().apply()的默认行为和普通groupby.apply()不同**:即使设置了raw=False,它传递给自定义函数的是单列Series,而不是你预期的DataFrame子集,所以函数里访问_df['x1']自然找不到对应的键。

问题原因拆解

当你执行df.groupby('group').expanding().apply(foo, raw=False)时,Pandas会对每个expanding窗口的每一列单独处理,把单列的Series传给foo,而不是整个窗口的DataFrame。这就导致你的函数试图访问Series的'x1'键时触发KeyError。

正确实现方式(兼容复杂自定义函数)

因为你提到实际函数逻辑复杂无法拆分,最稳妥的办法是先通过groupby.apply()拿到完整的组DataFrame,再在组内手动实现expanding窗口的逻辑,确保传递给foo的是真正的DataFrame子集:

import pandas as pd

# 初始化你的DataFrame
df = pd.DataFrame.from_dict(
    {
        'group': ['A','A','A','B','B','B'],
        'time': [1,2,3,1,2,3],
        'x1': [10,40,30,100,200,300],
        'x2': [1,0,1,2,0,3]
    }
).sort_values('time')

# 你的自定义函数(示例)
def foo(_df):
    return _df['x1'].max() * _df['x2'].iloc[-1]

# 定义组内的expanding处理逻辑
def process_group(group):
    # 遍历每个行的位置,生成截至当前行的expanding窗口
    expanding_results = []
    for idx in range(1, len(group) + 1):
        # 截取从第一行到当前行的窗口
        window_df = group.iloc[:idx]
        expanding_results.append(foo(window_df))
    # 将结果赋值给组内的新列
    group['foo_result'] = expanding_results
    return group

# 应用到分组数据,group_keys=False避免额外的分组索引
df = df.groupby('group', group_keys=False).apply(process_group)

print(df)

运行结果

执行后会得到符合预期的输出(注:你的示例中A组第二行x2值为0,所以结果是40*0=0,和你写的期望结果80略有出入,应该是笔误,但代码逻辑完全符合需求):

group  time   x1  x2  foo_result
0     A     1   10   1          10
3     B     1  100   2         200
1     A     2   40   0           0
4     B     2  200   0           0
2     A     3   30   1          40
5     B     3  300   3         900

为什么这个方法有效?

通过groupby('group').apply(process_group),我们可以拿到每个分组的完整DataFrame,然后手动遍历每个行的位置,截取截至当前行的窗口(完全模拟expanding的行为),再把这个窗口DataFrame传给你的自定义函数foo,这样就不会出现KeyError,同时完全兼容任何复杂的函数逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 10:22:34