数据重塑 #

数据重塑概述 #

数据重塑是改变数据形状和结构的操作,在数据清洗和分析中非常常用。

text
┌─────────────────────────────────────────────────────────────┐
│                    数据重塑方法                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  长格式 → 宽格式                                            │
│  ├── pivot()        透视                                    │
│  ├── pivot_table()  聚合透视                                │
│  └── unstack()      展开多层索引                            │
│                                                             │
│  宽格式 → 长格式                                            │
│  ├── melt()         熔化                                    │
│  └── stack()        堆叠                                    │
│                                                             │
│  其他操作                                                   │
│  ├── transpose()    转置                                    │
│  └── T              转置属性                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

准备数据 #

python
import pandas as pd
import numpy as np

# 长格式数据
df_long = pd.DataFrame({
    'date': ['2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02'],
    'city': ['Beijing', 'Shanghai', 'Beijing', 'Shanghai'],
    'temperature': [5, 10, 6, 12],
    'humidity': [30, 40, 35, 45]
})

print("长格式数据:")
print(df_long)

# 宽格式数据
df_wide = pd.DataFrame({
    'date': ['2024-01-01', '2024-01-02', '2024-01-03'],
    'Beijing_temp': [5, 6, 7],
    'Shanghai_temp': [10, 12, 14],
    'Beijing_humidity': [30, 35, 32],
    'Shanghai_humidity': [40, 45, 42]
})

print("\n宽格式数据:")
print(df_wide)

pivot - 透视 #

pivot 将长格式数据转换为宽格式。

python
# 基本透视
result = df_long.pivot(index='date', columns='city', values='temperature')
print(result)
# city       Beijing  Shanghai
# date                         
# 2024-01-01        5        10
# 2024-01-02        6        12

# 多值透视
result = df_long.pivot(index='date', columns='city')
print(result)
#            temperature      humidity     
# city          Beijing Shanghai Beijing Shanghai
# date                                          
# 2024-01-01          5       10      30       40
# 2024-01-02          6       12      35       45

# 透视后选择特定值
result = df_long.pivot(index='date', columns='city', values=['temperature', 'humidity'])
print(result['temperature'])

pivot 注意事项 #

python
# 如果有重复值,pivot 会报错
df_dup = pd.DataFrame({
    'date': ['2024-01-01', '2024-01-01', '2024-01-01'],
    'city': ['Beijing', 'Beijing', 'Shanghai'],
    'temp': [5, 6, 10]
})

# 这会报错
# df_dup.pivot(index='date', columns='city', values='temp')
# ValueError: Index contains duplicate entries

# 使用 pivot_table 替代
result = df_dup.pivot_table(index='date', columns='city', values='temp', aggfunc='mean')
print(result)

pivot_table - 聚合透视 #

pivot_table 可以处理重复值,并支持聚合函数。

python
# 创建有重复值的数据
df = pd.DataFrame({
    'date': ['2024-01-01', '2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02'],
    'city': ['Beijing', 'Beijing', 'Shanghai', 'Beijing', 'Shanghai'],
    'temperature': [5, 7, 10, 6, 12]
})

# 使用均值聚合
result = df.pivot_table(index='date', columns='city', values='temperature', aggfunc='mean')
print(result)
# city       Beijing  Shanghai
# date                         
# 2024-01-01      6.0      10.0
# 2024-01-02      6.0      12.0

# 多种聚合函数
result = df.pivot_table(index='date', columns='city', values='temperature', 
                         aggfunc=['mean', 'min', 'max', 'count'])
print(result)

# 多值聚合
result = df.pivot_table(index='date', columns='city', 
                         values=['temperature', 'humidity'],
                         aggfunc='mean')

# 添加汇总
result = df.pivot_table(index='date', columns='city', values='temperature',
                         aggfunc='mean', margins=True)

# 填充缺失值
result = df.pivot_table(index='date', columns='city', values='temperature',
                         aggfunc='mean', fill_value=0)

melt - 熔化 #

melt 将宽格式数据转换为长格式。

python
# 基本熔化
result = df_wide.melt(id_vars='date')
print(result)
#          date      variable  value
# 0  2024-01-01   Beijing_temp      5
# 1  2024-01-02   Beijing_temp      6
# 2  2024-01-03   Beijing_temp      7
# 3  2024-01-01  Shanghai_temp     10
# ...

# 指定值列
result = df_wide.melt(id_vars='date', value_vars=['Beijing_temp', 'Shanghai_temp'])
print(result)

# 自定义列名
result = df_wide.melt(id_vars='date', 
                       var_name='city_metric', 
                       value_name='value')
