讲师中心 微信公众号
AI工具推荐 视频效率加速

Python中如何合并多个DataFrame?concat与merge对比指南

轻杰酱_6697

轻杰酱_6697

发布时间:2025-07-05 14:01:21

|

1250人浏览过

|

来源于php中文网

原创

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?concat与merge对比指南

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

Python中如何合并多个DataFrame?concat与merge对比指南

解决方案

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

Python中如何合并多个DataFrame?concat与merge对比指南

pd.concat() 这个函数主要用于沿着某个轴(行或列)堆叠或连接DataFrame。你可以把它想象成把几个表格直接首尾相连,或者并排摆放。

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

示例:

立即学习“Python免费学习笔记(深入)”;

Python中如何合并多个DataFrame?concat与merge对比指南
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有相同列名(非键列)时,用于区分这些列的后缀。

示例:

立即学习“Python免费学习笔记(深入)”;

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 参数来精确控制连接的逻辑。

python-flask-vue-creator
python-flask-vue-creator

创建 Flask + Vue.js 全栈项目,采用单端口架构、uv 依赖管理、结构化日志和生产级前端设计。当用户要求以下操作时触发:创建新的 Flask+Vue 项目、搭建 Web 应用、构建全栈 Python+Vue 应用、初始化 Flask Web 项目、设置单端口 Flask 前后端项目。触发词:新建项目、创建项目、搭建项目、Flask项目、Vue项目。

下载

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是订单明细,另一个是产品信息,你需要把产品名称、价格等信息加到订单明细中。

最佳实践建议:

  1. 数据清洗先行: 在进行任何合并操作之前,务必确保你的键列(或其他需要对齐的列)是干净的。检查数据类型是否一致,是否存在前导/尾随空格,大小写是否统一。一个小小的差异都可能导致 merge 失败或 concat 产生 NaN。
  2. 明确 how 参数: 对于 merge,一定要想清楚你需要哪种连接类型。是只保留匹配项 (inner),还是保留左边所有 (left),或者所有 (outer)?这直接决定了结果数据集的完整性和大小。
  3. 索引的考量:
    • 对于 concat(axis=0),如果原始索引不重要,总是考虑 ignore_index=True 来避免索引重复。
    • 对于 merge,如果你想基于索引进行合并,可以使用 left_index=True 和 right_index=True。如果键列是索引,并且数据量很大,pandas在某些情况下会利用索引的有序性来加速合并。
  4. 内存管理: 当处理非常大的DataFrame时,合并操作可能会消耗大量内存。如果遇到内存不足的问题,可以考虑:
    • 逐块处理数据(例如,使用 pd.read_csv(chunksize=...))。
    • 优化DataFrame的数据类型(例如,使用 category 类型代替 object 类型来存储重复的字符串)。
    • 仅选择必要的列进行合并,减少不必要的内存开销。

总的来说,concat 和 merge 都是pandas数据处理的基石,它们解决的问题截然不同。选择合适的工具,理解其背后的逻辑和潜在的“坑”,能让你在数据处理的道路上走得更稳更快。

热门AI工具

更多
PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

4683

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

971

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

1229

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

6681

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

3423

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

6660

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

9201

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

1250

2024.04.29

Uvicorn 报错与问题解决教程
Uvicorn 报错与问题解决教程

本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。

0

2026.11.02

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn