Pandas数据透视表pivot_table的使用小结
数据分析师大概都有过这样的经历——面对一张几万行的原始数据表,老板要的是"按地区、按季度、按产品类别"的汇总报表,而你手里只有一堆散乱的流水记录。这时候,pivot_table 就是你最得力的工具。它不是什么高深的黑魔法,本质上就是把"长条形"的原始数据,折叠成一张人人看得懂的二维汇总表——同时完成分组、聚合、重塑三件事,一行代码搞定。
一、先搞清楚它在做什么
pivot_table 的工作逻辑,拆开来看其实只有三步:
第一步,分组。 按照你指定的 index 和 columns 字段,把数据切成若干个小格子——就像把一张大桌子划分成行和列的网格。
第二步,聚合。 每个格子里可能有多条记录,用 aggfunc 指定的函数(求和、均值、计数……)把它们压缩成一个数字。
第三步,重塑。 把压缩后的结果摆进二维表格,行由 index 决定,列由 columns 决定,一张干净的汇总表就成型了。
这里有个容易混淆的地方:pivot() 和 pivot_table() 长得很像,但前者要求每个行列组合唯一,遇到重复数据直接报错;后者通过聚合函数处理重复值,日常工作中几乎永远用后者。同样,groupby() 也能分组聚合,但输出的是"长格式"结果,不会自动帮你铺成二维表。三者各有用武之地,但要生成报表,pivot_table 是最直接的路。
二、把参数吃透
pandas.pivot_table(
data,
values=None,
index=None,
columns=None,
aggfunc='mean',
fill_value=None,
margins=False,
dropna=True,
margins_name='All',
observed=False, # pandas 2.2+ 建议显式设为 True
sort=True
)
参数不多,但每一个都有讲究,下面逐一说清楚:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| data | DataFrame | 必填 | 输入数据源 |
| values | str / list | None | 要聚合的数值列;省略则对所有数值列聚合 |
| index | str / list | None | 行分组字段,传列表可形成多层索引 |
| columns | str / list | None | 列分组字段,传列表可形成多层列 |
| aggfunc | func / list / dict | 'mean' | 聚合函数,支持字符串、函数、列表、字典 |
| fill_value | scalar | None | 聚合后产生的 NaN 用此值填充 |
| margins | bool | False | 是否在末尾添加行列汇总(小计/总计) |
| dropna | bool | True | 聚合前是否丢弃全为 NaN 的列 |
| margins_name | str | 'All' | 汇总行/列的标签,可改成"合计"或"总计" |
| observed | bool | False | 仅对 Categorical 类型有效,True 则只展示实际出现的值 |
| sort | bool | True | 结果是否排序(v1.3.0 新增) |
有两个参数特别容易被忽略,单独说一下。
fill_value 和 dropna 经常被当成同一回事,但它们作用的时机完全不同。dropna=True 发生在聚合之前,把含 NaN 的行直接丢掉;fill_value 发生在聚合之后,把结果表里出现的空格填上指定的值。两者同时使用时,先丢后填,顺序不能搞反。
observed 参数在 pandas 2.2 之后变得重要起来。如果分组字段是 Categorical 类型,默认的 observed=False 会把所有类别组合都列出来,哪怕某些组合在数据里根本不存在,结果表会凭空多出一堆全零的行。改成 observed=True 就只展示真实出现过的组合,干净很多。
三、从零开始,跑通第一个例子
import pandas as pd
import numpy as np
df = pd.DataFrame({
"A": ["foo", "foo", "foo", "foo", "foo", "bar", "bar", "bar", "bar"],
"B": ["one", "one", "one", "two", "two", "one", "one", "two", "two"],
"C": ["small", "large", "large", "small", "small", "large", "small", "small", "large"],
"D": [1, 2, 2, 3, 3, 4, 5, 6, 7],
"E": [2, 4, 5, 5, 6, 6, 8, 9, 9]
})
最基础的用法: 按 A、B 分行,按 C 分列,对 D 列求和。
table = pd.pivot_table(df, values='D', index=['A', 'B'],
columns=['C'], aggfunc="sum")
# C large small
# A B
# bar one 4.0 5.0
# two 7.0 6.0
# foo one 4.0 1.0
# two NaN 6.0
结果里出现了 NaN——因为 foo/two/large 这个组合在原始数据里不存在。加上 fill_value=0 就能填平:
table = pd.pivot_table(df, values='D', index=['A', 'B'],
columns=['C'], aggfunc="sum", fill_value=0)
对不同列用不同聚合函数: 这是 aggfunc 字典语法最实用的地方——D 列求均值,E 列同时算最小值、最大值和均值。
table = pd.pivot_table(df, values=['D', 'E'], index=['A', 'C'],
aggfunc={'D': 'mean', 'E': ['min', 'max', 'mean']})
# 结果列变成多层,E 列下挂三个子列
四、真实场景里怎么用
销售报表:最经典的用法
季度销售汇总大概是 pivot_table 被用得最多的场景。一张原始订单表,几行代码变成管理层要的那种"行是季度、列是地区、格子里是销售额"的报表:
data = {
'地区': ['华东', '华东', '华北', '华北', '华南', '华南'],
'产品': ['A', 'B', 'A', 'B', 'A', 'B'],
'季度': [1, 1, 1, 2, 2, 2],
'销售额': [150000, 120000, 90000, 110000, 130000, 95000],
'利润': [30000, 24000, 18000, 22000, 26000, 19000]
}
df_sales = pd.DataFrame(data)
pivot = pd.pivot_table(
data=df_sales,
values=['销售额', '利润'],
index='季度',
columns='地区',
aggfunc='sum',
fill_value=0,
margins=True,
margins_name='总计'
)
print(pivot)
margins=True 会自动在末尾追加一行一列的汇总,省去手动求和的麻烦。
时间维度分析:多层索引的威力
当你想同时按"地区"和"月份"分行时,把它们打包成列表传给 index 就行,pandas 会自动生成多层索引:
df['月份'] = df['日期'].dt.month
pivot = pd.pivot_table(
data=df,
index=['地区', '月份'], # 两级行索引
columns='产品',
values='销售额',
aggfunc='sum'
)
生成的表格可以用 .xs() 切片访问某一层:
pivot.xs('华东', level='地区') # 只看华东的数据
用户行为分析:多函数同时上
想同时看"总访问量"和"人均访问次数"?一次搞定:
pivot = pd.pivot_table(
data=df_user,
index='用户等级',
columns='访问渠道',
values='访问次数',
aggfunc=['sum', 'mean'],
fill_value=0
)
五、几个让结果更好用的技巧
自定义聚合函数
aggfunc 接受任意 Python 函数,不局限于内置统计量。比如想算极差(最大值减最小值):
pivot = pd.pivot_table(df, values='D', index='A',
aggfunc=lambda x: x.max() - x.min())
或者同时跑多个函数:
pivot = pd.pivot_table(df, values='D', index='A',
aggfunc=['sum', 'mean', 'count', np.std])
扁平化多层列名
使用多个 aggfunc 时,结果列会变成 MultiIndex,导出 Excel 或做后续处理时很麻烦。一行代码压平:
pivot.columns = ['_'.join(col).strip() for col in pivot.columns.values]
# 原来的 ('sum', 'D') 变成 'sum_D',清爽很多
链式操作:透视完接着筛选
pivot_table 的结果是标准 DataFrame,可以直接接 query()、sort_values() 等操作:
result = (
pd.pivot_table(df, values='销售额', index='地区', aggfunc='sum')
.reset_index()
.sort_values('销售额', ascending=False)
.query('销售额 > 100000')
)
六、几种相近方法的横向对比
选哪个方法,取决于你的数据形态和目标输出:
| 方法 | 支持重复值 | 支持聚合 | 输出格式 | 最适合 |
|---|---|---|---|---|
| pivot() | ❌ | ❌ | 宽格式 | 数据唯一,纯重塑 |
| pivot_table() | ✅ | ✅ 灵活 | 宽格式 | 汇总报表、多维分析 |
| groupby() | ✅ | ✅ 灵活 | 长格式 | 分组统计,结果灵活 |
| crosstab() | ✅ | ✅ 默认频次 | 宽格式 | 交叉频次统计 |
经验上来说:要生成"行×列"二维汇总表,首选 pivot_table;只需要对单列做分组统计,groupby 更简洁;做问卷数据的交叉分析,crosstab 最顺手。
七、综合实战:电商订单分析
把前面说的技巧都用上,跑一个完整的例子:
import pandas as pd
import numpy as np
np.random.seed(42)
n = 200
df = pd.DataFrame({
'地区': np.random.choice(['华东', '华北', '华南', '西部'], n),
'产品类别': np.random.choice(['电子', '服装', '食品'], n),
'季度': np.random.choice([1, 2, 3, 4], n),
'销售额': np.random.randint(1000, 50000, n),
'利润': np.random.randint(100, 10000, n),
'订单数': np.random.randint(1, 100, n)
})
# 多维透视:行=地区+季度,列=产品类别
# 销售额求和,利润求均值,末尾加总计
pivot = pd.pivot_table(
data=df,
values=['销售额', '利润'],
index=['地区', '季度'],
columns='产品类别',
aggfunc={'销售额': 'sum', '利润': 'mean'},
fill_value=0,
margins=True,
margins_name='汇总'
)
# 扁平化列名,方便后续处理
pivot.columns = ['_'.join(col) for col in pivot.columns]
print(pivot.head(10))
# 单独看华东的数据
print(pivot.xs('华东', level='地区'))
写在最后
pivot_table 的价值,在于它把"分组→聚合→重塑"这三步操作压缩成了一行声明式代码,让你把精力放在"我想看什么"上,而不是"怎么把数据搬来搬去"。
用熟之后,记住几个核心习惯:index/columns 控制维度,aggfunc 字典语法处理异构聚合,margins=True 自动加总计,fill_value 收拾稀疏数据的烂摊子,结果是标准 DataFrame,随时可以接后续操作。
剩下的,就是多跑几次真实数据,感觉自然就来了。
参考资料
- pandas 官方 API 文档:pandas.pivot_table
- pandas 官方用户指南:Reshaping and pivot tables
- 华为云开发者社区:深入探究Pandas中的透视表:基础到高级应用全覆盖
- 百度 Comate:Pandas数据透视表:多维度聚合与动态分析实战指南
到此这篇关于Pandas数据透视表pivot_table的使用小结的文章就介绍到这了,更多相关Pandas数据透视表pivot_table内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
django xadmin action兼容自定义model权限教程
这篇文章主要介绍了django xadmin action兼容自定义model权限教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-03-03
Python数据可视化之Pandas、Matplotlib与Seaborn的高效实战指南
本文介绍了Python数据可视化的综合解决方案,涵盖Pandas、Matplotlib和Seaborn三大工具的使用技巧,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下2026-02-02


最新评论