如何用Pandas计算DataFrame组内元素占比:单列除以分组总和
计算Pandas DataFrame分组内元素占比的解决方案
嘿,这个需求其实用Pandas的groupby配合transform方法就能完美解决,我给你一步步讲清楚怎么操作:
核心思路
我们需要先按c2列分组计算每组c3的总和,然后把这个总和广播到该组的每一行,这样原DataFrame的每个c3元素就能直接和对应组的总和做除法,得到占比。
具体步骤(附示例)
1. 先构造一个示例DataFrame(方便你对照测试)
import pandas as pd df = pd.DataFrame({ 'c2': ['A', 'A', 'B', 'B', 'B', 'C'], 'c3': [10, 20, 15, 5, 20, 30] })
这个示例里,c2列有A、B、C三个分组,c3是我们要计算占比的数值列。
2. 计算分组总和并广播到每一行
用groupby('c2')['c3'].transform('sum')就能把每组的总和对应到该组的每一行,我们可以先把这个结果存成一个新列,方便查看:
# 添加分组总和列 df['group_total'] = df.groupby('c2')['c3'].transform('sum')
这时候DataFrame会变成这样:
| c2 | c3 | group_total | |
|---|---|---|---|
| 0 | A | 10 | 30 |
| 1 | A | 20 | 30 |
| 2 | B | 15 | 40 |
| 3 | B | 5 | 40 |
| 4 | B | 20 | 40 |
| 5 | C | 30 | 30 |
3. 计算每个元素的分组占比
直接用原c3列除以group_total列就行,要是需要保留小数位数,可以用round()方法:
# 计算占比,保留两位小数 df['c3_ratio'] = (df['c3'] / df['group_total']).round(2)
最终结果:
| c2 | c3 | group_total | c3_ratio | |
|---|---|---|---|---|
| 0 | A | 10 | 30 | 0.33 |
| 1 | A | 20 | 30 | 0.67 |
| 2 | B | 15 | 40 | 0.38 |
| 3 | B | 5 | 40 | 0.12 |
| 4 | B | 20 | 40 | 0.5 |
| 5 | C | 30 | 30 | 1 |
4. 简化写法(跳过中间列)
如果不需要保留group_total列,也可以直接一步到位:
df['c3_ratio'] = df['c3'] / df.groupby('c2')['c3'].transform('sum')
注意事项
- 为什么用
transform而不是agg?因为agg只会返回每个分组的一个结果(比如每组总和),而transform会把结果对齐到原DataFrame的每一行,这样才能保证每个元素都能找到对应组的总和。 - 如果遇到分组总和为0的情况,直接除法会报错,你可以用
replace把0替换成NaN来避免错误:df['c3_ratio'] = df['c3'] / df.groupby('c2')['c3'].transform('sum').replace(0, float('nan'))
内容的提问来源于stack exchange,提问作者Christine
相关产品推荐
相关产品推荐

