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

Pandas df.unstack() 函数

Pandas 常用函数 Pandas 常用函数


df.unstack() 是 DataFrame 的成员方法,用于将行索引转换为列索引。它将具有层次化索引的数据"展开",将行级别的一个或多个层级移动到列中。

这是数据重塑的重要操作,通常与 stack() 配合使用,实现数据的互转。

单词释义unstack 意为"拆开、展开",在这里指将行索引"展开"为列,将长表转为宽表。


基本语法与参数

df.unstack() 是 DataFrame 的实例方法,通过点运算符调用。

语法格式

DataFrame.unstack(level=-1, fill_value=None)

参数说明

  • 参数level
    • 类型: int、str、int 列表或 str 列表。
    • 描述: 指定要展开到列的层级。对于多层索引,可以指定具体的层级编号(从0开始)或层级名称。默认为 -1,表示最内层。
  • 参数fill_value
    • 类型: 标量或 None。
    • 描述: 用于填充因 unstack 操作产生的缺失值的数值。默认为 None,保留 NaN。

函数说明

  • 返回值: 返回一个 Series 或 DataFrame。如果原始 DataFrame 只有一个行层级被展开,返回 Series;否则返回 DataFrame。
  • 效果: 将行索引的一个或多个层级移动到列索引,产生更宽的数据格式。展开后的数据是"宽格式",便于查看和比较。

实例

让我们通过一系列从简单到复杂的例子,彻底掌握 df.unstack() 的用法。

示例 1:基础用法 - 将行转为列

实例

import pandas as pd

# 1. 创建长格式数据
df = pd.DataFrame({
    'product': ['A', 'A', 'B', 'B', 'C', 'C'],
    'region': ['North', 'South', 'North', 'South', 'North', 'South'],
    'sales': [100, 150, 200, 180, 220, 250]
})

print("=== 原始长格式数据 ===")
print(df)

# 2. 设置层次化索引
df_indexed = df.set_index(['product', 'region'])
print("n=== 设置层次化索引后 ===")
print(df_indexed)

# 3. 使用 df.unstack() 将内层索引转为列
unstacked = df_indexed.unstack()
print("n=== df.unstack() 结果 ===")
print(unstacked)

# 4. 简化查看
print("n=== 只看销售额 ===")
print(unstacked['sales'])

运行结果预期:

=== 原始长格式数据 ===
  product region  sales
0       A  North    100
1       A  South    150
2       B  North    200
3       B  South    180
4       C  North    220
5       C  South    250
n=== 设置层次化索引后 ===
                sales
product region       
A       North     100
        South     150
B       North     200
        South     180
C       North     220
        South     250
n=== df.unstack() 结果 ===
        sales      
region  North South
product            
A         100   150
B         200   180
C         220   250
n=== 只看销售额 ===
region   North  South
product              
A          100    150
B          200    180
C          220    250

代码解析:

  1. 原始数据是长格式,每行记录一个产品在某地区的销售额。
  2. 使用 set_index() 创建层次化索引(product 为外层,region 为内层)。
  3. unstack() 将内层索引 region 移动到列位置。
  4. 结果是宽格式,可以直观比较不同产品在不同地区的销售数据。

示例 2:多层索引的展开

当 DataFrame 有多层行索引时,可以指定要展开的层级。

实例

import pandas as pd

# 1. 创建具有多层行索引的数据
df = pd.DataFrame({
    'year': [2023, 2023, 2023, 2023, 2024, 2024, 2024, 2024],
    'quarter': ['Q1', 'Q1', 'Q2', 'Q2', 'Q1', 'Q1', 'Q2', 'Q2'],
    'product': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B'],
    'sales': [100, 150, 200, 180, 220, 250, 230, 270]
})

print("=== 原始数据 ===")
print(df)

# 2. 设置多层索引
df_indexed = df.set_index(['year', 'quarter', 'product'])
print("n=== 设置多层索引 ===")
print(df_indexed)

# 3. 展开最内层(product,默认 level=-1)
print("n=== 展开 product 层(默认)===")
unstacked_inner = df_indexed.unstack()
print(unstacked_inner['sales'])

# 4. 展开中间层(quarter)
print("n=== 展开 quarter 层 ===")
unstacked_quarter = df_indexed.unstack(level='quarter')
print(unstacked_quarter['sales'])

# 5. 展开外层(year)
print("n=== 展开 year 层 ===")
unstacked_year = df_indexed.unstack(level='year')
print(unstacked_year['sales'])

# 6. 同时展开多个层级
print("n=== 同时展开 year 和 product ===")
unstacked_multi = df_indexed.unstack(level=['year', 'product'])
print(unstacked_multi['sales'])

运行结果预期:

=== 原始数据 ===
   year quarter product  sales
0  2023      Q1       A    100
1  2023      Q1       B    150
2  2023      Q2       A    200
3  2023      Q2       B    180
4  2024      Q1       A    220
5  2024      Q1       B    250
6  2024      Q2       A    230
7  2024      Q2       B    270
n=== 设置多层索引 ===
                      sales
