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

Pandas pd.melt() 函数

Pandas 常用函数 Pandas 常用函数


pd.melt() 是 Pandas 库的顶级函数,用于宽表转长表。它将包含多个列的宽格式数据"融化"为长格式,类似于 Excel 中的逆透视操作。

这是数据重塑中最常用的函数之一,特别是在数据可视化之前需要将数据转换为长格式,或者将多列合并为一列时非常有用。

单词释义melt 意为"融化、熔化",在这里指将宽表结构"融化"为长表结构,类似将多列数据聚拢在一起。


基本语法与参数

pd.melt() 是 Pandas 库的顶级函数,用于将宽格式数据转换为长格式。

语法格式

pd.melt(frame, id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None)

参数说明

  • 参数frame
    • 类型: DataFrame。
    • 描述: 必填参数。源数据 DataFrame,即要进行宽转长的数据。
  • 参数id_vars
    • 类型: 列名、元组列表或 None。
    • 描述: 用作标识符(ID)的列,这些列在转换后保持不变。可以是单个列名或列名列表。不指定时,所有列都会被视为 value_vars。
  • 参数value_vars
    • 类型: 列名、元组列表或 None。
    • 描述: 要"融化"的列,即将哪些列转换为行。如果不指定,则除 id_vars 外的所有列都会被转换。
  • 参数var_name
    • 类型: 字符串或 None。
    • 描述: 生成的新列名,用于存储原始列名。默认为 'variable'。
  • 参数value_name
    • 类型: 字符串。
    • 描述: 生成的值列名。默认为 'value'。
  • 参数col_level
    • 类型: int、str 或 None。
    • 描述: 如果列是 MultiIndex(多层索引),指定要融化的层级。

函数说明

  • 返回值: 返回一个 DataFrame,数据从宽格式转换为长格式。
  • 效果: 将多个列的值"融化"到两列中:一列存储原始列名(variable),一列存储对应的值(value)。

实例

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

示例 1:基础用法 - 简单的宽表转长表

实例

import pandas as pd

# 1. 创建宽格式数据(每个季度一列)
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'Q1_sales': [100, 150, 200],
    'Q2_sales': [120, 160, 210],
    'Q3_sales': [130, 170, 220]
})

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

# 2. 使用 pd.melt() 转换为长格式
melted = pd.melt(df, id_vars=['name'], value_vars=['Q1_sales', 'Q2_sales', 'Q3_sales'])
print("n=== pd.melt() 转换为长格式 ===")
print(melted)

# 3. 自定义列名
melted_custom = pd.melt(
    df,
    id_vars=['name'],
    value_vars=['Q1_sales', 'Q2_sales', 'Q3_sales'],
    var_name='quarter',
    value_name='sales'
)
print("n=== 自定义列名 ===")
print(melted_custom)

运行结果预期:

=== 原始宽格式数据 ===
      name  Q1_sales  Q2_sales  Q3_sales
0    Alice      100      120      130
1     Bob      150      160      170
2  Charlie      200      210      220

=== pd.melt() 转换为长格式 ===
      name    variable  value
0    Alice   Q1_sales    100
1     Bob   Q1_sales    150
2  Charlie  Q1_sales    200
3    Alice   Q2_sales    120
4     Bob   Q2_sales    160
5  Charlie  Q2_sales    210
6    Alice   Q3_sales    130
7     Bob   Q3_sales    170
8  Charlie  Q3_sales    220

=== 自定义列名 ===
      name  quarter  sales
0    Alice  Q1_sales    100
1     Bob  Q1_sales    150
2  Charlie  Q1_sales    200
3    Alice  Q2_sales    200

代码解析:

  1. 原始数据是宽格式,每行一个人,Q1、Q2、Q3 是三个季度的销售数据列。
  2. id_vars=['name'] 指定 name 列保持不变,作为标识符。
  3. value_vars=['Q1_sales', 'Q2_sales', 'Q3_sales'] 指定要融化的列。
  4. 结果中新增了 variable 列(存储原始列名)和 value 列(存储对应值)。
  5. 使用 var_namevalue_name 可以自定义新列的名称。

示例 2:不指定 value_vars - 融化除 id_vars 外的所有列

不指定 value_vars 时,会自动融化除 id_vars 外的所有列。

实例

import pandas as pd

# 1. 创建包含更多列的数据
df = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie'],
    'math': [90, 85, 92],
    'english': [88, 90, 87],
    'science': [95, 88, 91]
})

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

# 2. 只指定 id_vars,自动融化其他所有列
melted = pd.melt(df, id_vars=['id', 'name'])
print("n=== 融化所有非id列 ===")
print(melted)

# 3. 多个 id_vars 的情况
print("n=== 多个 id_vars ===")
melted_multi = pd.melt(df, id_vars=['name'], value_vars=['math', 'english', 'science'])
print(melted_multi)

# 4. 只使用一个 id_vars
print("n=== 一个 id_vars ===")
melted_one = pd.melt(df, id_vars=['id'])
print(melted_one)

运行结果预期:

=== 原始数据 ===
   id     name  math  english  science
0   1    Alice     90      88      95
1   2     Bob     85      90      88
2   3  Charlie    92      87      91

=== 融化所有非id列 ===
   id     name   variable  value
0   1    Alice      math     90
1   2       Bob     math     85
2   3  Charlie    math     92
3   1    Alice   english     88
4   2       融化为两列(variable 和 value)。

- 不指定 value_vars 时,系统会自动识别并熔化除 id_vars 外的所有列
- id_vars 可以是单个列或多个列的组合

