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

Pandas如何对DataFrame分组并将类别字段转为列统计计数

Pandas分组统计转宽表实现方案

要实现按setting分组、统计分组总记录数+各status类型计数、缺失status类别补0的宽表输出,用pd.crosstab(交叉统计表)实现最简便,不需要先生成groupby长表再转换,可直接一步出结果。

具体实现步骤

  • 先定义固定的status枚举值列表,保证即使数据集缺失某类status,最终输出也会保留对应列
  • 将status列转为pandas分类类型,绑定固定枚举值,避免统计时漏掉缺失的类别
  • 用crosstab以setting为行、status为列做计数统计
  • 新增total列,对每行各status的计数求和得到分组总记录数
  • 调整列顺序匹配目标输出格式

完整代码

import pandas as pd

# 构造原始数据集
lst = [
 ['s001','b1','typeA'],['s002','b1','typeB'],['s003','b1','typeC'],['s004','b1','typeD'],
 ['s005','b1','typeA'],['s006','b1','typeB'],['s007','b1','typeC'],['s008','b1','typeD'],
 ['s009','b2','typeA'],['s010','b2','typeB'],['s011','b2','typeC']
 ] 
df = pd.DataFrame(lst, columns=['sn','setting','status'])

# 定义固定的status类型
fixed_status_types = ['typeA', 'typeB', 'typeC', 'typeD']
# 将status列转为绑定固定类别的分类类型,缺失类别自动补0
df['status'] = pd.Categorical(df['status'], categories=fixed_status_types)

# 生成交叉统计宽表
result = pd.crosstab(
    index=df['setting'],
    columns=df['status'],
    dropna=False
).reset_index()

# 计算分组总记录数
result['total'] = result[fixed_status_types].sum(axis=1)
# 调整列顺序,和期望输出对齐
result = result[['setting', 'total'] + fixed_status_types]

输出结果

运行代码后得到的result内容如下,和预期格式完全一致(注:给出的期望输出里存在笔误,将typeA错写为tppeA,结果中已修正为正确列名):

setting  total  typeA  typeB  typeC  typeD
0      b1      8      2      2      2      2
1      b2      3      1      1      1      0

其他可选写法

如果更习惯用groupby的逻辑,也可以先分组计数再转透视表,但需要手动补全缺失的status列填0,代码会稍繁琐:

# 分组计数后转透视表
pivot_df = df.groupby(['setting','status']).size().unstack(fill_value=0)
# 补全可能缺失的status列
for col in fixed_status_types:
    if col not in pivot_df.columns:
        pivot_df[col] = 0
# 计算total并重设索引
pivot_df['total'] = pivot_df[fixed_status_types].sum(axis=1)
pivot_df = pivot_df.reset_index()[['setting','total']+fixed_status_types]

两种写法最终输出结果完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 16:09:17