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

如何对Dataframe分组统计并补全缺失结果为0、添加间隔与总计

实现DataFrame分组统计的三个需求:补全类别、添加总计、分组空行间隔

先明确咱们的原始数据和当前的问题:
原始DataFrame定义如下:

import pandas as pd

df = {'Client': ['A', 'A', 'A', 'B', 'B', 'B', 'B','B','B','B','C','D','D','D','D','D','D','D','D','D','D','D' ], 'Result': ['Covered', 'Customer Reject', 'Customer Timeout', 'Dealer Reject','Dealer Timeout','Done','Tied Covered','Tied Done','Tied Traded Away','Traded Away','No RFQ','Covered','Customer Reject','Customer Timeout','Dealer Reject','Dealer Timeout','Done','Tied Covered','Tied Done','Tied Traded Away','Traded Away','No RFQ']}
df = pd.DataFrame.from_dict(df)

现在直接用df.groupby(['Client','Result']).agg({'Result': 'size'})只能统计每个Client下实际出现过的Result,没法满足补全缺失类别、加总计、分组空行这三个需求,下面咱们一步步来实现:

步骤1:补全每个Client未出现的Result类别

首先把所有11种Result列出来,生成每个Client和所有Result的笛卡尔积索引,再和原统计结果合并填充0:

# 定义所有需要包含的Result类别
all_results = [
    'Covered', 'Customer Reject', 'Customer Timeout',
    'Dealer Reject', 'Dealer Timeout', 'Done',
    'Tied Covered', 'Tied Done', 'Tied Traded Away',
    'Traded Away', 'No RFQ'
]

# 先做基础分组统计
grouped = df.groupby(['Client', 'Result']).agg(size=('Result', 'size'))

# 生成每个Client对应的全Result组合的MultiIndex
clients = df['Client'].unique()
full_index = pd.MultiIndex.from_product(
    [clients, all_results],
    names=['Client', 'Result']
)

# 合并并填充缺失值为0
full_grouped = grouped.reindex(full_index, fill_value=0)

步骤2:为每个Client添加总计行

接下来给每个Client分组添加一行总计,统计该Client下所有Result的总和:

# 计算每个Client的总计
client_totals = full_grouped.groupby('Client').sum().rename({'size': 'Total'}, axis=1)
# 把总计行转换为和原数据一致的MultiIndex格式
total_rows = client_totals.reset_index().assign(Result='Total').set_index(['Client', 'Result'])
# 合并原数据和总计行,然后按Client排序
combined = pd.concat([full_grouped, total_rows]).sort_index(level='Client')

步骤3:添加分组间的空行间隔

最后在不同Client的分组之间插入空行,让结果更易读:

# 获取每个Client的行索引位置,准备插入空行
client_indices = combined.index.get_level_values('Client').unique()
insert_positions = []
for i in range(1, len(client_indices)):
    # 找到当前Client的第一行位置,在前一个Client的最后一行后插入空行
    pos = combined.index.get_loc((client_indices[i], all_results[0]))
    insert_positions.append(pos)

# 创建空行DataFrame,索引用(' ', '')来占位
empty_row = pd.DataFrame({'size': [None]}, index=pd.MultiIndex.from_tuples([(' ', '')], names=['Client', 'Result']))

# 逐个插入空行(倒序插入避免位置偏移)
for pos in reversed(insert_positions):
    combined = pd.concat([combined.iloc[:pos], empty_row, combined.iloc[pos:]]).reset_index(drop=False)

# 重置索引后再设置回MultiIndex
combined = combined.set_index(['Client', 'Result'])

现在打印combined就能看到符合要求的结果了:每个Client下的11种Result都被补全(未出现的统计值为0)、每个Client最后有总计行、不同Client分组之间有空白行间隔。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 15:07:45