You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用groupby和sum()分组后计算子类别对应类别的百分比

这个需求我之前做数据分析的时候经常碰到,用Pandas的分组和transform功能就能轻松搞定,不用折腾复杂的合并操作~

先看你的示例数据和初始代码,你已经能通过groupby(['key','data2'])['data1'].sum()得到每个子类别(比如A1、A2)的求和结果,接下来只需要计算这些子项在对应父类别(A、B、C)中的占比就行,核心思路是先算出每个父类别的总求和值,再让每个子项的求和值除以这个总数值。

给你两种实用的实现方式:

方法一:分步实现(清晰易懂,适合新手)

  1. 先计算每个(key, data2)组合的求和结果,并转成带列名的DataFrame:
import pandas as pd

df = pd.DataFrame({'key': ['A', 'B', 'C', 'A', 'B', 'C'], 'data1': range(6), 'data2': ['A1', 'B1', 'C1', 'A2', 'B2', 'C2']}, columns = ['key', 'data1', 'data2'])
sum_df = df.groupby(['key','data2'])['data1'].sum().reset_index(name='sum_data1')
  1. 用transform计算每个父类别的总和,并直接算出占比:
sum_df['proportion'] = sum_df['sum_data1'] / sum_df.groupby('key')['sum_data1'].transform('sum')

这里的transform('sum')会自动把每个key的总求和值,广播到该key下的所有子项行,这样就能直接做除法得到占比了,完全不用手动去合并数据。

最终得到的结果如下:

key data2  sum_data1  proportion
0   A    A1          0    0.000000
1   A    A2          3    1.000000
2   B    B1          1    0.200000
3   B    B2          4    0.800000
4   C    C1          2    0.285714
5   C    C2          5    0.714286

方法二:链式调用(简洁高效,适合熟练用户)

如果喜欢写紧凑的代码,可以利用多级索引的特性直接链式操作:

# 只得到占比列
proportion_series = df.groupby(['key','data2'])['data1'].sum() \
                      .groupby(level='key') \
                      .apply(lambda x: x / x.sum()) \
                      .rename('proportion')

# 如果要同时保留求和值和占比
result_df = df.groupby(['key','data2'])['data1'].sum().to_frame('sum_data1')
result_df['proportion'] = result_df.groupby(level='key')['sum_data1'].transform(lambda x: x/x.sum())

这里的groupby(level='key')是针对分组后得到的多级索引的第一级(也就是key)进行分组,省去了重置索引的步骤。

小提示

  • transform是这里的核心:它和普通的agg不同,不会把数据聚合压缩,而是返回和原数据行数一致的结果,把分组聚合的值“映射”回每一行,这在计算占比、均值这类相对指标时特别好用。
  • 如果需要保留多级索引,就不用调用reset_index,直接用level参数处理就行,效率更高。

内容的提问来源于stack exchange,提问作者SBad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:58:10