Pandas pd.melt() 函数
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)
# 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
代码解析:
- 原始数据是宽格式,每行一个人,Q1、Q2、Q3 是三个季度的销售数据列。
id_vars=['name']指定 name 列保持不变,作为标识符。value_vars=['Q1_sales', 'Q2_sales', 'Q3_sales']指定要融化的列。- 结果中新增了 variable 列(存储原始列名)和 value 列(存储对应值)。
- 使用
var_name和value_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)
# 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)
# 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)
# 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)
# 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 常用函数