[英]pandas: add a total row for each subgroup when groupby (especially for non-additive method such as `nunique`)
[英]Pandas - adding a total row to each subgroup as first row
我知道这个问题在 StackOverflow 上已经被多次提及,我觉得完成这个任务并不容易。 这个和许多其他答案: 将总行添加到 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
我的预期 output 如下,其中每个所有者的总数被计算并放置在子组中的第一行。
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
我尝试使用我在 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)
虽然理论上这可能很有趣,但总数并没有放在我想要的位置,而且最重要的是玩家姓名的值是连接的,所以我最终得到了一个非常紧凑的列。 这样我最终得到了一个多索引。
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
.....
显然,降低多索引的级别会有所帮助,但我这样错过了总数,它消失了。
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
如果可能的话,有什么想法吗? 我已经看到使用 groupby、assign 和 loc 您无法正确订购它们。
IIUC,您可以使用groupby.sum
来计算总数, assign
总名称指定为 player,将两个concat
按顺序连接,并使用稳定的方法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]
)
output:
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
另一种可能的解决方案:
(df.groupby('owner')
.apply(lambda x:
pd.concat(
[pd.concat([pd.DataFrame({'owner': x.owner.unique(), 'player': ['total']}),
pd.DataFrame(x.iloc[:, 2:].apply(sum, axis=0)).T], axis=1),
x]
))).reset_index(drop=True)
Output:
owner player val1 val2 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.