有没有办法对分组进行加权滚动求和?

2 投票
1 回答
770 浏览
提问于 2025-04-18 07:45

我想对一个数据表(DataFrame)应用加权求和。在过去,我使用过

for sec_id, sec_df_unidx in grouped:
    if sec_df_unidx.shape[0] > 3:
        pd.rolling_sum(sec_df[added_cols], 4)

我想对求和应用加权平均,其中最新的值乘以0.6,第二个值乘以0.2,第三个和第四个值各乘以0.1。

数据表(DF):

DATE    ID  VALUE
2012-12-31  A   100
2013-03-31  A   120
2013-06-30  A   140
2013-09-30  A   160
2013-12-31  A   180
2013-03-31  B   0
2013-06-30  B   5
2013-09-30  B   1
2013-12-31  B   3
2012-12-31  C   45
2013-03-31  C   46
2013-06-30  C   42
2013-09-30  C   30
2013-12-31  C   11
2012-12-31  D   18
2013-03-31  D   9
2013-06-30  D   13
2013-09-30  D   5
2013-12-31  D   11
2012-12-31  E   0

添加新列后的数据表(DF):

DATE    ID  VALUE   Weight_Sum
2012-12-31  A   100 NaN
2013-03-31  A   120 NaN
2013-06-30  A   140 NaN
2013-09-30  A   160 146
2013-12-31  A   180 166
2013-03-31  B   0   NaN
2013-06-30  B   5   NaN
2013-09-30  B   1   NaN
2013-12-31  B   3   2.5
2012-12-31  C   45  NaN
2013-03-31  C   46  NaN
2013-06-30  C   42  NaN
2013-09-30  C   30  35.5
2013-12-31  C   11  21.4
2012-12-31  D   18  NaN
2013-03-31  D   9   NaN
2013-06-30  D   13  NaN
2013-09-30  D   5   8.3
2013-12-31  D   11  9.8
2012-12-31  E   0   NaN

我可以用滚动应用(rolling_apply)或滚动求和(rolling_sum)来实现吗?还是说我必须使用循环(for loop)?

谢谢。

1 个回答

2

我觉得你可以通过一个叫做 rolling_apply 的功能,在正常的 groupby/apply 中使用它来实现。所以可以像下面这样做:

def roll_wsum(g,w,p):
    rsum = pd.rolling_apply(g.values,p,lambda x: np.dot(w,x),min_periods=p)
    return pd.Series(rsum,index=g.index)

weights = np.array([0.1,0.1,0.2,0.6])
df['wsum'] = df.groupby('ID')['VALUE'].apply(roll_wsum,weights,4)
print df

输出结果:

         DATE ID  VALUE   wsum
0  2012-12-31  A    100    NaN
1  2013-03-31  A    120    NaN
2  2013-06-30  A    140    NaN
3  2013-09-30  A    160  146.0
4  2013-12-31  A    180  166.0
5  2013-03-31  B      0    NaN
6  2013-06-30  B      5    NaN
7  2013-09-30  B      1    NaN
8  2013-12-31  B      3    2.5
9  2012-12-31  C     45    NaN
10 2013-03-31  C     46    NaN
11 2013-06-30  C     42    NaN
12 2013-09-30  C     30   35.5
13 2013-12-31  C     11   21.4
14 2012-12-31  D     18    NaN
15 2013-03-31  D      9    NaN
16 2013-06-30  D     13    NaN
17 2013-09-30  D      5    8.3
18 2013-12-31  D     11    9.8
19 2012-12-31  E      0    NaN

这里,我是先按照 'ID' 来对数据进行分组,然后把每组的 'VALUE' 列传给我的 roll_wsum 函数(同时还传入加权和的权重和周期)。这个 roll_wsum 函数会调用 rolling_apply,并给它一个简单的 lambda 函数:就是 'VALUE' 和权重的点积。此外,这里设置 min_periods=4 是很重要的,因为我们需要确保权重和 df['VALUE'].values 的长度是一样的。

由于我使用点积来计算加权和,这可能不会按照你想要的方式处理缺失值。所以,比如说,你可能更喜欢下面的方式(虽然对于示例数据来说没有区别):

def roll_wsum(g,w,p):
    rsum = pd.rolling_apply(g.values,p,lambda x: np.nansum(w*x),min_periods=p)
    return pd.Series(rsum,index=g.index)

weights = np.array([0.1,0.1,0.2,0.6])
df['wsum'] = df.groupby('ID')['VALUE'].apply(roll_wsum,weights,4)

撰写回答