Pandas 数据重塑(pivot / melt / stack / unstack)
数据重塑是数据分析中的常见操作,用于改变数据的布局结构。Pandas 提供了 pivot、melt、stack、unstack 等函数来实现长格式和宽格式之间的转换。
pivot 透视表
pivot 将长格式数据转换为宽格式,类似于 Excel 的透视表功能。
基本用法
实例
import pandas as pd
# 创建长格式数据
df = pd.DataFrame({
"日期": ["2024-01-01", "2024-01-01", "2024-01-02", "2024-01-02"],
"产品": ["A", "B", "A", "B"],
"销量": [100, 150, 120, 90]
})
print("长格式数据:")
print(df)
print()
# 转换为宽格式
pivot_df = df.pivot(index="日期", columns="产品", values="销量")
print("宽格式数据:")
print(pivot_df)
# 创建长格式数据
df = pd.DataFrame({
"日期": ["2024-01-01", "2024-01-01", "2024-01-02", "2024-01-02"],
"产品": ["A", "B", "A", "B"],
"销量": [100, 150, 120, 90]
})
print("长格式数据:")
print(df)
print()
# 转换为宽格式
pivot_df = df.pivot(index="日期", columns="产品", values="销量")
print("宽格式数据:")
print(pivot_df)
多重索引
实例
import pandas as pd
df = pd.DataFrame({
"年份": ["2024", "2024", "2024", "2024"],
"季度": ["Q1", "Q1", "Q2", "Q2"],
"产品": ["A", "B", "A", "B"],
"销量": [100, 150, 120, 90]
})
print("数据:")
print(df)
print()
# 多重索引透视
pivot_df = df.pivot(index=["年份", "季度"], columns="产品", values="销量")
print("多重索引透视:")
print(pivot_df)
df = pd.DataFrame({
"年份": ["2024", "2024", "2024", "2024"],
"季度": ["Q1", "Q1", "Q2", "Q2"],
"产品": ["A", "B", "A", "B"],
"销量": [100, 150, 120, 90]
})
print("数据:")
print(df)
print()
# 多重索引透视
pivot_df = df.pivot(index=["年份", "季度"], columns="产品", values="销量")
print("多重索引透视:")
print(pivot_df)
聚合函数
实例
import pandas as pd
# 有重复值的情况
df = pd.DataFrame({
"日期": ["2024-01-01", "2024-01-01", "2024-01-01", "2024-01-02"],
"产品": ["A", "A", "B", "B"],
"销量": [100, 110, 80, 90]
})
print("有重复值的数据:")
print(df)
print()
# pivot 默认不支持重复值,需要用 pivot_table 并指定聚合函数
pivot_df = df.pivot_table(index="日期", columns="产品", values="销量", aggfunc="sum")
print("使用 sum 聚合:")
print(pivot_df)
print()
# 使用 mean
print("使用 mean 聚合:")
print(df.pivot_table(index="日期", columns="产品", values="销量", aggfunc="mean"))
# 有重复值的情况
df = pd.DataFrame({
"日期": ["2024-01-01", "2024-01-01", "2024-01-01", "2024-01-02"],
"产品": ["A", "A", "B", "B"],
"销量": [100, 110, 80, 90]
})
print("有重复值的数据:")
print(df)
print()
# pivot 默认不支持重复值,需要用 pivot_table 并指定聚合函数
pivot_df = df.pivot_table(index="日期", columns="产品", values="销量", aggfunc="sum")
print("使用 sum 聚合:")
print(pivot_df)
print()
# 使用 mean
print("使用 mean 聚合:")
print(df.pivot_table(index="日期", columns="产品", values="销量", aggfunc="mean"))
pivot不允许有重复值,有重复值时使用pivot_table并指定聚合函数。
melt 逆透视
melt 将宽格式数据转换为长格式,是 pivot 的逆操作。
实例
import pandas as pd
# 创建宽格式数据
df = pd.DataFrame({
"日期": ["2024-01-01", "2024-01-02"],
"A": [100, 120],
"B": [150, 90]
})
print("宽格式数据:")
print(df)
print()
# 转换为长格式
melted = df.melt(id_vars="日期", var_name="产品", value_name="销量")
print("长格式数据:")
print(melted)
# 创建宽格式数据
df = pd.DataFrame({
"日期": ["2024-01-01", "2024-01-02"],
"A": [100, 120],
"B": [150, 90]
})
print("宽格式数据:")
print(df)
print()
# 转换为长格式
melted = df.melt(id_vars="日期", var_name="产品", value_name="销量")
print("长格式数据:")
print(melted)
保持多列不变
实例
import pandas as pd
df = pd.DataFrame({
"城市": ["北京", "上海"],
"2023营收": [1000, 800],
"2023利润": [200, 150],
"2024营收": [1200, 950],
"2024利润": [250, 180]
})
print("宽格式:")
print(df)
print()
# 保持"城市"不变,其他列转换为长格式
melted = df.melt(
id_vars="城市",
var_name="指标",
value_name="数值"
)
print("长格式:")
print(melted)
df = pd.DataFrame({
"城市": ["北京", "上海"],
"2023营收": [1000, 800],
"2023利润": [200, 150],
"2024营收": [1200, 950],
"2024利润": [250, 180]
})
print("宽格式:")
print(df)
print()
# 保持"城市"不变,其他列转换为长格式
melted = df.melt(
id_vars="城市",
var_name="指标",
value_name="数值"
)
print("长格式:")
print(melted)
stack 与 unstack
stack 和 unstack 是 MultiIndex 专用的重塑函数。
unstack
实例
import pandas as pd
# 创建带多层索引的数据
df = pd.DataFrame({
"A": [1, 2, 3, 4],
"B": [5, 6, 7, 8]
}, index=pd.MultiIndex.from_tuples(
[("X", 1), ("X", 2), ("Y", 1), ("Y", 2)],
names=["类别", "编号"]
))
print("多层索引数据:")
print(df)
print()
# unstack 将内层索引转为列
print("unstack 后:")
print(df.unstack())
# 创建带多层索引的数据
df = pd.DataFrame({
"A": [1, 2, 3, 4],
"B": [5, 6, 7, 8]
}, index=pd.MultiIndex.from_tuples(
[("X", 1), ("X", 2), ("Y", 1), ("Y", 2)],
names=["类别", "编号"]
))
print("多层索引数据:")
print(df)
print()
# unstack 将内层索引转为列
print("unstack 后:")
print(df.unstack())
stack
实例
import pandas as pd
# 创建宽格式(带列索引)
df = pd.DataFrame({
("A", "X"): [1, 2],
("A", "Y"): [3, 4],
("B", "X"): [5, 6],
("B", "Y"): [7, 8]
})
print("带多层列索引:")
print(df)
print()
# stack 将列索引转为内层索引
print("stack 后:")
print(df.stack())
# 创建宽格式(带列索引)
df = pd.DataFrame({
("A", "X"): [1, 2],
("A", "Y"): [3, 4],
("B", "X"): [5, 6],
("B", "Y"): [7, 8]
})
print("带多层列索引:")
print(df)
print()
# stack 将列索引转为内层索引
print("stack 后:")
print(df.stack())
实战:业务报表转换
实例
import pandas as pd
# 模拟业务数据 - 销售记录
sales = pd.DataFrame({
"日期": ["2024-01"] * 4,
"产品": ["手机", "电脑", "平板", "耳机"],
"渠道": ["线上", "线上", "线下", "线上"],
"销售额": [10000, 20000, 8000, 5000]
})
print("原始销售数据:")
print(sales)
print()
# 使用 pivot 转换
pivot = sales.pivot_table(
index="产品",
columns="渠道",
values="销售额",
aggfunc="sum",
fill_value=0
)
print("渠道销售透视:")
print(pivot)
print()
# 还原为长格式
print("还原为长格式:")
print(pivot.reset_index().melt(id_vars="产品", var_name="渠道", value_name="销售额"))
# 模拟业务数据 - 销售记录
sales = pd.DataFrame({
"日期": ["2024-01"] * 4,
"产品": ["手机", "电脑", "平板", "耳机"],
"渠道": ["线上", "线上", "线下", "线上"],
"销售额": [10000, 20000, 8000, 5000]
})
print("原始销售数据:")
print(sales)
print()
# 使用 pivot 转换
pivot = sales.pivot_table(
index="产品",
columns="渠道",
values="销售额",
aggfunc="sum",
fill_value=0
)
print("渠道销售透视:")
print(pivot)
print()
# 还原为长格式
print("还原为长格式:")
print(pivot.reset_index().melt(id_vars="产品", var_name="渠道", value_name="销售额"))
重塑函数选择
| 函数 | 作用 | 典型场景 |
|---|---|---|
pivot |
长→宽 | 行列转换 |
pivot_table |
长→宽(带聚合) | 有重复值时 |
melt |
宽→长 | 数据整理 |
unstack |
索引→列 | 多层索引 |
stack |
列→索引 | 多层索引 |
数据重塑的目的是为了让数据更适合分析或展示。根据下游需求选择合适的转换方式。
