Pandas df.stack() 函数
df.stack() 是 DataFrame 的成员方法,用于将列索引转换为行索引。它将宽格式数据的列"堆叠"到行中,产生一个具有层次化索引的 Series 或 DataFrame。
这是数据重塑的重要操作,通常与 unstack() 配合使用,实现数据的互转。
单词释义: stack 意为"堆叠、堆积",在这里指将列数据"堆叠"到行中,将宽表转为长表。
基本语法与参数
df.stack() 是 DataFrame 的实例方法,通过点运算符调用。
语法格式
DataFrame.stack(level=-1, dropna=True)
参数说明
- 参数:
level- 类型: int、str、int 列表或 str 列表。
- 描述: 指定要堆叠的层级。对于多层索引,可以指定具体的层级编号(从0开始)或层级名称。默认为 -1,表示最内层。
- 参数:
dropna- 类型: 布尔值。
- 描述: 是否删除结果中全为 NaN 的行。默认为 True,即删除包含全为 NaN 值的行。
函数说明
- 返回值: 返回一个 Series 或 DataFrame。如果原始 DataFrame 只有一个列被堆叠,返回 Series;否则返回 DataFrame。
- 效果: 将列索引转换为行索引,产生更长的数据格式。堆叠后的数据是"长格式",便于进行统计分析或可视化。
实例
让我们通过一系列从简单到复杂的例子,彻底掌握 df.stack() 的用法。
示例 1:基础用法 - 将列转为行
实例
import pandas as pd
import numpy as np
# 1. 创建宽格式数据(每个季度一列)
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'Q1': [100, 150, 200],
'Q2': [120, 160, 210],
'Q3': [130, 170, 220]
})
print("=== 原始宽格式数据 ===")
print(df)
print(f"列名: {df.columns.tolist()}")
# 2. 使用 df.stack() 将列转为行
stacked = df.stack()
print("n=== df.stack() 结果 ===")
print(stacked)
print(f"n类型: {type(stacked)}")
# 3. 将结果转换为DataFrame查看
print("n=== 转换为DataFrame ===")
stacked_df = stacked.reset_index()
stacked_df.columns = ['name', 'quarter', 'sales']
print(stacked_df)
import numpy as np
# 1. 创建宽格式数据(每个季度一列)
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'Q1': [100, 150, 200],
'Q2': [120, 160, 210],
'Q3': [130, 170, 220]
})
print("=== 原始宽格式数据 ===")
print(df)
print(f"列名: {df.columns.tolist()}")
# 2. 使用 df.stack() 将列转为行
stacked = df.stack()
print("n=== df.stack() 结果 ===")
print(stacked)
print(f"n类型: {type(stacked)}")
# 3. 将结果转换为DataFrame查看
print("n=== 转换为DataFrame ===")
stacked_df = stacked.reset_index()
stacked_df.columns = ['name', 'quarter', 'sales']
print(stacked_df)
运行结果预期:
=== 原始宽格式数据 ===
name Q1 Q2 Q3
0 Alice 100 120 130
1 Bob 150 160 170
2 Charlie 'Q2', 'Q3'], columns=['name', 'quarter', 'sales']
...
代码解析:
- 原始数据是宽格式,Q1、Q2、Q3 是三列季度数据。
stack()将 Q1、Q2、Q3 这三列"堆叠"到行中。- 结果是 Series 类型,包含两层索引:外层是原始行索引,内层是原始列名(季度)。
- 堆叠后数据变成了"长格式",每行只有一个季度值。
示例 2:多层列索引的堆叠
当 DataFrame 有多层列索引时,可以指定要堆叠的层级。
实例
import pandas as pd
import numpy as np
# 1. 创建具有多层列索引的数据
# 外层:产品类型(Electronics、Furniture)
# 内层:季度(Q1、Q2)
df = pd.DataFrame(
[[100, 110, 200, 210], [150, 160, 180, 190]],
index=['Store_A', 'Store_B'],
columns=pd.MultiIndex.from_tuples([
('Electronics', 'Q1'), ('Electronics', 'Q2'),
('Furniture', 'Q1'), ('Furniture', 'Q2')
], names=['Product', 'Quarter'])
)
print("=== 原始数据(多层列索引)===")
print(df)
print(f"列索引层级: {df.columns.names}")
# 2. 堆叠内层列(默认,level=-1)
print("n=== 堆叠内层列 (level=-1) ===")
stacked_inner = df.stack()
print(stacked_inner)
# 3. 堆叠外层列
print("n=== 堆叠外层列 (level=0) ===")
stacked_outer = df.stack(level=0)
print(stacked_outer)
# 4. 堆叠所有列(产生更长的格式)
print("n=== 堆叠所有列 ===")
stacked_all = df.stack(level=[0, 1])
print(stacked_all)
import numpy as np
# 1. 创建具有多层列索引的数据
# 外层:产品类型(Electronics、Furniture)
# 内层:季度(Q1、Q2)
df = pd.DataFrame(
[[100, 110, 200, 210], [150, 160, 180, 190]],
index=['Store_A', 'Store_B'],
columns=pd.MultiIndex.from_tuples([
('Electronics', 'Q1'), ('Electronics', 'Q2'),
('Furniture', 'Q1'), ('Furniture', 'Q2')
], names=['Product', 'Quarter'])
)
print("=== 原始数据(多层列索引)===")
print(df)
print(f"列索引层级: {df.columns.names}")
# 2. 堆叠内层列(默认,level=-1)
print("n=== 堆叠内层列 (level=-1) ===")
stacked_inner = df.stack()
print(stacked_inner)
# 3. 堆叠外层列
print("n=== 堆叠外层列 (level=0) ===")
stacked_outer = df.stack(level=0)
print(stacked_outer)
# 4. 堆叠所有列(产生更长的格式)
print("n=== 堆叠所有列 ===")
stacked_all = df.stack(level=[0, 1])
print(stacked_all)
运行结果预期:
=== 原始数据(多层列索引)=== Product Electronics Furniture Quarter Q1 Q2 Q1 Q ...
代码解析:
- 多层列索引的 DataFrame,列名是元组形式:(Product, Quarter)。
level=-1(默认)堆叠最内层,即 Quarter 层,结果保留 Product 作为列。level=0堆叠外层,即 Product 层,结果保留 Quarter 作为列。- 这种灵活性允许你根据分析需要选择堆叠的层级。
示例 3:处理缺失值
使用 dropna 参数控制缺失值的处理方式。
实例
import pandas as pd
import numpy as np
# 1. 创建包含缺失值的数据
df = pd.DataFrame({
'name': ['Alice', 'Bob'],
'Math': [100, np.nan],
'English': [90, 85],
'Science': [np.nan, 95]
})
print("=== 原始数据(包含缺失值)===")
print(df)
# 2. dropna=True(默认),删除全为NaN的行
print("n=== dropna=True(默认)===")
stacked_drop = df.stack(dropna=True)
print(stacked_drop)
# 3. dropna=False,保留NaN值
print("n=== dropna=False ===")
stacked_keep = df.stack(dropna=False)
print(stacked_keep)
# 4. 实际应用:将堆叠结果整理成可分析的长格式
print("n=== 整理为长格式DataFrame ===")
result = df.set_index('name').stack().reset_index()
result.columns = ['name', 'subject', 'score']
print(result)
# 5. 删除缺失值
result_clean = result.dropna()
print("n=== 删除缺失值后 ===")
print(result_clean)
import numpy as np
# 1. 创建包含缺失值的数据
df = pd.DataFrame({
'name': ['Alice', 'Bob'],
'Math': [100, np.nan],
'English': [90, 85],
'Science': [np.nan, 95]
})
print("=== 原始数据(包含缺失值)===")
print(df)
# 2. dropna=True(默认),删除全为NaN的行
print("n=== dropna=True(默认)===")
stacked_drop = df.stack(dropna=True)
print(stacked_drop)
# 3. dropna=False,保留NaN值
print("n=== dropna=False ===")
stacked_keep = df.stack(dropna=False)
print(stacked_keep)
# 4. 实际应用:将堆叠结果整理成可分析的长格式
print("n=== 整理为长格式DataFrame ===")
result = df.set_index('name').stack().reset_index()
result.columns = ['name', 'subject', 'score']
print(result)
# 5. 删除缺失值
result_clean = result.dropna()
print("n=== 删除缺失值后 ===")
print(result_clean)
运行结果预期:
=== 原始数据(包含缺失值)===
name Math English Science
0 Alice 100.0 90.0 NaN
1 Bob NaN 85.0 95.0
2=== 堆叠内层列 (level=-1) ===
Store_A Electronics Q1 100
Q2 110
Furniture Q1 200
Q2 210
Store_B Electronics Q1 150
...
代码解析:
dropna=True(默认)会删除所有值都为 NaN 的行。- 在数据分析中,通常需要保留原始数据,然后根据需要删除缺失值。
- 堆叠后使用
reset_index()可以将层次索引转换为普通列,便于后续处理。
示例 4:stack 与 unstack 的配合使用
stack() 和 unstack() 是互逆操作,配合使用可以实现数据的灵活重塑。
实例
import pandas as pd
# 1. 创建初始数据
df = pd.DataFrame({
'product': ['A', 'B', 'C'],
'North': [100, 150, 200],
'South': [180, 170, 160],
'East': [190, 200, 210]
})
print("=== 原始数据 ===")
print(df)
# 2. 使用 unstack 将地区转为列(先转为多层索引)
df_indexed = df.set_index('product')
print("n=== 设置索引后 ===")
print(df_indexed)
# 3. 使用 stack 将列转为行(stack是unstack的逆操作)
print("n=== unstack + stack 往返 ===")
# 先 unstack
unstacked = df_indexed.unstack()
print("unstack 结果:")
print(unstacked)
# 再 stack 回来
restacked = unstacked.stack()
print("nstack 回来:")
print(restacked)
# 4. 完整示例:创建多层索引然后转换
print("n=== 多层索引转换 ===")
# 创建多层索引DataFrame
multi_df = pd.DataFrame(
[[100, 110], [150, 160]],
index=pd.MultiIndex.from_tuples([('A', '2023'), ('B', '2023')], names=['product', 'year']),
columns=['North', 'South']
)
print("原始多层索引数据:")
print(multi_df)
# unstack year
print("nunstack year:")
print(multi_df.unstack(level='year'))
# unstack columns
print("nunstack columns (转为列):")
print(multi_df.unstack(level='columns'))
# 1. 创建初始数据
df = pd.DataFrame({
'product': ['A', 'B', 'C'],
'North': [100, 150, 200],
'South': [180, 170, 160],
'East': [190, 200, 210]
})
print("=== 原始数据 ===")
print(df)
# 2. 使用 unstack 将地区转为列(先转为多层索引)
df_indexed = df.set_index('product')
print("n=== 设置索引后 ===")
print(df_indexed)
# 3. 使用 stack 将列转为行(stack是unstack的逆操作)
print("n=== unstack + stack 往返 ===")
# 先 unstack
unstacked = df_indexed.unstack()
print("unstack 结果:")
print(unstacked)
# 再 stack 回来
restacked = unstacked.stack()
print("nstack 回来:")
print(restacked)
# 4. 完整示例:创建多层索引然后转换
print("n=== 多层索引转换 ===")
# 创建多层索引DataFrame
multi_df = pd.DataFrame(
[[100, 110], [150, 160]],
index=pd.MultiIndex.from_tuples([('A', '2023'), ('B', '2023')], names=['product', 'year']),
columns=['North', 'South']
)
print("原始多层索引数据:")
print(multi_df)
# unstack year
print("nunstack year:")
print(multi_df.unstack(level='year'))
# unstack columns
print("nunstack columns (转为列):")
print(multi_df.unstack(level='columns'))
运行结果预期:
=== unstack + stack 往返 ===
unstack 结果:
product
North A 100
B 150
C 200
South A 180
B 170
...
代码解析:
stack()将列索引转换为行索引,将宽表转为长表。unstack()将行索引转换为列索引,将长表转为宽表。- 两者配合使用可以实现数据的任意形状转换。
- 对于数据分析来说,理解这两种操作的互逆关系非常重要。
提示:
stack()和unstack()是数据重塑的核心工具。stack()将列"堆"到行中(宽转长),unstack()将行"拆"到列中(长转宽)。

Pandas 常用函数