Pandas合并两个DataFrame的几种方法
在Python数据分析中,`pandas`库的`pd.merge()`函数是合并DataFrame的强大工具,它如同SQL中的JOIN操作,基于共同列或索引实现数据的内、左、右、外连接。通过`on`参数指定连接键,支持单列或多列匹配,`left_on`和`right_on`处理列名不同的情况,`suffixes`自定义重复列名后缀。`pd.concat()`则擅长沿轴堆叠结构相似的数据。索引合并需设置`left_index`和`right_index`,冲突时可用`reset_index`或`ignore_index`解决。本文将深入探讨`pd.merge()`的用法,多列匹配场景,以及`pd.concat()`与`pd.merge()`的本质区别,并提供有效处理重复列名和索引冲突的实用技巧,助力读者高效完成数据整合任务。
最核心的合并方法是pd.merge(),它基于共同列或索引进行内、左、右、外连接;on参数指定连接键,支持单列或多列匹配;当列名不同时可用left_on和right_on;重复列名通过suffixes自定义后缀区分;pd.concat()用于沿轴堆叠数据,适合结构相似的数据拼接;基于索引合并需设置left_index和right_index,索引冲突可通过reset_index或ignore_index处理。
在Python中,合并两个pandas DataFrame最常用的方法是使用pd.merge()
函数,它能够根据一个或多个共同的键(列或索引)将两个DataFrame连接起来,就像SQL中的JOIN操作一样。此外,pd.concat()
用于沿着某个轴堆叠或拼接DataFrame,而df.join()
则是pd.merge()
的一种简化形式,主要用于基于索引的连接。
解决方案
要合并两个DataFrame,最核心且功能最强大的工具就是pd.merge()
。它允许我们以多种方式(内连接、左连接、右连接、外连接)将数据基于共同的列或索引进行整合。
假设我们有两个DataFrame,df1
和df2
:
import pandas as pd df1 = pd.DataFrame({ 'ID': [1, 2, 3, 4], 'Name': ['Alice', 'Bob', 'Charlie', 'David'], 'City': ['New York', 'London', 'Paris', 'Tokyo'] }) df2 = pd.DataFrame({ 'ID': [1, 2, 5, 6], 'Age': [25, 30, 22, 35], 'Occupation': ['Engineer', 'Doctor', 'Artist', 'Teacher'] }) # 默认情况下,pd.merge()会尝试找到两个DataFrame中共同的列名作为键进行内连接 # 比如这里,'ID'是共同的列 merged_df_inner = pd.merge(df1, df2, on='ID', how='inner') print("内连接结果 (inner join):\n", merged_df_inner) # 左连接 (left join): 保留左边DataFrame的所有行,匹配右边DataFrame的数据 merged_df_left = pd.merge(df1, df2, on='ID', how='left') print("\n左连接结果 (left join):\n", merged_df_left) # 右连接 (right join): 保留右边DataFrame的所有行,匹配左边DataFrame的数据 merged_df_right = pd.merge(df1, df2, on='ID', how='right') print("\n右连接结果 (right join):\n", merged_df_right) # 外连接 (outer join): 保留所有行的信息,无论是否匹配 merged_df_outer = pd.merge(df1, df2, on='ID', how='outer') print("\n外连接结果 (outer join):\n", merged_df_outer)
pd.merge()
的关键参数包括:
left
,right
: 要合并的两个DataFrame。on
: 用于连接的列名(或列名列表),这些列名必须在两个DataFrame中都存在。left_on
,right_on
: 当左右DataFrame的连接列名不同时使用。how
: 连接类型,可以是'inner'
(默认),'left'
,'right'
,'outer'
。suffixes
: 当合并后出现重复列名时,用于区分左右DataFrame的后缀。left_index
,right_index
: 如果想基于索引进行连接,可以将它们设置为True
。
pd.merge()
的on
参数到底怎么用?处理多列匹配的复杂场景?
pd.merge()
中的on
参数是指定连接键的核心。它既可以接受单个列名,也可以接受一个列名列表,这在处理需要多条件匹配的复杂数据时尤其有用。我个人觉得,理解on
参数的灵活性是掌握pd.merge()
的关键一步。
当on
参数是一个字符串时,比如on='ID'
,这意味着两个DataFrame都会使用名为'ID'
的列作为连接键。如果两个DataFrame中连接的列名不一样,例如df1
中有'CustomerID'
,而df2
中有'ClientID'
,但它们代表的是同一个实体,这时就不能直接用on
了。我们需要分别指定left_on='CustomerID'
和right_on='ClientID'
。
来看一个多列匹配的例子,这在处理复合主键或者需要更精确匹配的场景下非常常见。比如,你可能有一个销售订单表,需要通过'订单号'
和'商品ID'
的组合来匹配商品详情。
import pandas as pd orders = pd.DataFrame({ 'OrderID': ['A001', 'A001', 'A002', 'A003'], 'ProductID': [101, 102, 101, 103], 'Quantity': [1, 2, 1, 3] }) product_details = pd.DataFrame({ 'ProductID': [101, 102, 103, 104], 'ProductName': ['Laptop', 'Mouse', 'Keyboard', 'Monitor'], 'Price': [1200, 25, 75, 300] }) # 如果我们想把订单信息和商品详情合并,基于 ProductID 就可以 merged_by_product = pd.merge(orders, product_details, on='ProductID', how='left') print("基于ProductID的合并:\n", merged_by_product) # 假设我们还有一个订单状态表,需要根据 OrderID 和 ProductID 来更新特定商品的订单状态 order_status = pd.DataFrame({ 'OrderID': ['A001', 'A001', 'A002'], 'ProductID': [101, 102, 101], 'Status': ['Shipped', 'Processing', 'Delivered'] }) # 这时候就需要多列匹配了,使用 on=['OrderID', 'ProductID'] final_merged_df = pd.merge(merged_by_product, order_status, on=['OrderID', 'ProductID'], how='left') print("\n基于多列匹配的最终合并:\n", final_merged_df)
这里,on=['OrderID', 'ProductID']
告诉pd.merge()
,只有当两个DataFrame的OrderID
和ProductID
都完全一致时,才认为它们是匹配的。这种精确匹配避免了只凭单一列可能导致的错误关联。我在实际工作中,遇到过很多数据清洗的场景,往往就需要这种多列匹配来确保数据合并的准确性,不然结果可能就南辕北辙了。
pd.concat()
和pd.merge()
有什么本质区别?什么时候该用哪个?
这确实是初学者,甚至是一些有经验的用户也容易混淆的地方。我常看到有人试图用pd.merge()
去堆叠数据,或者用pd.concat()
去连接数据,结果可想而知,要么报错,要么得到一堆NaN
。它们的核心设计目的完全不同。
pd.merge()
的核心是连接(Joining)。它基于一个或多个键(列或索引)来查找两个DataFrame中匹配的行,然后将这些行横向(按列)拼接起来。可以把它想象成数据库中的JOIN操作,它关注的是“哪些行是相关的?”以及“如何把相关行的信息放到一起?”。
pd.concat()
的核心是堆叠(Concatenating)或拼接(Appending)。它将多个DataFrame沿着某个轴(行或列)直接堆叠起来,就像乐高积木一样。它不关心数据内容是否匹配,只关心形状是否能对齐。它关注的是“如何把多个数据块简单地堆起来?”。
什么时候用哪个?
使用
pd.merge()
的场景:- 当你需要根据共同的ID、日期、名称等键将两个来源不同的数据集关联起来时。
- 当你需要查找一个DataFrame中哪些记录在另一个DataFrame中存在或缺失时(通过不同的
how
参数)。 - 例如,将客户信息表与订单表根据
CustomerID
进行关联。
使用
pd.concat()
的场景:- 当你有一些相同结构(或类似结构)的数据,想把它们按行堆叠起来,形成一个更大的数据集时。比如,你每天都有一个CSV文件记录当天的销售数据,你想把一个月的销售数据都放到一个DataFrame里进行分析。
- 当你有一些具有相同索引但列不同的DataFrame,想把它们按列拼接起来时。比如,你有一个DataFrame记录了用户的基本信息,另一个DataFrame记录了用户的联系方式,它们都以
UserID
作为索引,你想把它们横向拼接。
# pd.concat() 示例:按行堆叠 df_q1 = pd.DataFrame({'Month': ['Jan', 'Feb'], 'Sales': [100, 120]}) df_q2 = pd.DataFrame({'Month': ['Mar', 'Apr'], 'Sales': [150, 110]}) all_sales = pd.concat([df_q1, df_q2], ignore_index=True) print("按行堆叠 (pd.concat):\n", all_sales) # pd.concat() 示例:按列拼接 (需要索引对齐) df_info = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [25, 30]}, index=[1, 2]) df_contact = pd.DataFrame({'Email': ['a@example.com', 'b@example.com'], 'Phone': ['111', '222']}, index=[1, 2]) combined_info = pd.concat([df_info, df_contact], axis=1) print("\n按列拼接 (pd.concat, axis=1):\n", combined_info)
可以看到,pd.concat()
在按行堆叠时,默认会保留原始索引,如果你不希望这样,需要设置ignore_index=True
。而按列拼接时,它会尝试根据索引对齐。这种行为与pd.merge()
基于列值进行匹配的逻辑截然不同。所以,在选择函数之前,先问问自己:我是想“关联”数据,还是想“堆叠”数据?
合并DataFrame时,如何有效处理重复列名和索引冲突?
在实际数据处理中,合并DataFrame常常会遇到列名冲突和索引冲突的问题。如果不妥善处理,轻则数据混乱,重则结果错误。我个人觉得,这些细节的处理能力,很大程度上决定了数据分析的可靠性。
1. 处理重复列名:suffixes
参数
当两个DataFrame有共同的非连接列名时,pd.merge()
默认会在这些重复的列名后面加上_x
和_y
后缀。但很多时候,这种默认的后缀并不够清晰,或者与你的命名规范不符。这时,suffixes
参数就派上用场了。它接受一个包含两个字符串的元组,分别作为左右DataFrame重复列名的后缀。
import pandas as pd df_user_info = pd.DataFrame({ 'ID': [1, 2, 3], 'Name': ['Alice', 'Bob', 'Charlie'], 'Score': [85, 90, 78] }) df_exam_results = pd.DataFrame({ 'ID': [1, 2, 4], 'Score': [92, 88, 95], # 注意这里也有一个 'Score' 列 'Grade': ['A', 'B', 'A'] }) # 不指定 suffixes,默认会是 _x 和 _y merged_default_suffix = pd.merge(df_user_info, df_exam_results, on='ID', how='left') print("默认后缀处理重复列名:\n", merged_default_suffix) # 使用自定义 suffixes merged_custom_suffix = pd.merge( df_user_info, df_exam_results, on='ID', how='left', suffixes=('_userInfo', '_examResult') ) print("\n自定义后缀处理重复列名:\n", merged_custom_suffix)
通过suffixes=('_userInfo', '_examResult')
,我们可以清晰地知道Score_userInfo
是来自用户信息表的,而Score_examResult
是来自考试结果表的。这种命名方式能极大提高代码的可读性和数据的可追溯性。
2. 处理索引冲突/基于索引合并:left_index
, right_index
和 reset_index()
基于索引合并: 如果你的DataFrame的索引本身就是你想要用来连接的键,那么可以使用
left_index=True
和right_index=True
参数。df_a = pd.DataFrame({'ValueA': [10, 20]}, index=['K1', 'K2']) df_b = pd.DataFrame({'ValueB': [30, 40]}, index=['K1', 'K3']) merged_by_index = pd.merge(df_a, df_b, left_index=True, right_index=True, how='outer') print("基于索引的合并:\n", merged_by_index)
索引冲突和重置:
- 当使用
pd.concat()
按行堆叠时,如果原始DataFrame的索引不是唯一的,或者你不想保留它们,ignore_index=True
会非常有用。它会生成一个全新的、从0开始的整数索引。 - 在使用
pd.merge()
时,如果你的连接键是某个列,但你又担心原始索引会干扰后续操作,或者想把索引也作为普通列进行合并,可以先用df.reset_index()
将索引转换为普通列,然后再进行合并。
# 假设df1的索引有意义,但我们想把它作为列参与合并 df1_with_index_as_col = df1.reset_index().rename(columns={'index': 'OriginalIndex'}) # 然后再与df2合并,如果需要的话 # pd.merge(df1_with_index_as_col, df2, on='ID')
处理索引问题时,我经常会先停下来思考:这个索引对我来说是数据的一部分(需要参与合并或保留),还是仅仅一个行标识(可以忽略或重置)?这决定了我应该使用
left_index/right_index
,还是reset_index()
,或者干脆ignore_index
。忽略这些看似细微的索引问题,可能会在后续的数据聚合或分析中埋下隐患,导致意想不到的错误结果。- 当使用
今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

- 上一篇
- 块状链表是什么?怎么操作?

- 下一篇
- GolangJSON优化:json-iterator替代标准库方法
-
- 文章 · python教程 | 8分钟前 |
- SQLAlchemy父类关联子类获取方法
- 421浏览 收藏
-
- 文章 · python教程 | 20分钟前 |
- Python快速统计元组列表共通元素技巧
- 119浏览 收藏
-
- 文章 · python教程 | 42分钟前 |
- Python日志配置与使用详解
- 236浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python对比列表差异的实用方法
- 218浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python连接Kafka的配置教程
- 231浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Python中r的作用是原始字符串,防止转义
- 130浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Tabula-py提取PDF表格数据技巧
- 445浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Python类与对象详解教程
- 131浏览 收藏
-
- 文章 · python教程 | 3小时前 |
- AzureDurableFunctions大数据共享方法
- 168浏览 收藏
-
- 文章 · python教程 | 4小时前 |
- Flask静态资源404解决与路径设置
- 461浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 514次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- AI Mermaid流程图
- SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
- 461次使用
-
- 搜获客【笔记生成器】
- 搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
- 451次使用
-
- iTerms
- iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
- 478次使用
-
- TokenPony
- TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
- 504次使用
-
- 迅捷AIPPT
- 迅捷AIPPT是一款高效AI智能PPT生成软件,一键智能生成精美演示文稿。内置海量专业模板、多样风格,支持自定义大纲,助您轻松制作高质量PPT,大幅节省时间。
- 451次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览