代码解析:

  • 不指定 value_vars 时,会自动融化除 id_vars 之外的所有列。
  • 当只有 id_vars 而无 value_vars 时,每个数据行会按 value_vars 的数量产生相应数量的新行。
  • 这种方法在需要将多列数据统一处理时非常方便。

示例 3:没有 id_vars - 融化所有列

当不指定 id_vars 时,原始数据的索引会作为标识符。

实例

import pandas as pd

# 1. 创建数据(没有明确的 id 列)
df = pd.DataFrame({
    'Q1': [100, 150, 200],
    'Q2': [120, 160, 210],
    'Q3': [130, 170, 220]
})

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

# 2. 不指定 id_vars,使用默认索引
melted = pd.melt(df)
print("n=== 不指定 id_vars ===")
print(melted)

# 3. 恢复原始索引
print("n=== 重置索引 ===")
melted_with_index = pd.melt(df, ignore_index=False)
print(melted_with_index)

# 4. 实用案例:创建标识符
df_with_id = pd.DataFrame({
    'year': [2023, 2023, 2023],
    'Q1': [100, 150, 200],
    'Q2': [120, 160, 210]
})
print("n=== 原始数据(带年份)===")
print(df_with_id)

# 先将 year 加入 id_vars
melted_year = pd.melt(df_with_id, id_vars=['year'])
print("n=== 包含年份的融化结果 ===")
print(melted_year)

运行结果预期:

=== 原始数据 ===
     Q1   Q2   Q3
0  100  120  130
1  150  160  170
2  200  210  220

=== 不指定 id_vars ===
   variable  value
0        Q1    100
1        Q1    150
2        融化所有列,将原始列名转为 variable 列的值,原始值转为 value 列。

代码解析:

  • 不指定 id_vars 时,只剩 variable 和 value 两列。
  • 使用 ignore_index=False 可以保留原始索引,方便后续与原始数据对比。
  • 实际使用中,通常会指定一个或多个 id_vars 来保持关键信息。

示例 4:实用案例 - 数据可视化前的准备

melt() 是数据可视化的好帮手,许多绘图库(如 Seaborn、Matplotlib)更擅长处理长格式数据。

实例

import pandas as pd

# 1. 创建销售数据(每个地区一列)
sales = pd.DataFrame({
    'product': ['A', 'B', 'C', 'D'],
    'Jan': [1200, 1500, 900, 1100],
    'Feb': [1350, 1600, 950, 1200],
    'Mar': [1100, 1450, 880, 1050]
})

print("=== 宽格式销售数据 ===")
print(sales)

# 2. 融化为长格式(用于可视化)
sales_long = pd.melt(
    sales,
    id_vars=['product'],
    var_name='month',
    value_name='sales'
)

print("n=== 长格式销售数据 ===")
print(sales_long)

# 3. 数据处理示例:计算同比增长
# 添加月份编号
month_map = {'Jan': 1, 'Feb': 2, 'Mar': 3}
sales_long['month_num'] = sales_long['month'].map(month_map)

print("n=== 添加月份编号 ===")
print(sales_long)

# 4. 筛选特定月份的数据
feb_sales = sales_long[sales_long['month'] == 'Feb']
print("n=== 2月份销售数据 ===")
print(feb_sales)

运行结果预期:

=== 宽格式销售数据 ===
  product   Jan   Feb   Mar
0       A  1200  1350  1100
product  Jan  180  170   6

=== 长格式销售数据(用于可视化) ===
   product month  sales
0       A   Jan  1200
1       B   Jan  1500
2       C   Jan   900
3       D   Jan  1100
4       A   Feb  1350

代码解析:

  • 宽格式数据每个地区/时间点一列,便于查看和录入。
  • 长格式数据每个观察值一行,是统计分析的标准格式。
  • Seaborn 等可视化库接受长格式数据,可以轻松创建分组柱状图、折线图等。
  • 使用 id_vars 可以保留产品、地区等分类变量不被融化。

示例 5:多层列索引的融化

当 DataFrame 有多层列索引时,可以使用 col_level 参数。

实例

import pandas as pd

# 1. 创建具有多层列索引的数据
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=['Category', 'Quarter'])
)

print("=== 原始数据(多层列索引)===")
print(df)

# 2. 融化所有列(不指定层级)
print("n=== 融化所有列 ===")
melted_all = pd.melt(df, ignore_index=False)
print(melted_all)

# 3. 只融化内层(Quarter)
print("n=== 只融化 Quarter 层 ===")
melted_quarter = pd.melt(df, col_level=1)
print(melted_quarter)

# 4. 融化外层(Category)
print("n=== 只融化 Category 层 ===")
melted_category = pd.melt(df, col_level=0)
print(melted_category)

运行结果预期:

=== 原始数据(多层列索引)===
Category      Electronics   Furniture
Quarter              Q1   Q2      Q1   融化不同层级会产生不同的结果:
- 融化内层(Quarter)保留 Category 作为 id
- 融化外层(Category)保留 Quarter 作为 id

代码解析:

  • 多层列索引的 DataFrame,列名是元组形式:(Category, Quarter)。
  • col_level=0 融化外层(Category),保留 Quarter 作为 id。
  • col_level=1 融化内层(Quarter),保留 Category 作为 id。
  • 这种灵活性允许你根据分析需要选择融化的层级。

提示: pd.melt() 是数据可视化的好帮手。多数绘图库(如 Seaborn、Plotnine)更擅长处理长格式数据,先用 melt() 转换数据再绘图是常用做法。

Pandas 常用函数 Pandas 常用函数