跳到主要内容

Pandas 数据重塑与透视表

数据重塑用于改变表格中数值的排列方式。下面的长表每行记录某一天的一个指标;转成宽表后,每行对应一天,各指标分别占一列。“一行代表什么”就是行粒度。pivot 只重新排列数值,不做汇总;pivot_table 则会按求和等规则合并观测记录。选择方法前,先明确结果中的每一行要代表什么。

操作选型指南

场景需求推荐操作
长表转宽表(唯一映射,无重复)pivot
长表转宽表(需聚合处理)pivot_table
宽表转长表meltwide_to_long
索引层级在行/列轴间移动stack / unstack
展开列表型单元格为多行explode
类别交叉统计crosstab
import pandas as pd

observations = pd.DataFrame({
"date": ["2026-01-01", "2026-01-01", "2026-01-02"],
"metric": ["visits", "sales", "visits"], "value": [10, 2, 20],
})
# 基础透视:假设每个 (date, metric) 组合唯一
wide = observations.pivot(index="date", columns="metric", values="value")

# 聚合透视:处理重复键,显式指定聚合函数
sales = pd.DataFrame({
"region": ["east", "east", "west"], "product": ["A", "A", "B"], "revenue": [10, 20, 5]
})
summary = sales.pivot_table(
index="region",
columns="product",
values="revenue",
aggfunc="sum",
fill_value=0,
margins=True,
observed=True,
)

关键区别:

  • pivot 在遇到重复的索引/列组合时会直接报错。这其实是一个有用的粒度检查机制,能帮你发现数据中的意外重复。
  • 仅当确实需要聚合(如求和、计数)时才使用 pivot_table,且必须显式指定 aggfunc,避免默认行为带来的歧义。

转回长表

# 将宽表转回长表
long = wide.reset_index().melt(
id_vars="date",
var_name="metric",
value_name="value",
)

重塑后的验证要点:

  1. 行数校验:确认转换前后的总行数或关键键的唯一性符合预期。
  2. 缺失值语义:严格区分“结构性缺失”(该组合本就不存在)与“观测值缺失”(存在但值为 NaN)。
  3. 填充策略fill_value=0 仅在“无观测记录”在业务上确实等同于“数值为 0”时才合理。否则,应保留 NaN 以区分“未发生”和“发生但值为 0”。

重塑后能还原什么

本例 wide(2, 2):visits 为 10、20,sales 为 2、缺失。melt 后有四行,其中 1 月 2 日缺失的 sales 组合是重塑时补出的。因此若不处理结构性缺失,就无法精确还原原来的三行。也不能一律删除缺失行,因为有些缺失可能本来就是观测记录。

透视表 API 对单独的 sales 表进行聚合:east/A 为 30,west/B 为 5,summary.loc["All", "All"] 的总计为 35。聚合后原来的 10 和 20 已合并,melt 无法还原。margins=True 使用聚合函数重新计算总计,所以均值总计通常不是已显示分组均值的简单平均。若类别层级或缺失键会影响目标表格,应显式选择 observeddropna

参考资料

探索关联打开关联网络