本文介绍如何使用 pandas 对多个分类列(如问卷题目)按指定分组变量(如“category”)分别统计各取值出现频次,并以清晰的多级列结构呈现结果。
本文介绍如何使用 pandas 对多个分类列(如问卷题目)按指定分组变量(如“category”)分别统计各取值出现频次,并以清晰的多级列结构呈现结果。
在处理问卷、用户反馈或分类标签类数据时,常需按某一维度(如用户群体、实验组别)分别统计多个问题选项的分布情况。直接对多列使用 groupby().value_counts() 或 pivot_table 容易陷入层级混乱——例如将所有问题组合成笛卡尔积索引,失去“每题独立统计”的语义。正确解法是先标准化数据结构,再统一聚合。
核心思路分三步:
- 宽表转长表(melt):将待统计的多列(如 "Question 1", "Question 2")合并为两列——"Question"(列名作为变量)和 "Value"(对应取值);
- 构建多级列透视表(pivot_table):以分组变量("Category")为行索引,以 ["Question", "Value"] 为列索引,用 aggfunc="size" 统计频次;
- 自动填充缺失值(fill_value=0):确保未出现的组合显示为 0,而非 NaN。
以下是完整可运行代码示例:
import pandas as pd
# 构造示例数据
data = {
"ID": [1, 2, 3, 4],
"Category": ["A", "A", "B", "B"],
"Question 1": ["Agree", "Disagree", "Agree", "Disagree"],
"Question 2": ["Agree", "Agree", "Agree", "Disagree"]
}
df = pd.DataFrame(data)
# 步骤1:宽表 → 长表(保留 ID 和 Category 为标识列)
df_long = df.melt(
id_vars=["ID", "Category"],
value_vars=["Question 1", "Question 2"],
var_name="Question",
value_name="Value"
)
# 步骤2 & 3:按 Category 分组,对 (Question, Value) 组合做频次透视
result = df_long.pivot_table(
index="Category",
columns=["Question", "Value"],
aggfunc="size",
fill_value=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/Question 2),第二级为选项值(Agree/Disagree),语义一目了然;
- 支持任意数量问题列:只需扩展 value_vars 列表(如 ["Q1", "Q2", "Q3", "Q4"]);
- 兼容任意分类型值(字符串、数字、布尔值等),无需预定义类别。
⚠️ 注意事项:
- 若原始数据中某题存在空值(NaN),melt 后会保留,pivot_table 默认会忽略 NaN 作为列值;如需统计缺失值,可先用 df.fillna("Missing") 处理;
- pivot_table(..., aggfunc="size") 等价于 pivot_table(..., aggfunc=lambda x: len(x)),但更高效;
- 如需进一步计算百分比,可在 result 上使用 result.div(result.sum(axis=1), axis=0).round(3) 实现行归一化。
该模式是 Pandas 数据重塑的经典实践,兼顾可读性、扩展性与性能,适用于各类多维分类频次分析场景。











