分组 totals/subtotals

groupby with totals/subtotals

假设我有以下数据框

Strategy    AssetClass    Symbol         Value    Indicator
Strat1      OPT           OPT_ABC1       50       -0.3
Strat1      OPT           OPT_ABC2       50       1.5
Strat1      STK           STK_ABC        50       2.7
Strat2      STK           STK_XYZ        70       -3.8
Strat3      OPT           OPT_MNO        25       10

我想制作以下内容:

Strategy    AssetClass    Symbol    Value    Indicator
Strat1                                       3.9
            OPT                              1.2
                          OPT_ABC1  50       -0.3
                          OPT_ABC2  50       1.5
            STK                              2.7
                          STK_ABC   50       2.7
Strat2                                       -3.8
            STK                              -3.8
                          STK_XYZ   70       -3.8
Strat3                                       10
            OPT                              10
                          OPT_MNO   25       10

因此,我们的想法是按照每个策略的总计重新排列数据,然后是资产类别,然后是每个交易品种。 “值”列在符号级别可用,而“指标”列是子组的总和。

我考虑过使用 pd.pivot_table,但它似乎无法生成我正在寻找的 totals/sub_totals。我想我应该 use/loop 在 pd.groupby 策略上,然后在 Strategy/AssetClass 上循环另一个 groupby,然后在 Strategy/AssetClass/Symbol

上循环一个 groupby

df 是上面的数据框,我这样做了:

container = []
for label, _df in df.groupby(['Strategy', 'AssetClass', 'Symbol']):
    _df.loc[f'{label}'] = _df[['Indicator']].sum()
    container.append(_df)

df_res = pd.concat(container)
print(df_res.fillna(''))

我的问题是小计是插入到对应行之后,标签作为索引。此外,我想不出添加其他 lopps(即小计)easy/pythonic 的方法

您可以按不同的列进行聚合,因此为了提高性能,最好不要使用嵌套 groupby.apply,而是使用多重聚合,最后按 concat, change order of columns by DataFrame.reindex 将它们连接在一起,最后对前 2 列进行排序:

df1 = df.groupby(['Strategy', 'AssetClass', 'Symbol'], as_index=False).sum()

df2 = (df1.groupby(['Strategy', 'AssetClass'], as_index=False)['Indicator'].sum()
          .assign(Symbol = ''))

df3 = (df1.groupby('Strategy', as_index=False)['Indicator'].sum()
          .assign(AssetClass = ''))

df = (pd.concat([df3, df2, df1])
        .reindex(df.columns, axis=1)
        .fillna('')
        .sort_values(['Strategy','AssetClass'], ignore_index=True))
print (df)
   Strategy AssetClass    Symbol Value  Indicator
0    Strat1                                   3.9
1    Strat1        OPT                        1.2
2    Strat1        OPT  OPT_ABC1  50.0       -0.3
3    Strat1        OPT  OPT_ABC2  50.0        1.5
4    Strat1        STK                        2.7
5    Strat1        STK   STK_ABC  50.0        2.7
6    Strat2                                  -3.8
7    Strat2        STK                       -3.8
8    Strat2        STK   STK_XYZ  70.0       -3.8
9    Strat3                                  10.0
10   Strat3        OPT                       10.0
11   Strat3        OPT   OPT_MNO  25.0       10.0