如何在 df.groupby 之后将数据框列值作为窗口大小传递?

Posted

技术标签:

【中文标题】如何在 df.groupby 之后将数据框列值作为窗口大小传递?【英文标题】:How to pass dataframe column value as window size after df.groupby? 【发布时间】:2020-04-16 13:26:45 【问题描述】:
    A   B   C
0   1   10  2
1   1   15  2
2   1   14  2
3   2   11  4
4   2   12  4
5   2   13  4
6   2   16  4
7   1   18  2

这是我的示例数据框。

    我想在“A”列上应用 groupby,

    根据“C”列的值在“B”列上应用滚动总和,这意味着当 A 为 1 时,窗口大小应为 2,而不是 NaN,我想要剩余值的总和,而不考虑窗口大小.

目前我的输出是:

A   
1  0    25.0
   1    29.0
   2    32.0
   7     NaN
2  3    23.0
   4    25.0
   5    29.0
   6     NaN

以上代码: df['B'].groupby(df['A']).rolling(df['C'][0]).sum().shift(-1)

当 C = 4 时,我希望滚动窗口为 4 并且不希望 NaN

所需的输出应如下所示:

    A   B   C   Rolling_sum
0   1   10  2   25
1   1   15  2   29
2   1   14  2   32
7   1   18  2   18
3   2   11  4   52
4   2   12  4   41
5   2   13  4   29
6   2   16  4   16

【问题讨论】:

【参考方案1】: 我们可以使用DataFrame.groupby 根据C列的值使用groupby.rolling。 这里我们使用df[::-1]来反转索引的顺序,得到合适的解。 最后我们使用pd.concat 加入为C 的每个值获得的序列。
df = df.sort_values('A')
df['Rolling_sum']= pd.concat([group[::-1].groupby(df['A'])
                                         .rolling(i,min_periods = 1)
                                         .B.sum()
                                         .reset_index(level = 'A',drop =True) 
                            for i, group in df.groupby('C')])
print(df)

输出

   A   B  C  Rolling_sum
0  1  10  2         25.0
1  1  15  2         29.0
2  1  14  2         32.0
7  1  18  2         18.0
3  2  11  4         52.0
4  2  12  4         41.0
5  2  13  4         29.0
6  2  16  4         16.0

【讨论】:

【参考方案2】:

因为您想逐列传递动态窗口 C 使用 lambda 函数和 iloc[::-1] 的更改顺序:

df = df.sort_values('A')
df['Rolling_sum'] = (df.iloc[::-1].groupby('A')
                       .apply(lambda x: x.B.rolling(x.C.iat[0], min_periods=0).sum())
                       .reset_index(level=0, drop=True))
print (df)
   A   B  C  Rolling_sum
0  1  10  2         25.0
1  1  15  2         29.0
2  1  14  2         32.0
7  1  18  2         18.0
3  2  11  4         52.0
4  2  12  4         41.0
5  2  13  4         29.0
6  2  16  4         16.0

如果性能很重要(取决于组的数量、组的大小、真实数据中的最佳测试),则大步前进的解决方案:

def rolling_window(a, window):
    a = np.concatenate([[0] * (window - 1), a])
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides).sum(axis=1)

df = df.sort_values('A')
df['Rolling_sum']  = (df.iloc[::-1].groupby('A')
                        .apply(lambda x: pd.Series(rolling_window(x.B, x.C.iat[0]), 
                                                   index=x.index))
                        .reset_index(level=0, drop=True))
print (df) 
   A   B  C  Rolling_sum
0  1  10  2           25
1  1  15  2           29
2  1  14  2           32
7  1  18  2           18
3  2  11  4           52
4  2  12  4           41
5  2  13  4           29
6  2  16  4           16

【讨论】:

这真的很有帮助!但是如果我在 C 中改变了值怎么办?我可以将不同的值传递给窗口大小参数吗?@ jezrael

以上是关于如何在 df.groupby 之后将数据框列值作为窗口大小传递?的主要内容,如果未能解决你的问题,请参考以下文章

我如何将两个数据框列值作为键传递给2键到一个值字典,然后将结果传递到另一列?

Python Pandas:如何将数据框列值设置为 X 轴标签

df.groupby()方法讲解

(Python)如何修复数据框列值中的数值表示错误

如何在循环中读取数据框列值并检查每列的数据类型

将附加信息(数据)附加到数据框列值