本文介绍如何利用 pd.crosstab 将分类变量(如顾客评分)按分组(如门店)展开为多个计数列,高效实现“一店一行、三评计数”的宽表转换,并控制列序与轴标签。
本文介绍如何利用 `pd.crosstab` 将分类变量(如顾客评分)按分组(如门店)展开为多个计数列,高效实现“一店一行、三评计数”的宽表转换,并控制列序与轴标签。
在数据分析中,常需将长格式的分类计数数据(如每条记录代表一次门店评分)聚合为宽格式汇总表(如每行代表一家门店,各列分别显示 High / Medium / Low 的出现次数)。Pandas 提供了简洁高效的解决方案——pd.crosstab,它专为构建二维频数交叉表而设计。
以下是一个典型场景:原始 DataFrame 包含两列 'Shop' 和 'Review',其中 'Review' 取值为 'High'、'Medium' 或 'Low',但同一店铺可能有多条评分记录。目标是生成新 DataFrame,每行唯一对应一个店铺,并新增三列分别统计该店各评分等级的数量。
首先,构造示例数据:
import pandas as pd data = [['store1', 'High'], ['store1', 'Medium'], ['store2', 'Low'], ['store2', 'Low']] df = pd.DataFrame(data, columns=['Shop', 'Review'])
为确保输出列严格按 'High' → 'Medium' → 'Low' 顺序排列(而非默认字母序),推荐先将 'Review' 列转为有序分类类型(Categorical):
df['Review'] = pd.Categorical(df['Review'], categories=['High', 'Medium', 'Low'])
接着调用 pd.crosstab 进行交叉计数:
result = pd.crosstab(df['Shop'], df['Review']) print(result)
输出为:
Review High Medium Low Shop store1 1 1 0 store2 0 0 2
默认情况下,索引名为 'Shop',列名为 'Review'。若需去除这些轴名称以获得更干净的结构化结果,可链式调用 .rename_axis():
result = pd.crosstab(df['Shop'], df['Review']).rename_axis(index=None, columns=None) print(result)
输出变为:
High Medium Low store1 1 1 0 store2 0 0 2
✅ 关键注意事项:
- 若原始数据中存在未声明的 'Review' 值(如 'Very High'),且未在 categories 中定义,该值将被设为 NaN 并在 crosstab 中忽略;建议提前清洗或扩展类别。
- crosstab 返回的是 DataFrame,可直接参与后续分析(如计算满意度比率:result['High'] / result.sum(axis=1))。
- 如需保留原始索引或合并回原表,可用 result.reset_index() 转换索引为普通列,再通过 merge 关联。
该方法比手动 groupby().apply(lambda x: x.value_counts()) 或多次 sum() 更简洁、性能更优,是 Pandas 宽表聚合的标准实践。










