
本文介绍如何使用 pandas 对多个分类列(如问卷题目)分别按分组变量(如用户类别)统计各取值频次,核心是通过 melt 转为长格式再用 pivot_table 构建多级列结构。
本文介绍如何使用 pandas 对多个分类列(如问卷题目)分别按分组变量(如用户类别)统计各取值频次,核心是通过 melt 转为长格式再用 pivot_table 构建多级列结构。
在处理问卷、用户反馈或多维度分类数据时,常需按某个分组字段(如 Category)分别统计多个问题列(如 Question 1、Question 2)中各选项的出现次数。直接对宽表使用 groupby().value_counts() 或 pivot_table 易导致列嵌套混乱或维度错位。正确解法是先标准化数据结构,再聚合。
✅ 推荐方案:melt + pivot_table
首先将问题列“堆叠”为长格式,使每行代表一个观测单元(ID + 分组 + 题目 + 答案),再以 Category 为行索引、("Question", "Value") 为多级列进行透视计数:
import pandas as pd
# 构造示例数据
df = pd.DataFrame({
"ID": [1, 2, 3, 4],
"Category": ["A", "A", "B", "B"],
"Question 1": ["Agree", "Disagree", "Agree", "Disagree"],
"Question 2": ["Agree", "Agree", "Agree", "Disagree"]
})
# 步骤1:宽→长转换 —— 将所有问题列统一为两列:'Question' 和 'Value'
df_long = df.melt(
id_vars=["ID", "Category"], # 保留的标识列(不展开)
value_vars=["Question 1", "Question 2"], # 需展开的问题列
var_name="Question", # 新列名:问题名称
value_name="Value" # 新列名:回答值
)
# 步骤2:按 Category 行分组,按 (Question, Value) 列分组,计数
result = df_long.pivot_table(
index="Category",
columns=["Question", "Value"],
aggfunc="size", # 等价于 count non-NA
fill_value=0 # 缺失组合补 0
)
print(result)
输出结果为清晰的多级列 DataFrame:
Question Question 1 Question 2 Value Agree Disagree Agree Disagree Category A 1 1 2 0 B 1 1 1 1
⚠️ 注意事项与进阶提示
- 列名兼容性:若问题列名含空格或特殊字符(如 "Question 1"),melt 可正常处理,但后续引用多级列时建议用元组索引,例如 result[("Question 1", "Agree")];
- 扩展性:只需向 value_vars 添加更多问题列(如 ["Question 1", "Question 2", "Question 3"]),逻辑自动适配;
- 替代写法:也可用 groupby(["Category", "Question", "Value"]).size().unstack([1,2], fill_value=0),但 pivot_table 更直观;
- 性能优化:大数据集下,melt 后 pivot_table 效率优于循环遍历各列 value_counts()。
该方法兼顾可读性、可维护性与扩展性,是 Pandas 处理“多题型分组频次统计”任务的标准范式。











