如何基于公共标识列合并两个 DataFrame 并优先保留第二张表的重复行
发布时间 - 2026-01-07 00:00:00 点击率:次本文介绍一种高效、可扩展的方法,使用 pd.concat() 配合布尔索引实现两表按指定列(支持单列或多列)合并:保留 df2 的全部行,仅补充 df1 中在 df2 中完全不存在的行(含重复),避免 combine_first 导致的重复膨胀问题。
在 Pandas 数据处理中,当需要“以 df2 为主、df1 为辅”合并两个结构相同的数据框(即:保留 df2 的所有行,同时只追加 df1 中在 df2 中完全未出现过的记录(包括重复行)),直接使用 combine_first 或 merge 往往会因索引对齐逻辑导致重复行被错误广播——正如示例中 A=123 的行从 df2 的 4 行 + df1 的 2 行,意外膨胀为 8 行。
正确解法是:显式分离“覆盖部分”与“补充部分”,再垂直拼接:
✅ 推荐方案:concat + 布尔索引(高效、清晰、支持多列)
import pandas as pd
from io import StringIO
# 示例数据
csv1_data = """A,B,C,D
123,xyz,S1,1111
123,xyz,S1,1111
234,mno,S3,2222
999,abc,S9,9999
999,abc,S9,9999"""
csv2_data = """A,B,C,D
123,abc,S1,1234
123,abc,S1,1234
123,abc,S1,1234
123,cde,S2,2345
234,nop,S3,
567,pqr,S5,5555"""
df1 = pd.read_csv(StringIO(csv1_data), dtype=str, keep_default_na=False)
df2 = pd.read_csv(StringIO(csv2_data), dtype=str, keep_default_na=False)
# ✅ 核心逻辑:取 df2 全部 + df1 中 A 值不在 df2.A 中的行(保留原始重复)
key_col = 'A'
result = pd.concat([
df2,
df1[~df1[key_col].isin(df2[key_col])]
], ignore_index=True)
print(result)输出:
A B C D 0 123 abc S1 1234 1 123 abc S1 1234 2 123 abc S1 1234 3 123 cde S2 2345 4 234 nop S3 5 567 pqr S5 5555 6 999 abc S9 9999 7 999 abc S9 9999
? 支持多列联合标识(动态适配)
当关键标识不止一列(如 ['A', 'B'] 或 ['A', 'A1', 'A2']),只需将列名列表传入,并利用 MultiIndex.isin() 进行精确匹配:
key_cols = ['A'] # 可动态替换为 ['A', 'B']、['A', 'A1', 'A2'] 等 # 构建 MultiIndex 进行成员判断 df1_mask = ~df1.set_index(key_cols).index.isin(df2.set_index(key_cols).index) result = pd.concat([df2, df1[df1_mask]], ignore_index=True)
? 性能提示:该方法时间复杂度为 O(n + m),远优于基于索引重排的 combine_first(易触发内部广播),特别适合百万级数据场景。
⚠️ 注意事项与最佳实践
-
不要用 set_index 后 combine_first:它会将 df1 中每个匹配索引的所有行与 df2 中对应索引的所有行做笛
卡尔式填充,导致重复爆炸; - isin 判断基于值而非位置:确保 key 列类型一致(如都为字符串),避免因 int/str 混合导致匹配失败;
-
空值(NaN)需预处理:isin() 对 NaN 默认返回 False,若业务允许 NaN 作为有效键,建议先用 fillna() 统一占位符(如 "
"); - 内存友好:全程不修改原 DataFrame,无需 .copy(),ignore_index=True 保证结果索引连续。
综上,pd.concat([df2, df1[~df1[key].isin(df2[key])]]) 是解决“主从式去重合并”的简洁、健壮且高性能的标准范式,兼顾可读性与工程可维护性。
# csv
# pandas
# NULL
# 字符串
# int
# copy
# 布尔
# 卡尔
# 只需
# 不存在
# 数据处理
# 而非
# 高性能
# 会将
# 往往会
# 都为
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】
怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?
如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环
Laravel Admin后台管理框架推荐_Laravel快速开发后台工具
如何在IIS管理器中快速创建并配置网站?
微信h5制作网站有哪些,免费微信H5页面制作工具?
C++时间戳转换成日期时间的步骤和示例代码
如何获取PHP WAP自助建站系统源码?
Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言
如何在万网开始建站?分步指南解析
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
成都网站制作公司哪家好,四川省职工服务网是做什么用?
如何挑选优质建站一级代理提升网站排名?
购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?
今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】
智能起名网站制作软件有哪些,制作logo的软件?
如何基于PHP生成高效IDC网络公司建站源码?
Laravel如何使用Scope本地作用域_Laravel模型常用查询逻辑封装技巧【手册】
Laravel如何自定义分页视图?(Pagination示例)
制作公司内部网站有哪些,内网如何建网站?
桂林网站制作公司有哪些,桂林马拉松怎么报名?
实现点击下箭头变上箭头来回切换的两种方法【推荐】
Laravel如何实现数据导出到PDF_Laravel使用snappy生成网页快照PDF【方案】
PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】
Laravel如何创建自定义Artisan命令?(代码示例)
Python面向对象测试方法_mock解析【教程】
ChatGPT怎么生成Excel公式_ChatGPT公式生成方法【指南】
Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案
高端网站建设与定制开发一站式解决方案 中企动力
1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤
历史网站制作软件,华为如何找回被删除的网站?
网站图片在线制作软件,怎么在图片上做链接?
如何快速生成ASP一键建站模板并优化安全性?
LinuxShell函数封装方法_脚本复用设计思路【教程】
如何选择可靠的免备案建站服务器?
如何快速查询域名建站关键信息?
Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】
教你用AI将一段旋律扩展成一首完整的曲子
JS实现鼠标移上去显示图片或微信二维码
如何在云虚拟主机上快速搭建个人网站?
如何在IIS中新建站点并配置端口与物理路径?
JS经典正则表达式笔试题汇总
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
5种Android数据存储方式汇总
装修招标网站设计制作流程,装修招标流程?
Laravel全局作用域是什么_Laravel Eloquent Global Scopes应用指南
用yum安装MySQLdb模块的步骤方法
Laravel如何升级到最新的版本_Laravel版本升级流程与兼容性处理
Python并发异常传播_错误处理解析【教程】
如何在IIS中配置站点IP、端口及主机头?
上一篇:centos7不能访问外网怎么办
下一篇:docker可以拷贝镜像环境吗
上一篇:centos7不能访问外网怎么办
下一篇:docker可以拷贝镜像环境吗


卡尔式填充,导致重复爆炸;