pin_drop当前位置:知识文库 ❯ 图文

pandas merge合并教程 - 数据表JOIN连接操作详解

merge()是pandas中用于合并两个DataFrame的核心函数,功能类似于SQL中的JOIN操作。通过merge,我们可以根据一个或多个键将来自不同数据源的数据整合到一起。

一、merge基本语法

代码示例

import pandas as pd
import numpy as np

# 创建两个示例DataFrame
df1 = pd.DataFrame({
    'emp_id': [1, 2, 3, 4],
    'name': ['Alice', 'Bob', 'Charlie', 'David'],
    'department': ['技术', '销售', '技术', '人事']
})

df2 = pd.DataFrame({
    'emp_id': [1, 2, 3, 5],
    'salary': [12000, 8000, 15000, 10000],
    'hire_date': ['2020-01-01', '2019-06-15', '2021-03-20', '2022-07-01']
})

# 基本merge(默认内连接,自动识别同名列作为连接键)
result = pd.merge(df1, df2)
print("默认内连接:")
print(result)

关键参数说明:

  • left/right:要合并的左右DataFrame

  • how:连接方式,'inner'、'outer'、'left'、'right'、'cross'

  • on:连接键(两个DataFrame都有的列名)

  • left_on/right_on:左右DataFrame各自的连接键

  • left_index/right_index:是否使用索引作为连接键

  • suffixes:重名列的后缀,默认('_left', '_right')

二、四种连接方式

1. 内连接(inner)

只保留两个DataFrame中都存在的键对应的行。

代码示例

# 内连接:只保留emp_id在两个表中都存在的记录
inner = pd.merge(df1, df2, on='emp_id', how='inner')
print("内连接结果(emp_id: 1,2,3):")
print(inner)

2. 左连接(left)

保留左表所有行,右表匹配不上的用NaN填充。

代码示例

# 左连接:保留左表全部记录
left = pd.merge(df1, df2, on='emp_id', how='left')
print("左连接结果(保留df1全部,emp_id=4的薪资为NaN):")
print(left)

3. 右连接(right)

保留右表所有行,左表匹配不上的用NaN填充。

代码示例

# 右连接:保留右表全部记录
right = pd.merge(df1, df2, on='emp_id', how='right')
print("右连接结果(保留df2全部,emp_id=5的姓名为NaN):")
print(right)

4. 外连接(outer)

保留两个表的所有行,匹配不上的用NaN填充。

代码示例

# 外连接:保留两个表全部记录
outer = pd.merge(df1, df2, on='emp_id', how='outer')
print("外连接结果(保留所有emp_id: 1,2,3,4,5):")
print(outer)
连接方式 保留的行 缺失值处理 SQL等价
inner 两表都有的键 无缺失值 INNER JOIN
left 左表全部 + 右表匹配 右表无匹配则为NaN LEFT JOIN
right 右表全部 + 左表匹配 左表无匹配则为NaN RIGHT JOIN
outer 两表全部 无匹配则为NaN FULL OUTER JOIN
cross 笛卡尔积(所有组合) 无缺失值 CROSS JOIN

三、多键连接与列名处理

1. 多键连接

代码示例

# 多键连接:on参数传入列表
df_a = pd.DataFrame({
    'key1': ['A', 'A', 'B', 'B'],
    'key2': [1, 2, 1, 2],
    'value_a': [10, 20, 30, 40]
})

df_b = pd.DataFrame({
    'key1': ['A', 'B', 'B', 'C'],
    'key2': [1, 1, 2, 1],
    'value_b': [100, 200, 300, 400]
})

result = pd.merge(df_a, df_b, on=['key1', 'key2'])
print("多键连接结果:")
print(result)

2. 不同列名连接

代码示例

# 左右表连接键名称不同
employees = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie']
})

salaries = pd.DataFrame({
    'emp_id': [1, 2, 4],
    'salary': [12000, 8000, 15000]
})

# 使用 left_on 和 right_on 指定不同的列名
result = pd.merge(employees, salaries, 
                  left_on='id', right_on='emp_id', how='left')
print(result)

3. 处理重名列

代码示例

# 两表有同名列(非连接键)
df1 = pd.DataFrame({
    'key': [1, 2],
    'value': [10, 20],
    'note': ['df1_note1', 'df1_note2']
})

df2 = pd.DataFrame({
    'key': [1, 2],
    'value': [100, 200],
    'note': ['df2_note1', 'df2_note2']
})

# 自定义后缀
result = pd.merge(df1, df2, on='key', 
                  suffixes=('_left', '_right'))
print(result)

四、indicator参数与验证

代码示例

# indicator=True 添加来源列
result = pd.merge(df1, df2, on='emp_id', how='outer', indicator=True)
print(result)
# _merge列会显示:both / left_only / right_only

# 自定义indicator列名
result = pd.merge(df1, df2, on='emp_id', how='outer', 
                  indicator='source')
print(result)

# validate参数验证连接类型
# 'one_to_one': 检查连接键在两个表中是否唯一
# 'one_to_many': 左表唯一,右表可重复
# 'many_to_one': 左表可重复,右表唯一
# 'many_to_many': 允许重复

