Pandas - 将总行添加到每个子组作为第一行

Geo*_*ere 1 python group-by pandas

我知道这个问题在 StackOverflow 上已经被多次提及,我认为完成这项任务并不简单。这个和许多其他答案:Adding Total row to pandas DataFrame groupby

我的数据示例(实际上有 25 列,但它们很相似,只是数字):

owner   player  val1    val1    val3
A       x       5.60    3.18    0.76
A       y       12.08   15.95   -0.24
A       z       0.03    0.05    -0.41
B       x       0.02    0.01    2.06
B       z       2.36    2.37    0.00
C       x       0.16    0.15    0.05
C       y       0.72    0.75    -0.04
D       x       0.33    0.56    -0.41
Run Code Online (Sandbox Code Playgroud)

我的预期输出如下,其中计算每个所有者的总数并将其放置为子组中的第一行。

owner   player  val1    val1    val3
A      total    17.71   19.18   0.11
A      x        5.60    3.18    0.76
A      y        12.08   15.95   -0.24
A      z        0.03    0.05    -0.41
B      total    2.38    2.38    2.05
B      x        0.02    0.01    2.06
B      z        2.36    2.37    0.00
C      total    0.88    0.90    0.01
C      x        0.16    0.15    0.05
C      y        0.72    0.75    -0.04
D      total    0.33    0.56    -0.41
D      x        0.33    0.56    -0.41
Run Code Online (Sandbox Code Playgroud)

我尝试使用我在 StackOverflow 上找到的东西,它看起来像我正在寻找的东西,但我无法使它完全正确。

def lambda_t(x):
    df = x.sort_values(['owner']).drop(['owner'],axis=1)
    df.loc['total'] = df.sum()
    return df

df.groupby(['owner']).apply(lambda_t)
Run Code Online (Sandbox Code Playgroud)

虽然从理论上讲,这可能是一些有趣的事情,但总数并未放置在我想要的位置,而且除此之外,玩家姓名上的值是串联的,因此我最终得到了一个非常拥挤的列。这样我最终就有了一个多重索引。

owner       player  val1    val1    val3
A   0        x      5.60    3.18    0.76
    1        y      12.08   15.95   -0.24
    2        z      0.03    0.05    -0.41
    total    xzy    17.71   19.18   0.11
.....
Run Code Online (Sandbox Code Playgroud)

显然,降低多索引的级别可以有所帮助,但我这样错过了总数,它消失了。

df.groupby(['owner']).apply(lambda_t).droplevel(level=1)

owner       player  val1    val1    val3
A            x      5.60    3.18    0.76
A            y      12.08   15.95   -0.24
A            z      0.03    0.05    -0.41
A            xzy    17.71   19.18   0.11
Run Code Online (Sandbox Code Playgroud)

如果这可能的话有什么想法吗?我发现使用 groupby、assign 和 loc 时,您无法正确排序它们。

moz*_*way 5

IIUC,您可以使用稳定的方法按顺序groupby.sum计算总数、assign作为玩家的总名称、concat两个 DataFrame :sort_values

out = (pd
  .concat([df.groupby('owner', as_index=False).sum().assign(player='total'),
           df])
   .sort_values(by='owner', kind='stable', ignore_index=True)
   [df.columns]
)
Run Code Online (Sandbox Code Playgroud)

输出:

   owner player   val1    val1  val3
0      A  total  17.71   19.18  0.11
1      A      x   5.60    3.18  0.76
2      A      y  12.08   15.95 -0.24
3      A      z   0.03    0.05 -0.41
4      B  total   2.38    2.38  2.06
5      B      x   0.02    0.01  2.06
6      B      z   2.36    2.37  0.00
7      C  total   0.88    0.90  0.01
8      C      x   0.16    0.15  0.05
9      C      y   0.72    0.75 -0.04
10     D  total   0.33    0.56 -0.41
11     D      x   0.33    0.56 -0.41
Run Code Online (Sandbox Code Playgroud)