PythonDataFrame合并:concat与merge对比解析
在文章实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《Python合并DataFrame:concat与merge对比详解》,聊聊,希望可以帮助到正在努力赚钱的你。
Python中合并多个DataFrame的核心方法有两种:一是使用pd.concat进行堆叠式合并,二是使用pd.merge进行关联式合并。pd.concat主要用于沿行或列方向堆叠数据,适用于结构相似的数据整合,关键参数包括objs(待合并对象)、axis(合并方向)、join(索引/列对齐方式)及ignore_index(是否重置索引)。pd.merge则基于共同键进行数据关联,支持内连接、左连接、右连接和外连接,核心参数有left/right(待合并的两个DataFrame)、how(连接类型)、on/left_on/right_on(连接键)及suffixes(列名冲突处理)。选择concat时应确保数据结构一致或索引对齐,而merge适用于存在逻辑关联的数据整合,需注意键列清洗与连接类型选择。两者在性能上各有侧重,concat适合垂直或水平拼接,merge适合基于键的关系型合并,实际应用中应根据数据特征和需求合理选用。

Python中合并多个DataFrame,本质上无非两种核心操作:一种是像堆积木一样,把数据框一个接一个地堆叠起来,这通常是 pd.concat 的职责;另一种则是像给不同表做“联姻”,根据某些共同的“媒人”(键)把它们关联起来,这正是 pd.merge 的强项。理解它们各自的适用场景和内在逻辑,是高效处理数据的基础。

解决方案
在Python的pandas库中,合并多个DataFrame主要依赖于pd.concat()和pd.merge()这两个函数。它们解决的是不同类型的数据整合问题。

pd.concat()
这个函数主要用于沿着某个轴(行或列)堆叠或连接DataFrame。你可以把它想象成把几个表格直接首尾相连,或者并排摆放。
- 核心功能: 堆叠(append)或并排连接(concatenate)。
- 主要参数:
objs: 一个DataFrame对象的序列或字典,这是要合并的数据框列表。axis: 决定合并方向。axis=0(默认)表示按行堆叠,即增加行;axis=1表示按列并排,即增加列。join: 当按列合并时,如何处理不完全匹配的索引。'outer'(默认)会保留所有索引,缺失值用NaN填充;'inner'只保留共同的索引。当按行合并时,如何处理列。'outer'会保留所有列,缺失值用NaN填充;'inner'只保留共同的列。ignore_index: 如果设为True,合并后的DataFrame会重置索引,这在堆叠操作中非常有用,可以避免重复索引。
示例:

