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。你可以把它想象成把几个表格直接首尾相连,或者并排摆放。
示例:
立即学习“Python免费学习笔记(深入)”;
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操作。它基于列的值进行匹配,而不是简单地堆叠。
示例:
立即学习“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)
我个人觉得,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 的用武之地了。pd.merge 最强大的地方在于它能够模拟SQL的各种连接操作,通过 how 参数来精确控制连接的逻辑。
how 参数的奥秘:
# 示例数据 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 和 merge 都是pandas数据处理的基石,它们解决的问题截然不同。选择合适的工具,理解其背后的逻辑和潜在的“坑”,能让你在数据处理的道路上走得更稳更快。
以上就是Python中如何合并多个DataFrame?concat与merge对比指南的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号