Pandas 基于多列值的Groupby

Pandas Groupby Based on Values in Multiple Columns

我有一个 dataframe,我正在尝试使用 pandas.groupby 来获得累计和。我分组依据的值显示在两个不同的列中,我无法让分组依据正常工作。我的起始 dataframe 是:

df = pd.DataFrame({'col_A': ['red', 'red', 'blue', 'red'], 'col_B': ['blue', 'red', 'blue', 'red'], 'col_A_qty': [1, 1, 1, 1], 'col_B_qty': [1, 1, 1, 1]})

col_A   col_B   col_A_qty   col_B_qty
red      blue      1           1
red      red       1           1
blue    blue       1           1
red      red       1           1

我想要得到的结果是:

col_A   col_B   col_A_qty   col_B_qty   red_cumsum  blue_cumsum
red     blue       1            1           1           1
red     red        1            1           3           1
blue    blue       1            1           3           3
red     red        1            1           5           3

我试过:

df.groupby(['col_A', 'col_B'])['col_A_qty'].cumsum()

但是这个分组基于 col_Acol_B 的组合。如何使用 pandas.groupby 来计算红色和蓝色的累积和,无论它是在 col_A 还是 col_B

尝试两个pivot

out = pd.pivot(df,columns='col_A',values='col_A_qty').fillna(0).cumsum().add(pd.pivot(df,columns='col_B',values='col_B_qty').fillna(0).cumsum(),fill_value=0)
Out[404]: 
col_A  blue  red
0       1.0  1.0
1       1.0  3.0
2       3.0  3.0
3       3.0  5.0
df = df.join(out)

一个简单的方法是将每个cumsum列定义为两个Series.cumsum,如下:

df['red_cumsum'] = df['col_A'].eq('red').cumsum() + df['col_B'].eq('red').cumsum()
df['blue_cumsum'] = df['col_A'].eq('blue').cumsum() + df['col_B'].eq('blue').cumsum()

在每一列 col_Acol_B 中,检查值是否等于 'red' / 'blue'(结果为布尔序列)。然后,我们对这些结果布尔系列使用 Series.cumsum 来获得累积计数。在这个用例中你真的不需要使用 pandas.groupby

如果在col_Acol_B中有多个item,也可以遍历unique item列表,如下:

for item in np.unique(df[['col_A', 'col_B']]):
    df[f'{item}_cumsum'] = df['col_A'].eq(item).cumsum() + df['col_B'].eq(item).cumsum()

结果:

print(df)

  col_A col_B  col_A_qty  col_B_qty  red_cumsum  blue_cumsum
0   red  blue          1          1           1            1
1   red   red          1          1           3            1
2  blue  blue          1          1           3            3
3   red   red          1          1           5            3