import pandas as pd
df1 = pd.DataFrame({'A': ['A0', 'A1'], 'B': ['B0', 'B1']}, index=[0, 1])
df2 = pd.DataFrame({'A': ['A2', 'A3'], 'B': ['B2', 'B3']}, index=[2, 3])
df3 = pd.DataFrame({'C': ['C4', 'C5'], 'D': ['D4', 'D5']}, index=[4, 5])
# 按行堆叠 (默认 axis=0)
result_rows = pd.concat([df1, df2])
# print(result_rows)
# 按列并排 (axis=1)
# 注意:这里会根据索引进行对齐,如果索引不同,会填充NaN
result_cols = pd.concat([df1, df3], axis=1)
# print(result_cols)
# 按行堆叠并重置索引
result_reset_index = pd.concat([df1, df2], ignore_index=True)
# print(result_reset_index)pd.merge()
这个函数用于通过一个或多个键(列)将两个DataFrame连接起来,类似于SQL中的JOIN操作。它基于列的值进行匹配,而不是简单地堆叠。
- 核心功能: 根据共同列(或索引)进行数据关联。
- 主要参数:
left,right: 要合并的两个DataFrame。how: 指定合并类型。'inner'(默认):只保留左右DataFrame中键都存在的行。'left':保留左DataFrame的所有行,右DataFrame中匹配的行,不匹配的用NaN填充。'right':保留右DataFrame的所有行,左DataFrame中匹配的行,不匹配的用NaN填充。'outer':保留左右DataFrame中的所有行,不匹配的用NaN填充。
on: 用于连接的列名(如果左右DataFrame的键列名相同)。left_on,right_on: 如果左右DataFrame的键列名不同,分别指定。suffixes: 当左右DataFrame有相同列名(非键列)时,用于区分这些列的后缀。
示例:
df_employees = pd.DataFrame({
'employee_id': [1, 2, 3, 4],
'name': ['Alice', 'Bob', 'Charlie', 'David'],
'department_id': [101, 102, 101, 103]
})
df_departments = pd.DataFrame({
'department_id': [101, 102, 104],
'department_name': ['HR', 'IT', 'Finance']
})
# 内连接:只保留员工和部门ID都匹配的记录
merged_inner = pd.merge(df_employees, df_departments, on='department_id', how='inner')
# print(merged_inner)
# 左连接:保留所有员工信息,匹配部门信息
merged_left = pd.merge(df_employees, df_departments, on='department_id', how='left')
# print(merged_left)concat 适用场景与常见误区
我个人觉得,pd.concat 最能体现其价值的地方,就是当你手里有一堆结构相同或者非常相似的数据碎片时。比如,你从数据库里分批导出了按月份划分的销售数据,或者从不同渠道抓取了格式一致的用户行为日志,这时候,把它们堆叠起来形成一个完整的、更大的数据集,concat 简直是神来之笔。它尤其适合处理时间序列数据,或者当你需要把多个文件(例如CSV)的内容合并成一个DataFrame时。
然而,concat 也不是没有坑。最常见的误区,我觉得就是索引的处理。如果你只是简单地 pd.concat([df1, df2]),而这两个DataFrame又恰好有相同的索引值(比如都是从0开始),那么合并后的结果就会出现重复索引。这在后续的数据处理中,比如使用 loc 进行选择时,可能会导致意想不到的结果。所以,我几乎成了 ignore_index=True 的忠实拥趸,尤其是在做行堆叠时,它能帮你自动生成一个干净、连续的新索引。
# 常见误区:索引重复
df_a = pd.DataFrame({'value': [10, 20]}, index=[0, 1])
df_b = pd.DataFrame({'value': [30, 40]}, index=[0, 1]) # 同样有0, 1索引
# 结果索引会重复
bad_concat = pd.concat([df_a, df_b])
# print(bad_concat)
# print(bad_concat.loc[0]) # 这会返回两行!
# 解决方案:重置索引
good_concat = pd.concat([df_a, df_b], ignore_index=True)
# print(good_concat)
# print(good_concat.loc[0]) # 只返回一行另一个小陷阱是列的不匹配。当你 axis=0 进行行堆叠时,如果各个DataFrame的列名不完全一致,concat 默认会采取 join='outer' 策略,也就是保留所有列,不匹配的地方用 NaN 填充。这通常是期望的行为,但如果你只想要那些所有DataFrame都共有的列,那就得明确指定 join='inner'。我有时候会忘记这一点,结果发现合并出来的数据框多了很多 NaN 列,回头检查才发现是列名没对齐。
df_sales = pd.DataFrame({'product': ['A', 'B'], 'price': [100, 200]})
df_returns = pd.DataFrame({'product': ['A', 'C'], 'quantity': [1, 2]})
# 默认 outer join,会保留所有列
outer_concat = pd.concat([df_sales, df_returns], axis=0)
# print(outer_concat)
# inner join,只保留共同列(product)
inner_concat = pd.concat([df_sales, df_returns], axis=0, join='inner')
# print(inner_concat)merge 的连接类型与复杂性处理
说到合并,其实除了最直接的拼接,我们更多时候面对的是数据间的“联姻”,这也就是 merge 的用武之地了。pd.merge 最强大的地方在于它能够模拟SQL的各种连接操作,通过 how 参数来精确控制连接的逻辑。
how 参数的奥秘:
how='inner'(内连接):这是默认选项,也是最严格的。它只保留左右两个DataFrame中键都存在的行。你可以想象成,只有当两个数据源都能找到匹配的对象时,这条记录才会被纳入结果。how='left'(左连接):以左边的DataFrame为基准。它会保留左DataFrame的所有行,并尝试在右DataFrame中找到匹配的行。如果找到了,就合并;如果没找到,右DataFrame对应的列就用NaN填充。这在你想保留所有“主”数据(比如所有客户信息),然后附加“次要”数据(比如他们的订单历史)时非常有用。how='right'(右连接):与左连接相反,以右边的DataFrame为基准。保留右DataFrame的所有行,并尝试在左DataFrame中找到匹配的行。how='outer'(外连接):这是最“包容”的连接方式。它会保留左右两个DataFrame中的所有行。如果某个键只存在于一个DataFrame中,另一个DataFrame对应的列就会用NaN填充。这在你想看到所有可能的组合,即使数据不完全匹配时,会很有帮助。
# 示例数据
df_users = pd.DataFrame({
'user_id': [1, 2, 3, 4],
'username': ['alpha', 'beta', 'gamma', 'delta']
})
df_orders = pd.DataFrame({
'order_id': [101, 102, 103, 104],
'user_id': [1, 2, 5, 1], # user_id 5 不在 df_users 中
'amount': [100, 150, 200, 120]
})
# 内连接:只显示有订单的用户
inner_join = pd.merge(df_users, df_orders, on='user_id', how='inner')
# print("\nInner Join:\n", inner_join)
# 左连接:显示所有用户,以及他们的订单(如果没有则为NaN)
left_join = pd.merge(df_users, df_orders, on='user_id', how='left')
# print("\nLeft Join:\n", left_join)
# 右连接:显示所有订单,以及对应的用户信息(如果用户不存在则为NaN)
right_join = pd.merge(df_users, df_orders, on='user_id', how='right')
# print("\nRight Join:\n", right_join)
# 外连接:显示所有用户和所有订单,无论是否匹配
outer_join = pd.merge(df_users, df_orders, on='user_id', how='outer')
# print("\nOuter Join:\n", outer_join)处理多键合并或非等值连接:
当需要根据多个列进行合并时,merge 同样游刃有余。你只需要把 on、left_on 或 right_on 参数的值从单个字符串变成一个字符串列表即可。比如,如果你需要根据 (department_id, employee_name) 来匹配数据,那就 on=['department_id', 'employee_name']。
df_emp_details = pd.DataFrame({
'emp_id': [1, 2, 3],
'first_name': ['John', 'Jane', 'Peter'],
'last_name': ['Doe', 'Smith', 'Jones']
})
df_emp_salaries = pd.DataFrame({
'employee_id': [1, 2, 3],
'first': ['John', 'Jane', 'Peter'],
'last': ['Doe', 'Smith', 'Jones'],
'salary': [50000, 60000, 70000]
})
# 多键合并
multi_key_merge = pd.merge(df_emp_details, df_emp_salaries,
left_on=['emp_id', 'first_name', 'last_name'],
right_on=['employee_id', 'first', 'last'],
how='inner')
# print("\nMulti-key Merge:\n", multi_key_merge)至于非等值连接(比如 A.value > B.value),pd.merge 本身并不直接支持,它主要用于等值连接。如果真有这样的需求,我通常会考虑几种变通方法:要么是先进行一个宽泛的合并,然后用布尔索引进行筛选;要么是利用 pd.merge_asof(针对时间序列的近似匹配);再复杂一点,可能就要回到循环或者自定义函数,但那已经超出了 merge 的核心范畴了。
性能考量与最佳实践:何时选择 concat 或 merge?
在处理大数据量时,concat 和 merge 的性能表现确实值得掰扯一下。这就像是开车,你知道目的地,但得选对路和交通工具。
性能表现:
concat: 对于简单的行堆叠,concat通常非常高效,因为它主要是内存块的拼接。尤其是当所有DataFrame的列结构完全一致时,它的开销相对较小。然而,如果需要进行大量的列级别合并(axis=1),并且索引不完全对齐,那么concat可能需要在内部进行大量的重索引和数据填充,这会消耗更多的时间和内存。merge:merge的性能通常取决于你选择的连接类型 (how) 以及用于连接的键列。在内部,pandas会尝试优化,比如使用哈希表或排序合并算法。如果键列已经被索引(通过df.set_index()),或者键列的数据类型是高效的(比如整数或分类类型),merge的性能会更好。但如果键列是字符串且非常长,或者数据量巨大且键列没有优化,merge可能会变得相当慢,因为它需要进行大量的字符串比较和哈希计算。
选择哪一个?这其实是个“哲学问题”,答案完全取决于你的数据关系和目标。
我的经验是:
选择
concat的时机:- 数据结构一致,需要垂直扩展: 你有多个DataFrame,它们拥有相同的列名和数据类型,你只是想把它们堆叠起来,形成一个更长的DataFrame。比如,每日销售数据文件,你需要把它们合并成月度或年度报告。
- 需要水平扩展,且索引能够对齐: 你有多个DataFrame,它们有相同的行索引,你只是想把它们并排放置,增加列。比如,一个DataFrame有用户基本信息,另一个有用户的联系方式,它们的索引都是
user_id。 - 数据来源分散,但内容同质: 比如爬取了多个网页,每个网页的数据结构都一样,需要汇总。
选择
merge的时机:- 数据存在关联关系,需要水平整合: 你的数据分布在不同的DataFrame中,但它们之间存在逻辑上的关联(比如通过
customer_id或product_id)。你需要根据这些关联键来组合信息。这就像数据库中的表连接。 - 需要根据特定条件筛选或补充数据: 你想根据某个DataFrame的完整性来决定合并结果(如
left join或right join),或者你想找出所有匹配和不匹配的项(如outer join)。 - 数据来源异构,但逻辑相关: 比如一个DataFrame是订单明细,另一个是产品信息,你需要把产品名称、价格等信息加到订单明细中。
- 数据存在关联关系,需要水平整合: 你的数据分布在不同的DataFrame中,但它们之间存在逻辑上的关联(比如通过
最佳实践建议:
- 数据清洗先行: 在进行任何合并操作之前,务必确保你的键列(或其他需要对齐的列)是干净的。检查数据类型是否一致,是否存在前导/尾随空格,大小写是否统一。一个小小的差异都可能导致
merge失败或concat产生NaN。 - 明确
how参数: 对于merge,一定要想清楚你需要哪种连接类型。是只保留匹配项 (inner),还是保留左边所有 (left),或者所有 (outer)?这直接决定了结果数据集的完整性和大小。 - 索引的考量:
- 对于
concat(axis=0),如果原始索引不重要,总是考虑ignore_index=True来避免索引重复。 - 对于
merge,如果你想基于索引进行合并,可以使用left_index=True和right_index=True。如果键列是索引,并且数据量很大,pandas在某些情况下会利用索引的有序性来加速合并。
- 对于
- 内存管理: 当处理非常大的DataFrame时,合并操作可能会消耗大量内存。如果遇到内存不足的问题,可以考虑:
- 逐块处理数据(例如,使用
pd.read_csv(chunksize=...))。 - 优化DataFrame的数据类型(例如,使用
category类型代替object类型来存储重复的字符串)。 - 仅选择必要的列进行合并,减少不必要的内存开销。
- 逐块处理数据(例如,使用
总的来说,concat 和 merge 都是pandas数据处理的基石,它们解决的问题截然不同。选择合适的工具,理解其背后的逻辑和潜在的“坑”,能让你在数据处理的道路上走得更稳更快。
终于介绍完啦!小伙伴们,这篇关于《PythonDataFrame合并:concat与merge对比解析》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!
软件业前5月利润增14.2%
- 上一篇
- 软件业前5月利润增14.2%
- 下一篇
- Python视频流处理:OpenCV帧操作详解
-
- 文章 · python教程 | 5小时前 |
- Python语言入门与基础解析
- 296浏览 收藏
-
- 文章 · python教程 | 5小时前 |
- PyMongo导入CSV:类型转换技巧详解
- 351浏览 收藏
-
- 文章 · python教程 | 5小时前 |
- Python列表优势与实用技巧
- 157浏览 收藏
-
- 文章 · python教程 | 5小时前 |
- Pandas修改首行数据技巧分享
- 485浏览 收藏
-
- 文章 · python教程 | 7小时前 |
- Python列表创建技巧全解析
- 283浏览 收藏
-
- 文章 · python教程 | 8小时前 |
- Python计算文件实际占用空间技巧
- 349浏览 收藏
-
- 文章 · python教程 | 9小时前 |
- OpenCV中OCR技术应用详解
- 204浏览 收藏
-
- 文章 · python教程 | 10小时前 |
- Pandas读取Django表格:协议关键作用
- 401浏览 收藏
-
- 文章 · python教程 | 10小时前 | 身份验证 断点续传 requests库 PythonAPI下载 urllib库
- Python调用API下载文件方法
- 227浏览 收藏
-
- 文章 · python教程 | 10小时前 |
- Windows7安装RtMidi失败解决办法
- 400浏览 收藏
-
- 文章 · python教程 | 10小时前 |
- Python异步任务优化技巧分享
- 327浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3182次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3393次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3424次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4528次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3802次使用
-
- 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浏览