result = pd.merge(df1, df2, on='emp_id', how='left', 
                  validate='one_to_one')

五、merge与join对比

代码示例

# merge:基于列名合并
result1 = pd.merge(df1, df2, on='emp_id')

# join:基于索引合并
df1_indexed = df1.set_index('emp_id')
df2_indexed = df2.set_index('emp_id')
result2 = df1_indexed.join(df2_indexed, how='inner')

# join 等价于 merge 的写法
result2 = pd.merge(df1_indexed, df2_indexed, 
                   left_index=True, right_index=True)

提示merge是最通用的合并方法,推荐优先使用。join更简洁但基于索引,适合快速按索引合并的场景。

六、实际应用场景

场景一:员工信息整合

代码示例

# 多个来源的员工数据整合
base_info = pd.DataFrame({
    'emp_id': [1, 2, 3, 4],
    'name': ['Alice', 'Bob', 'Charlie', 'David'],
    'email': ['alice@co.com', 'bob@co.com', 'charlie@co.com', 'david@co.com']
})

salary_info = pd.DataFrame({
    'emp_id': [1, 2, 3, 5],
    'salary': [12000, 8000, 15000, 10000],
    'bonus': [2000, 1000, 3000, 1500]
})

perf_info = pd.DataFrame({
    'emp_id': [1, 2, 3, 4],
    'rating': ['A', 'B', 'A', 'C'],
    'review_date': ['2024-01-15', '2024-01-16', '2024-01-15', '2024-01-17']
})

# 逐步合并
result = base_info.merge(salary_info, on='emp_id', how='left')
result = result.merge(perf_info, on='emp_id', how='left')

# 或使用 reduce 一次性合并
from functools import reduce
dfs = [base_info, salary_info, perf_info]
result = reduce(lambda left, right: pd.merge(left, right, on='emp_id', how='left'), dfs)

print(result)

场景二:时间序列数据对齐

代码示例

# 两个不同频率的时间序列
stock_a = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=5, freq='D'),
    'price_a': [100, 102, 101, 105, 103]
})

stock_b = pd.DataFrame({
    'date': pd.to_datetime(['2024-01-01', '2024-01-03', '2024-01-05']),
    'price_b': [50, 52, 51]
})

# 外连接后前向填充
merged = stock_a.merge(stock_b, on='date', how='left')
merged['price_b'] = merged['price_b'].ffill()
print(merged)

场景三:查找差异数据

代码示例

# 找出只存在于左表的数据(差集)
old_data = pd.DataFrame({'id': [1, 2, 3, 4, 5]})
new_data = pd.DataFrame({'id': [3, 4, 5, 6, 7]})

# 左连接 + indicator找只存在于旧数据的记录
diff = pd.merge(old_data, new_data, on='id', how='left', indicator=True)
only_in_old = diff[diff['_merge'] == 'left_only'][['id']]
print("只在旧数据中的ID:")
print(only_in_old)

# 外连接找两边的差异
full_diff = pd.merge(old_data, new_data, on='id', how='outer', indicator=True)
print("完整差异分析:")
print(full_diff)

小贴士

性能优化:merge操作前确保连接键的数据类型一致,否则会进行隐式转换影响性能。对于大数据集,可以先对连接键排序或使用sort=False。频繁使用merge时,考虑将连接键设为索引以提高效率。更多详情参考pandas合并官方文档

常见问题

merge出现重复行是怎么回事?

当连接键在某个表中存在重复值时,merge会产生笛卡尔积。例如左表key=A有2行,右表key=A有3行,结果会有6行。解决方法是:1) 确认连接键是否应该唯一;2) 合并前去重;3) 使用validate参数提前检查连接关系。

merge和concat有什么区别?

merge用于按列(键)水平合并两个表(类似SQL JOIN),concat用于沿轴方向(行或列)拼接多个表。如果要将两个结构相同的表上下拼接,用concat;如果要按某个键将两个表关联起来,用merge。

如何高效地合并多个DataFrame?

对于多个DataFrame的合并,可以使用functools.reduce配合merge:reduce(lambda l, r: pd.merge(l, r, on='key', how='left'), [df1, df2, df3, df4])。这样比逐行merge更简洁。如果要拼接大量相同结构的DataFrame,使用pd.concat(list_of_dfs)更高效。

如何避免merge后的列名冲突?

使用suffixes参数自定义后缀:pd.merge(df1, df2, on='key', suffixes=('_df1', '_df2'))。合并后也可以用rename方法重命名列:result.rename(columns={'value_df1': 'value_left', 'value_df2': 'value_right'})。

练习1

创建两个DataFrame:学生信息表(学号、姓名、班级)和成绩表(学号、科目、分数),使用左连接将它们合并,找出没有成绩记录的学生。

练习2

有三份数据:产品表、订单表、客户表。使用merge将它们整合成一张包含产品名、订单金额、客户信息的宽表。

练习3

使用outer连接和indicator参数,比较两个版本的员工数据,找出新增的员工和离职的员工。

标签: pandas merge 数据合并 DataFrame Python JOIN

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: pandas groupby分组聚合教程 - 数据分析核心技巧 下一篇: pandas concat拼接教程 - 数据表轴向拼接合并详解

poll相关推荐