print(result)

# 分割变量名
result = df_wide.melt(id_vars='date')
result[['city', 'metric']] = result['variable'].str.split('_', expand=True)
print(result)

melt 实用技巧 #

python
# 部分列熔化
result = df_wide.melt(id_vars='date', 
                       value_vars=['Beijing_temp', 'Shanghai_temp'],
                       var_name='city_temp',
                       value_name='temperature')
print(result)

# 保留特定列
result = df_wide.melt(id_vars=['date'], 
                       value_vars=['Beijing_temp', 'Shanghai_humidity'])
print(result)

stack 和 unstack #

stack - 堆叠 #

stack 将列"堆叠"为行,使数据变长。

python
df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': [4, 5, 6],
    'C': [7, 8, 9]
}, index=['x', 'y', 'z'])

# 堆叠
result = df.stack()
print(result)
# x  A    1
#    B    4
#    C    7
# y  A    2
#    B    5
#    C    8
# z  A    3
#    B    6
#    C    7
# dtype: int64

# 堆叠多层索引 DataFrame
df_multi = pd.DataFrame(
    np.random.randn(3, 4),
    columns=pd.MultiIndex.from_product([['A', 'B'], ['x', 'y']])
)
result = df_multi.stack()
print(result)

unstack - 展开 #

unstack 将行"展开"为列,使数据变宽。

python
# 创建多层索引
index = pd.MultiIndex.from_product([['2024-01-01', '2024-01-02'], 
                                     ['Beijing', 'Shanghai']])
df = pd.DataFrame({'temperature': [5, 10, 6, 12]}, index=index)

# 展开
result = df.unstack()
print(result)
#           temperature      
# city          Beijing Shanghai
# date                          
# 2024-01-01         5       10
# 2024-01-02         6       12

# 展开指定层
result = df.unstack(level=0)
print(result)

# 填充缺失值
result = df.unstack(fill_value=0)

stack/unstack 配合使用 #

python
# stack 后 unstack 可以恢复
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
stacked = df.stack()
unstacked = stacked.unstack()
print(unstacked.equals(df))  # True

transpose - 转置 #

python
df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': [4, 5, 6]
})

# 转置
result = df.transpose()
print(result)
#    0  1  2
# A  1  2  3
# B  4  5  6

# 使用 T 属性
result = df.T
print(result)

实用案例 #

长宽格式转换 #

python
# 长格式 → 宽格式
df_long = pd.DataFrame({
    'year': [2020, 2020, 2021, 2021],
    'quarter': ['Q1', 'Q2', 'Q1', 'Q2'],
    'sales': [100, 150, 120, 180]
})

df_wide = df_long.pivot(index='year', columns='quarter', values='sales')
print(df_wide)

# 宽格式 → 长格式
df_wide = pd.DataFrame({
    'year': [2020, 2021],
    'Q1': [100, 120],
    'Q2': [150, 180]
})

df_long = df_wide.melt(id_vars='year', var_name='quarter', value_name='sales')
print(df_long)

多变量重塑 #

python
# 多变量数据
df = pd.DataFrame({
    'date': ['2024-01-01', '2024-01-02'],
    'Beijing_temp': [5, 6],
    'Beijing_humidity': [30, 35],
    'Shanghai_temp': [10, 12],
    'Shanghai_humidity': [40, 45]
})

# 熔化并分割变量
result = df.melt(id_vars='date')
result[['city', 'metric']] = result['variable'].str.split('_', expand=True)
result = result.pivot_table(index=['date', 'city'], columns='metric', values='value').reset_index()
print(result)

时间序列重塑 #

python
# 时间序列数据
dates = pd.date_range('2024-01-01', periods=6, freq='D')
df = pd.DataFrame({
    'date': dates,
    'value': np.random.randn(6)
})

# 添加年月列
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day

# 透视为月度表格
result = df.pivot_table(index='month', columns='day', values='value')
print(result)

重塑方法选择指南 #

text
┌─────────────────────────────────────────────────────────────┐
│                    重塑方法选择                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  场景                      推荐方法                         │
│  ────────────────────────  ────────────────────────────    │
│  长格式 → 宽格式(无重复)  df.pivot()                       │
│  长格式 → 宽格式(有重复)  df.pivot_table()                 │
│  宽格式 → 长格式            df.melt()                       │
│  多层索引展开              df.unstack()                     │
│  列转行                    df.stack()                       │
│  行列互换                  df.T 或 df.transpose()           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

下一步 #

掌握了数据重塑后,接下来学习 时间序列,深入了解 Pandas 的时间序列处理功能!

最后更新:2026-04-04