year quarter product       
2023 Q1      A          100
             B          150
     Q2      A          200
             B          180
2024 Q1      A          220
             B          250
     Q2      A          230
             B          270
n=== 展开 product 层(默认)===
product         A    B
year quarter          
2023 Q1       100  150
     Q2       200  180
2024 Q1       220  250
     Q2       230  270
n=== 展开 quarter 层 ===
quarter        Q1   Q2
year product          
2023 A        100  200
     B        150  180
2024 A        220  230
     B        250  270
n=== 展开 year 层 ===
year             2023  2024
quarter product            
Q1      A         100   220
        B         150   250
Q2      A         200   230
        B         180   270
n=== 同时展开 year 和 product ===
year    2023      2024     
product    A    B    A    B
quarter                    
Q1       100  150  220  250
Q2       200  180  230  270

代码解析:

  • 多层索引的 DataFrame,可以使用 level 参数指定展开哪个层级。
  • 默认 level=-1 展开最内层(product)。
  • 展开不同层级会产生不同的数据布局,便于从不同角度分析数据。

示例 3:使用 fill_value 处理缺失值

使用 fill_value 参数可以填充 unstack 后产生的缺失值。

实例

import pandas as pd
import numpy as np

# 1. 创建不完整的数据(不是所有产品-地区组合都有数据)
df = pd.DataFrame({
    'product': ['A', 'A', 'B', 'C'],
    'region': ['North', 'South', 'North', 'East'],
    'sales': [100, 150, 200, 220]
})

print("=== 原始数据(不完整)===")
print(df)

# 2. 创建层次化索引并 unstack
df_indexed = df.set_index(['product', 'region'])
print("n=== 层次化索引 ===")
print(df_indexed)

# 3. 不填充缺失值
print("n=== 不填充缺失值 ===")
unstacked = df_indexed.unstack()
print(unstacked)
print(f"缺失值数量: {unstacked['sales'].isna().sum().sum()}")

# 4. 使用 fill_value=0 填充缺失值
print("n=== fill_value=0 ===")
unstacked_fill = df_indexed.unstack(fill_value=0)
print(unstacked_fill)
print(f"缺失值数量: {unstacked_fill['sales'].isna().sum().sum()}")

运行结果预期:

=== 原始数据(不完整)===
  product region  sales
0       A  North    100
1       A  South    150
2       B  North    200
3       C   East    220
n=== 层次化索引 ===
                sales
product region       
A       North     100
        South     150
B       North     200
C       East      220
n=== 不填充缺失值 ===
         sales              
region    East  North  South
product                     
A          NaN  100.0  150.0
B          NaN  200.0    NaN
C        220.0    NaN    NaN
缺失值数量: 5
n=== fill_value=0 ===
        sales            
region   East North South
product                  
A           0   100   150
B           0   200     0
C         220     0     0
缺失值数量: 0

代码解析:

  • 当原始数据不完整时,unstack 会产生缺失值(NaN)。
  • 使用 fill_value 参数可以指定填充值,避免后续计算出错。
  • 通常填充为 0 表示"无数据"或"不存在该组合"。

示例 4:unstack 与 stack 的配合使用

unstack()stack() 是互逆操作,配合使用可以实现数据的灵活重塑。

实例

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. 先 stack 转为长格式
print("n=== step 1: stack 转为长格式 ===")
stacked = df.set_index('product').stack()
print(stacked)

# 3. 再 unstack 回来(验证可逆性)
print("n=== step 2: unstack 转回宽格式 ===")
restored = stacked.unstack()
print(restored)

# 4. 实战:重新排列数据
print("n=== 实战:将 region 移到列 ===")
# 原始:product 为行索引,region 为列
# 目标:region 为行索引,product 为列
result = df.set_index('product').unstack().unstack(level=-1)
print(result)

# 5. 使用 reorder_levels 调整层级顺序
print("n=== 使用 reorder_levels 调整层级 ===")
# 创建双层索引
df_multi = pd.DataFrame(
    [[100, 200], [150, 180], [190, 210]],
    index=pd.MultiIndex.from_tuples([
        ('A', 'North'), ('B', 'North'), ('C', 'North')
    ], names=['product', 'region']),
    columns=['2023', '2024']
)
print("原始数据:")
print(df_multi)

# 调整层级顺序
print("n调整后(年份在外层):")
print(df_multi.unstack(level='region'))

运行结果预期:

=== 原始宽格式数据 ===
  product  North  South  East
0       A    100    180   190
1        B    150    170 
...

代码解析:

  • stack()unstack() 是一对互逆操作。
  • 先 stack 再 unstack,理论上可以恢复到原始形状(忽略填充值差异)。
  • 可以通过不同的 level 组合实现不同的数据布局。
  • 在实际数据分析中,经常需要反复调整数据形状以适应不同的分析需求。

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

Pandas 常用函数 Pandas 常用函数