Pandas Merge:Python中合并DataFrame的完整指南
Updated on
在现实世界中,使用单个DataFrame的情况很少见。大多数数据分析项目需要您合并来自多个来源的数据——销售记录与客户档案、传感器读数与设备元数据,或调查回复与人口统计表。pandas merge函数是Python开发人员用来合并DataFrame的标准工具,深入理解它是数据准备耗费几分钟还是几小时的关键差异。
本指南涵盖了pd.merge()的所有方面:四种主要连接类型、在多列上合并、处理重复名称以及常见陷阱。每个示例都使用可以直接复制到笔记本中的可运行代码。
pd.merge()的作用
pd.merge()通过基于一个或多个共享列(称为键)匹配行来组合两个DataFrame。它的工作方式类似于SQL JOIN语句。您选择要匹配的列以及要执行的连接类型,pandas会处理其余部分。
以下是基本语法:
import pandas as pd
result = pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
suffixes=('_x', '_y'), indicator=False, validate=None)关键参数参考
| 参数 | 描述 | 默认值 |
|---|---|---|
left | 第一个(左侧)DataFrame | 必需 |
right | 第二个(右侧)DataFrame | 必需 |
how | 连接类型:'inner'、'left'、'right'、'outer'、'cross' | 'inner' |
on | 要连接的列名(必须在两个DataFrame中都存在) | None |
left_on | 左侧DataFrame用作键的列 | None |
right_on | 右侧DataFrame用作键的列 | None |
left_index | 使用左侧DataFrame的索引作为连接键 | False |
right_index | 使用右侧DataFrame的索引作为连接键 | False |
suffixes | 应用于重叠列名的后缀 | ('_x', '_y') |
indicator | 添加显示每行来源的列 | False |
validate | 检查合并是否为一对一、一对多等 | None |
如果省略on、left_on和right_on,pandas将自动在两个DataFrame中共享相同名称的所有列上进行连接。
所有示例的样本数据
下面的每个示例都使用这两个DataFrame:
import pandas as pd
employees = pd.DataFrame({
'emp_id': [1, 2, 3, 4, 5],
'name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],
'dept_id': [10, 20, 10, 30, 20]
})
departments = pd.DataFrame({
'dept_id': [10, 20, 40],
'dept_name': ['Engineering', 'Marketing', 'Sales']
})
print(employees)
print(departments)输出:
emp_id name dept_id
0 1 Alice 10
1 2 Bob 20
2 3 Charlie 10
3 4 Diana 30
4 5 Eve 20
dept_id dept_name
0 10 Engineering
1 20 Marketing
2 40 Sales注意,dept_id 30仅存在于employees中,而dept_id 40仅存在于departments中。这种不匹配是故意的——它使连接类型之间的差异变得明显。
内连接(默认)
内连接仅返回键在两个DataFrame中都存在的行。没有匹配的行将被删除。
inner_result = pd.merge(employees, departments, on='dept_id', how='inner')
print(inner_result)输出:
emp_id name dept_id dept_name
0 1 Alice 10 Engineering
1 3 Charlie 10 Engineering
2 2 Bob 20 Marketing
3 5 Eve 20 MarketingDiana(dept_id=30)被删除,因为departments表中不存在部门30。部门40(销售)也不存在,因为没有员工属于它。
何时使用内连接: 当您只想要完整记录时使用它——两边都有有效数据的行。这是最安全的默认值,因为它永远不会从不匹配的行引入NaN值。
左连接
左连接保留左侧DataFrame中的所有行,只保留右侧匹配的行。在没有匹配的地方,右侧列填充为NaN。
left_result = pd.merge(employees, departments, on='dept_id', how='left')
print(left_result)输出:
emp_id name dept_id dept_name
0 1 Alice 10 Engineering
1 2 Bob 20 Marketing
2 3 Charlie 10 Engineering
3 4 Diana 30 NaN
4 5 Eve 20 MarketingDiana现在被包含进来了,但她的dept_name是NaN,因为departments表中没有部门30的条目。
何时使用左连接: 当左侧DataFrame是您的"主要"数据集,您希望用附加列丰富它,而不想丢失主表中的任何行时使用它。这是实践中最常见的合并类型。
右连接
右连接是左连接的镜像。它保留右侧DataFrame中的所有行,只保留左侧匹配的行。
right_result = pd.merge(employees, departments, on='dept_id', how='right')
print(right_result)输出:
emp_id name dept_id dept_name
0 1.0 Alice 10 Engineering
1 3.0 Charlie 10 Engineering
2 2.0 Bob 20 Marketing
3 5.0 Eve 20 Marketing
4 NaN NaN 40 Sales销售部门(dept_id=40)现在出现了,尽管没有员工属于它。该行的员工字段为NaN。
何时使用右连接: 在实践中,右连接很少见。您总是可以通过交换DataFrame顺序将右连接重写为左连接。大多数代码库为了一致性更喜欢左连接。
外连接(完全外连接)
外连接返回来自两个DataFrame的所有行。在没有匹配的地方,缺失值填充为NaN。
outer_result = pd.merge(employees, departments, on='dept_id', how='outer')
print(outer_result)输出:
emp_id name dept_id dept_name
0 1.0 Alice 10 Engineering
1 3.0 Charlie 10 Engineering
2 2.0 Bob 20 Marketing
3 5.0 Eve 20 Marketing
4 4.0 Diana 30 NaN
5 NaN NaN 40 SalesDiana(没有匹配的部门)和销售(没有匹配的员工)都出现在结果中。
何时使用外连接: 当您需要了解两个数据集的完整情况并想识别哪些行未能匹配时使用它。indicator参数在这里特别有用。
合并类型快速比较
| 合并类型 | 保留左侧 | 保留右侧 | 不匹配的行 |
|---|---|---|---|
inner | 仅匹配 | 仅匹配 | 删除 |
left | 所有行 | 仅匹配 | 保留左侧行,右侧填充NaN |
right | 仅匹配 | 所有行 | 保留右侧行,左侧填充NaN |
outer | 所有行 | 所有行 | 双方都保留,无匹配处为NaN |
cross | 所有行 | 所有行 | 笛卡尔积(每种组合) |
在多列上合并
当单个列不足以唯一标识匹配时,将列名列表传递给on:
sales = pd.DataFrame({
'year': [2024, 2024, 2025, 2025],
'quarter': ['Q1', 'Q2', 'Q1', 'Q2'],
'revenue': [100, 150, 200, 250]
})
targets = pd.DataFrame({
'year': [2024, 2024, 2025, 2025],
'quarter': ['Q1', 'Q2', 'Q1', 'Q2'],
'target': [120, 140, 210, 230]
})
merged = pd.merge(sales, targets, on=['year', 'quarter'])
print(merged)输出:
year quarter revenue target
0 2024 Q1 100 120
1 2024 Q2 150 140
2 2025 Q1 200 210
3 2025 Q2 250 230这相当于SQL中的复合键。year和quarter都必须匹配才能连接行。
在不同列名上合并
有时两个DataFrame对相同概念使用不同的名称。使用left_on和right_on代替on:
orders = pd.DataFrame({
'order_id': [101, 102, 103],
'customer_id': [1, 2, 3],
'amount': [50.0, 75.0, 120.0]
})
customers = pd.DataFrame({
'id': [1, 2, 4],
'name': ['Alice', 'Bob', 'Diana']
})
merged = pd.merge(orders, customers, left_on='customer_id', right_on='id', how='left')
print(merged)输出:
order_id customer_id amount id name
0 101 1 50.0 1.0 Alice
1 102 2 75.0 2.0 Bob
2 103 3 120.0 NaN NaN注意,customer_id和id列都出现在结果中。您可以之后删除重复项:
merged = merged.drop(columns=['id'])使用后缀处理重复列名
当两个DataFrame都有同名列(除了键之外)时,pandas会附加后缀来区分它们:
df1 = pd.DataFrame({
'id': [1, 2, 3],
'score': [85, 90, 78]
})
df2 = pd.DataFrame({
'id': [1, 2, 3],
'score': [88, 92, 80]
})
# 默认后缀
merged = pd.merge(df1, df2, on='id')
print(merged)输出:
id score_x score_y
0 1 85 88
1 2 90 92
2 3 78 80您可以自定义后缀以使列名更有意义:
merged = pd.merge(df1, df2, on='id', suffixes=('_midterm', '_final'))
print(merged)输出:
id score_midterm score_final
0 1 85 88
1 2 90 92
2 3 78 80使用Indicator参数
indicator参数添加一个_merge列,告诉您每行来自哪里:
result = pd.merge(employees, departments, on='dept_id', how='outer', indicator=True)
print(result)输出:
emp_id name dept_id dept_name _merge
0 1.0 Alice 10 Engineering both
1 3.0 Charlie 10 Engineering both
2 2.0 Bob 20 Marketing both
3 5.0 Eve 20 Marketing both
4 4.0 Diana 30 NaN left_only
5 NaN NaN 40 Sales right_only这对于数据质量检查非常有用——您可以快速过滤未能匹配的行:
unmatched = result[result['_merge'] != 'both']
print(unmatched)merge()与join()与concat()——何时使用每个
Pandas提供了三种组合DataFrame的方法。以下是何时使用每种方法:
| 功能 | pd.merge() | df.join() | pd.concat() |
|---|---|---|---|
| 连接类型 | 基于列(类似SQL) | 默认基于索引 | 堆叠行或列 |
| 语法 | pd.merge(df1, df2, on='col') | df1.join(df2, on='col') | pd.concat([df1, df2]) |
| 最适合 | 在共享列上连接 | 在索引上连接 | 垂直/水平堆叠DataFrame |
| 多个键 | 是(on=['a','b']) | 有限 | 不适用 |
| 多个DataFrame | 一次两个 | 一次两个 | 一次任意数量 |
| 默认连接 | 内连接 | 左连接 | 外连接(axis=0) |
| 灵活性 | 最高 | 中等 | 不同用例 |
经验法则:
- 当您基于列值组合DataFrame时使用
pd.merge()(最常见的情况)。 - 当您的连接键是索引且您想要更短的语法时使用
df.join()。 - 当您在彼此之上堆叠DataFrame(追加行)或并排放置时使用
pd.concat()。
常见错误和故障排除
1. MergeError:列重叠但未指定后缀
当两个DataFrame都有同名非键列且您设置了suffixes=(False, False)时会发生这种情况:
# 修复:使用有意义的后缀
merged = pd.merge(df1, df2, on='id', suffixes=('_left', '_right'))2. 意外行爆炸(多对多合并)
如果两个DataFrame在连接键中都有重复值,pandas会创建匹配行的笛卡尔积。这可能导致结果的行数远多于任一输入:
# 在合并前检查重复项
print(df1['key'].duplicated().sum())
print(df2['key'].duplicated().sum())
# 使用validate尽早捕获这种情况
merged = pd.merge(df1, df2, on='key', validate='one_to_many')validate参数接受'one_to_one'、'one_to_many'、'many_to_one'和'many_to_many'。如果数据与预期的基数不匹配,它会引发MergeError。
3. 键列具有不同的数据类型
如果一个DataFrame将键存储为int64,而另一个存储为object(字符串),则合并将失败或产生零匹配:
# 检查数据类型
print(df1['id'].dtype) # int64
print(df2['id'].dtype) # object
# 修复:转换为相同类型
df2['id'] = df2['id'].astype(int)
merged = pd.merge(df1, df2, on='id')4. 键中的NaN值
连接键列中带有NaN的行不会匹配任何内容(在pandas中NaN != NaN)。首先删除或填充它们:
df1 = df1.dropna(subset=['key'])使用PyGWalker可视化合并后的DataFrame
合并数据后,下一步通常是探索结果——查看分布、发现模式并检查异常。与其编写数十个matplotlib或seaborn调用,您可以使用PyGWalker (opens in a new tab),这是一个开源Python库,可以将任何pandas DataFrame直接在Jupyter Notebook内转换为交互式、类似Tableau的可视化探索界面。
import pandas as pd
import pygwalker as pyg
# 合并您的DataFrame
employees = pd.DataFrame({
'emp_id': [1, 2, 3, 4, 5],
'name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],
'dept_id': [10, 20, 10, 30, 20],
'salary': [95000, 82000, 105000, 78000, 91000]
})
departments = pd.DataFrame({
'dept_id': [10, 20, 30],
'dept_name': ['Engineering', 'Marketing', 'Design']
})
merged = pd.merge(employees, departments, on='dept_id')
# 启动交互式可视化——拖放探索
walker = pyg.walk(merged)使用PyGWalker,您可以将dept_name拖到x轴,将salary拖到y轴,立即查看按部门划分的薪资分布——无需图表代码。您可以通过拖动字段创建条形图、散点图、直方图等。它对于探索复杂合并的结果特别强大,您需要验证连接是否按预期工作。
您可以在Google Colab (opens in a new tab)、Kaggle (opens in a new tab)上立即尝试PyGWalker,或使用
pip install pygwalker进行安装。
常见问题
pandas merge和join有什么区别?
pd.merge()默认基于列值连接DataFrame,并支持所有连接类型(内连接、左连接、右连接、外连接、交叉连接)。df.join()默认在索引上连接,使用左连接。在底层,join()调用merge(),因此它们产生相同的结果——merge()只是让您对要匹配的列有更多控制。
如何在pandas中在多列上合并两个DataFrame?
将列名列表传递给on参数:pd.merge(df1, df2, on=['col_a', 'col_b'])。两列都必须匹配才能连接行。这相当于SQL中的复合键。
为什么我的pandas merge创建重复行?
当连接键在一个或两个DataFrame中具有重复值时,会出现重复行。Pandas创建所有匹配行的笛卡尔积。在合并前使用df.duplicated(subset=['key']).sum()检查重复项,或使用validate='one_to_one'尽早捕获它。
pandas中的交叉合并是什么?
交叉合并(how='cross')产生两个DataFrame的笛卡尔积——左侧的每一行都与右侧的每一行配对。如果左侧有3行,右侧有4行,结果有12行。它对于生成所有可能的组合很有用,例如将每个产品与每个商店位置配对。
如何在索引上执行pandas merge?
设置left_index=True和/或right_index=True:pd.merge(df1, df2, left_index=True, right_index=True)。您还可以混合索引和列键:pd.merge(df1, df2, left_on='col_a', right_index=True)。
结论
pandas merge()函数是Python中组合DataFrame最灵活且使用最广泛的工具。回顾要点:
- 内连接(默认)仅保留两个DataFrame中都匹配的行。
- 左连接保留左侧DataFrame的所有行,在右侧没有匹配的地方填充NaN。
- 右连接保留右侧DataFrame的所有行——但为了一致性,最好使用交换顺序的左连接。
- 外连接保留双方的所有内容,对于使用
indicator=True识别不匹配的记录很有用。 - 对于同名键使用
on,对于不同名键使用left_on/right_on,使用suffixes处理重叠列。 - 在合并前始终检查重复键和不匹配的数据类型,以避免意外结果。
一旦您的数据合并完成,像PyGWalker (opens in a new tab)这样的工具可以让您在不编写图表代码的情况下直观地探索结果,使整个分析工作流程更快、更直观。