一句话总结
stack()将列索引旋转为行索引(宽表变长表),unstack()将行索引旋转为列索引(长表变宽表)。两者是处理 MultiIndex 时最常用的重塑工具。
1. stack() — 堆叠(列 → 行)
将 DataFrame 的列索引旋转为最内层行索引,返回 Series 或 DataFrame。
基本语法
DataFrame.stack(level=-1, dropna=_NoDefault.no_default, sort=_NoDefault.no_default, future_stack=False)| 参数 | 说明 |
|---|---|
level | 指定要堆叠的列索引层级。默认为 -1(最内层);可传 int、str 或列表 |
dropna | 是否删除结果为 NaN 的行。默认为 True(v2.0 起由 future_stack 控制) |
sort | 是否对结果索引排序,默认 False |
示例:基本堆叠
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': [1, 2],
'B': [3, 4]
}, index=['x', 'y'])
stacked = df.stack()
print(stacked)
# x A 1
# B 3
# y A 2
# B 4
# dtype: int64示例:多层列索引
cols = pd.MultiIndex.from_tuples([('class1', 'A'), ('class1', 'B'),
('class2', 'A'), ('class2', 'B')])
df_multi = pd.DataFrame(np.random.rand(3, 4), columns=cols, index=['r1', 'r2', 'r3'])
# 默认堆叠最内层('A'/'B')
df_multi.stack()
# 指定 level=0,堆叠 'class1'/'class2'
df_multi.stack(level=0)示例:dropna 参数
df_with_na = pd.DataFrame({
'A': [1.0, np.nan],
'B': [3.0, 4.0]
}, index=['x', 'y'])
df_with_na.stack(dropna=True) # 删除 NaN 行
df_with_na.stack(dropna=False) # 保留 NaN 行2. unstack() — 取消堆叠(行 → 列)
将行索引旋转为列索引,是 stack() 的逆操作。
基本语法
DataFrame.unstack(level=-1, fill_value=None, sort=True)| 参数 | 说明 |
|---|---|
level | 指定要取消堆叠的行索引层级。默认为 -1(最内层);可传 int、str 或列表 |
fill_value | 若结果中存在缺失值,用该值填充(可用于处理多重索引组合无数据的情况) |
sort | 是否对结果列索引排序,默认 True |
示例:基本取消堆叠
s = pd.Series([1, 2, 3, 4], index=pd.MultiIndex.from_product([['x', 'y'], ['A', 'B']]))
print(s.unstack())
# A B
# x 1 2
# y 3 4示例:fill_value 参数
idx = pd.MultiIndex.from_tuples([('x', 'A'), ('x', 'B'), ('y', 'B')])
s = pd.Series([1, 2, 3], index=idx)
s.unstack(fill_value=0)
# A B
# x 1 2
# y 0 3 ← 缺失的 ('y', 'A') 被填充为 03. 多层索引的灵活操作
堆叠 / 取消堆叠多层索引的部分层级
df = pd.DataFrame(np.arange(8).reshape(2, 4),
index=pd.MultiIndex.from_product([['a', 'b'], ['one', 'two']]),
columns=pd.MultiIndex.from_product([['x', 'y'], ['i', 'j']]))
# 取消最内层行索引
df.unstack()
# 取消指定层(如第 0 层)
df.unstack(level=0)
# 同时取消多层
df.unstack(level=[0, 1])多层索引堆叠后再恢复
stacked = df.stack() # 列 → 行
restored = stacked.unstack() # 行 → 列(逆操作)使用 level 参数指定具体层级
# 堆叠 'class1'/'class2' 这一层(level=0)
df_multi.stack(level=0)
# 取消堆叠指定名称的行索引层
df_unstacked = df.unstack(level='color')4. 用例:长宽格式互转
# 宽表 → 长表(stack)
wide = pd.DataFrame({'2023': [100, 200], '2024': [150, 250]}, index=['A', 'B'])
long_df = wide.stack().reset_index(name='value')
long_df.columns = ['item', 'year', 'value']
# 长表 → 宽表(unstack)
wide_again = long_df.set_index(['item', 'year'])['value'].unstack()5. 注意事项
易混淆点
stack()返回 Series(若所有列堆叠后仅剩一个值列);unstack()通常返回 DataFrame。stack()默认dropna=True,会静默删除缺失值;若需保留应设置dropna=False。- 对于无 MultiIndex 的普通 DataFrame,
unstack()会将普通行索引转为列索引。
记忆技巧
- Stack(堆叠):像把盘子叠起来,列 → 行,数据变”瘦高”。
- Unstack(取消堆叠):把叠起来的盘子摊开,行 → 列,数据变”矮胖”。