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

如何用Pandas的groupby/crosstab/pivot_table实现指定统计表格?

使用Pandas实现指定统计汇总表

需求说明

给定如下输入数据:

GenderSQ2_1SQ2_2SQ2_3
M123
F1NaN3
F123
FNaN23
M12NaN
MNaN23

需要生成包含两类统计的汇总表:

  • All行:统计总样本数(Base)、男性(M)和女性(F)的样本数
  • SQ2_*行:对应列非空值占对应分组总数的百分比(保留1位小数)

最终输出:

BaseMF
All633
SQ2_166.066.066.0
SQ2_283.0100.066.0
SQ2_383.066.0100.0

实现方法(基于Pandas)

步骤1:构造输入DataFrame

先把原始数据转为Pandas的DataFrame:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'Gender': ['M', 'F', 'F', 'F', 'M', 'M'],
    'SQ2_1': [1, 1, 1, np.nan, 1, np.nan],
    'SQ2_2': [2, np.nan, 2, 2, 2, 2],
    'SQ2_3': [3, 3, 3, 3, np.nan, 3]
})

步骤2:计算「All」行的统计数据

直接统计总样本数和各性别的样本数:

# 生成All行数据
all_row = pd.Series({
    'Base': len(df),
    'M': df['Gender'].value_counts().get('M', 0),
    'F': df['Gender'].value_counts().get('F', 0)
}).to_frame('All').T

步骤3:计算各SQ2列的百分比统计

遍历所有SQ2开头的列,按性别分组统计非空值占比:

# 筛选出所有SQ2相关列
sq_columns = [col for col in df.columns if col.startswith('SQ2_')]
percent_rows = pd.DataFrame()

for col in sq_columns:
    # 按性别统计该列非空值数量
    group_non_null = df.groupby('Gender')[col].count()
    # 计算各性别占比,乘以100后保留1位小数
    group_pct = (group_non_null / all_row.loc['All', ['M', 'F']]) * 100
    # 计算整体占比
    overall_pct = (df[col].count() / all_row.loc['All', 'Base']) * 100
    # 整理为当前列的统计行
    current_row = pd.Series({
        'Base': round(overall_pct, 1),
        'M': round(group_pct.get('M', 0), 1),
        'F': round(group_pct.get('F', 0), 1)
    }, name=col)
    percent_rows = pd.concat([percent_rows, current_row.to_frame().T])

步骤4:合并结果并输出

把All行和各SQ2百分比行合并,调整索引格式:

# 合并所有行
final_result = pd.concat([all_row, percent_rows])
# 重置索引列名,让索引列显示为空
final_result.index.name = ''

# 打印结果
print(final_result)

运行后即可得到目标汇总表。


另一种方法:用pivot_table简化分组统计

如果偏好使用pivot_table,可以通过标记非空值来实现:

# 把各SQ2列的非空值标记为1,空值标记为0
df_non_null = df[sq_columns].notna().astype(int)
df_non_null['Gender'] = df['Gender']

# 用pivot_table统计各性别下的非空总数
pivot_stats = pd.pivot_table(df_non_null, index=df_non_null.columns[:-1], columns='Gender', aggfunc='sum')
# 调整结构为宽表
pivot_wide = pivot_stats.unstack().reset_index(name='count').pivot(index='level_0', columns='Gender', values='count').fillna(0)

# 计算百分比并添加Base列
pivot_pct = pivot_wide.div(all_row.loc['All', ['M', 'F']], axis=1) * 100
pivot_pct['Base'] = (df[sq_columns].count() / all_row.loc['All', 'Base']) * 100
pivot_pct = pivot_pct[['Base', 'M', 'F']].round(1)

# 合并All行得到最终结果
final_result = pd.concat([all_row, pivot_pct])
final_result.index.name = ''

print(final_result)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 13:48:17