现在位置: 首页 > Pandas 教程 > 正文

Pandas df.stack() 函数

Pandas 常用函数 Pandas 常用函数


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)

运行结果预期:

=== 原始宽格式数据 ===
      name  Q1   Q2   Q3
0    Alice  100  120  130
1      Bob  150  160  170
2  Charlie  'Q2', 'Q3'], columns=['name', 'quarter', 'sales']
...

代码解析:

  1. 原始数据是宽格式,Q1、Q2、Q3 是三列季度数据。
  2. stack() 将 Q1、Q2、Q3 这三列"堆叠"到行中。
  3. 结果是 Series 类型,包含两层索引:外层是原始行索引,内层是原始列名(季度)。
  4. 堆叠后数据变成了"长格式",每行只有一个季度值。

示例 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)

运行结果预期:

=== 原始数据(多层列索引)===
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)

运行结果预期:

=== 原始数据(包含缺失值)===
   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'))

运行结果预期:

=== unstack + stack 往返 ===
unstack 结果:
       product
North  A          100
       B          150
       C          200
South  A          180
       B          170
...

代码解析:

  • stack() 将列索引转换为行索引,将宽表转为长表。
  • unstack() 将行索引转换为列索引,将长表转为宽表。
  • 两者配合使用可以实现数据的任意形状转换。
  • 对于数据分析来说,理解这两种操作的互逆关系非常重要。

提示: stack()unstack() 是数据重塑的核心工具。stack() 将列"堆"到行中(宽转长),unstack() 将行"拆"到列中(长转宽)。

Pandas 常用函数 Pandas 常用函数