求更简洁的Python pandas groupby分组占比实现方法
问题描述
需要对DataFrame数据按指定列进行groupby分组,计算每组中数值大于特定阈值的数据占该组总数的百分比。当前通过两次groupby生成临时DataFrame,合并后计算占比,希望找到无需创建临时DataFrame的更简洁(Pythonic)实现方式。
示例数据
import pandas as pd df = pd.DataFrame({'n': ['a', 'b', 'c', 'a', 'c', 'a', 'a', 'c', 'a'], 'm': ['j', 'j', 'j', 'j', 'j', 'j', 'f', 'f', 'f'], 'v': [1, 1, 1, 2, 1, 2, 3, 6, 5]})
现有实现步骤
- 按
n和m分组统计每组总数:
dfcount = df.groupby(['n', 'm'])['v'].agg('count').reset_index().rename(columns={'v': 'count'})
- 筛选
v大于1的数据,再按n和m分组统计数量:
dfover1 = df[df['v'] > 1].groupby(['n','m']).count().reset_index().rename(columns={'v': 'over1count'})
- 合并两个临时DataFrame,计算占比:
dfnew = dfcount.merge(dfover1, on=['n', 'm']) dfnew['late%'] = (100 * dfnew['over1count'] / dfnew['count']).round(1)
期望最终结果
| n | m | count | over1count | late% | |
|---|---|---|---|---|---|
| 0 | a | f | 2 | 2 | 100.0 |
| 1 | a | j | 3 | 2 | 66.7 |
| 2 | c | f | 1 | 1 | 100.0 |
简洁实现方式
以下几种方法只需一次groupby操作,无需创建临时DataFrame,代码更简洁高效:
方法一:聚合时同时计算总数和符合条件的数量
利用agg参数直接指定多个统计项,一次完成总数和达标数的计算:
result = df.groupby(['n', 'm'])['v'].agg( count='count', over1count=lambda x: (x > 1).sum() ).reset_index() result['late%'] = (100 * result['over1count'] / result['count']).round(1)
方法二:直接计算占比(按需保留列)
如果不需要单独的count和over1count列,可直接计算占比;若需要保留总数,也能通过agg一次性完成:
# 仅保留占比列 result = df.groupby(['n', 'm'])['v'].apply(lambda x: (x > 1).mean() * 100).round(1).reset_index(name='late%') # 同时保留总数和占比 result = df.groupby(['n', 'm'])['v'].agg( count='count', late%=lambda x: (x > 1).mean() * 100 ).round(1).reset_index()
方法三:先标记达标状态再聚合
先新增一个布尔列标记数据是否符合阈值条件,再分组统计总数和达标数:
result = df.assign(over1=df['v'] > 1).groupby(['n', 'm']).agg( count=('v', 'count'), over1count=('over1', 'sum') ).reset_index() result['late%'] = (100 * result['over1count'] / result['count']).round(1)
内容的提问来源于stack exchange,提问作者Jamie
相关产品推荐
相关产品推荐

