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)三、多键连接与列名处理
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参数,比较两个版本的员工数据,找出新增的员工和离职的员工。
本文涉及AI创作
内容由AI创作,请仔细甄别