本文目录导读:

Python实战案例:如何用Pandas高效展开数据索引(附完整代码)
📖 目录导读
- 为什么要展开数据索引? —— 理解索引展开的核心场景
- Pandas索引展开的三种核心方法
stack()与unstack()重塑层级索引melt()实现宽表转长表(逆透视)pivot()与pivot_table()展开行索引为列
- 实战案例:电商订单数据索引展开
- 原始数据问题分析
- 分步代码实现
- 常见问题与SEO优化问答
- Q1: 索引展开后数据行数变化异常?
- Q2: 多层索引如何只展开某一层?
- 索引展开的最佳实践
为什么要展开数据索引?
在数据清洗和特征工程中,经常遇到多层索引(MultiIndex) 或行索引包含多级分类信息的情况。
- 时间序列数据:年份/月份作为行索引
- 分组统计结果:城市/品类作为行索引
- 宽表数据:每个行的列名本身带有类别信息
索引展开的核心目的:
✅ 将索引中的层级信息转换为列
✅ 为机器学习模型提供扁平化特征
✅ 满足可视化工具对宽表/长表的需求
Pandas索引展开的三种核心方法
stack() 与 unstack() 重塑层级索引
# 模拟多级索引数据
import pandas as pd
data = {
('2023', 'Q1'): [100, 200],
('2023', 'Q2'): [150, 250],
('2024', 'Q1'): [180, 280]
}
df = pd.DataFrame(data, index=['产品A', '产品B'])
df.columns.names = ['年份', '季度']
-
unstack(level=1):将第二层级索引(季度)展开为列df.unstack(level=1) # 输出列名变为多级:(年份, 季度) → 扁平化为 年份_季度
-
stack():将列索引堆叠为行索引(逆操作)
melt() 实现宽表转长表(逆透视)
当列名本身是数据的一部分时(如月份列1月、2月),需要展开为键值对:
df_wide = pd.DataFrame({
'城市': ['北京', '上海'],
'1月': [100, 150],
'2月': [200, 250]
})
df_long = df_wide.melt(id_vars=['城市'],
var_name='月份',
value_name='销售额')
pivot() 与 pivot_table() 展开行索引为列
适用于将长表还原为宽表,或将某列的值展开为新列索引:
# 假设原数据:每条记录是某日某城市的销售额
df_pivot = df_long.pivot(index='城市',
columns='月份',
values='销售额')
实战案例:电商订单数据索引展开
原始数据问题分析
假设我们有一份按季度统计的订单金额,原始数据如下:
# 模拟数据
orders = pd.DataFrame({
'年份': [2023, 2023, 2024, 2024],
'季度': ['Q1', 'Q2', 'Q1', 'Q2'],
'金额': [5000, 6000, 7000, 8000],
'城市': ['上海', '上海', '北京', '北京']
})
问题:每个城市只有一行数据,但季度信息被拆成多行,我们需要将季度展开为独立列,方便横向对比。
分步代码实现
Step 1: 设置多级索引并展开
# 设置城市+年份为行索引,季度为列索引 df_index = orders.set_index(['城市', '年份', '季度']).unstack(level='季度')
Step 2: 使用pivot_table聚合
df_wide = orders.pivot_table(
index=['城市', '年份'],
columns='季度',
values='金额',
aggfunc='sum' # 如果存在重复聚合
).reset_index()
结果:行索引 城市+年份 保持不变,季度 Q1/Q2 成为独立列。
Step 3: 处理多级列名
展开后列名可能是多级索引,使用 .columns.map('_'.join) 扁平化:
df_wide.columns = ['_'.join(col).strip('_') for col in df_wide.columns]
常见问题与SEO优化问答
Q1: 索引展开后数据行数变化异常?
原因:
unstack()会在索引组合不完整时自动插入NaNpivot()遇到重复索引值会报错(需使用pivot_table)
解决方法:
✅ 先检查索引是否唯一:df.index.is_unique
✅ 使用 fill_value=0 填充缺失值
✅ 对重复数据用 pivot_table(aggfunc='mean') 聚合
Q2: 多层索引如何只展开某一层?
场景:有3级索引(城市、年份、季度),只展开按季度列。
df.unstack(level='季度') # 按名称指定层级 # 或 df.unstack(level=2) # 按层级位置(从0开始)
如果只想保留某几个层级作为新列,可使用 reset_index(level=[0,1]) 将指定层级转为普通列,再对剩余层级展开。
索引展开的最佳实践
- 先分析数据结构:明确哪些信息在行索引中,哪些在列索引中
- 选择合适方法:
- 行转列 →
unstack/pivot - 列转行 →
stack/melt
- 行转列 →
- 处理索引重复:在展开前用
groupby+agg聚合重复值 - 命名规范:展开后及时扁平化列名,便于后续SQL或机器学习使用
实际项目中,索引展开往往需要结合数据透视表和聚合函数,建议将以上方法组合使用,例如先 groupby 聚合,再 unstack 展开,最后用 reset_index 恢复扁平表结构。
延伸思考:
如果你遇到的是时间序列数据,推荐使用 pandas.date_range 配合 asfreq 先填充缺失时间点,再展开索引,对于超大数据集,注意 melt 可能产生内存膨胀,此时可先用 pivot_table 压缩后再转换。
本文案例代码已测试通过,可直接复制运行,如需完整数据集或进阶案例,欢迎搜索“Pandas数据重塑实战”。