Python中比对含同名列的异结构DataFrame差异实现方法
pandas 非对齐DataFrame按关联键差异比对实现
pandas内置的.compare()方法强制要求两个输入DataFrame的列名、索引完全对齐,你的场景下两个表列数、行数都不一致,且需要按Sport字段做关联匹配,没法直接调用该方法,可按以下逻辑实现:
核心判定逻辑拆分
- 处理abc存在、xyz缺失的Sport值:直接标注不存在
- 处理xyz存在、abc缺失的Sport值:输出对应
SportLeague值,标注为待删除 - 处理两边共有的Sport值:逐行匹配
Year、ID字段,任意字段不一致则记录差异,输出对应SportLeague作为标识
可直接运行的实现代码
import pandas as pd import numpy as np # 测试用例数据 abc = {'Sport' : ['Football', 'Basketball', 'Baseball', 'Hockey'], 'Year' : ['2021','2021','2022','2022'], 'ID' : ['1','2','3','4']} abc = pd.DataFrame(abc) xyz = {'Sport' : ['Football', 'Football', 'Basketball', 'Baseball', 'Hockey', 'Soccer'], 'SportLeague' : ['Football:NFL', 'Football:XFL', 'Basketball:NBA', 'Baseball:MLB', 'Hockey:NHL', 'Soccer:MLS'], 'Year' : ['2022','2019', '2022','2022','2022', '2022'], 'ID' : ['2','0', '3','2','4', '1']} xyz = pd.DataFrame(xyz).sort_values(by=['ID'], ascending=True) diff_records = [] # 提取两边Sport字段的集合 abc_sports = set(abc['Sport']) xyz_sports = set(xyz['Sport']) # 1. 判定abc存在但xyz缺失的Sport for sport in abc_sports - xyz_sports: diff_records.append({ "匹配标识": sport, "差异内容": "Not Found in `xyz data frame`" }) # 2. 判定xyz存在但abc缺失的Sport for _, row in xyz[~xyz['Sport'].isin(abc_sports)].iterrows(): league_tag = row['SportLeague'] diff_records.append({ "匹配标识": league_tag, "差异内容": f"Remove `{league_tag}`" }) # 3. 判定两边共有的Sport下Year、ID字段的差异 for _, xyz_row in xyz[xyz['Sport'].isin(abc_sports)].iterrows(): league_tag = xyz_row['SportLeague'] xyz_year, xyz_id = xyz_row['Year'], xyz_row['ID'] # 取abc中同Sport的对应记录 abc_match = abc[abc['Sport'] == xyz_row['Sport']].iloc[0] abc_year, abc_id = abc_match['Year'], abc_match['ID'] if (xyz_year != abc_year) or (xyz_id != abc_id): diff_records.append({ "匹配标识": league_tag, "差异内容": f"Change from {xyz_year} and {xyz_id} to {abc_year} and {abc_id}" }) # 转换为DataFrame输出,仅保留存在差异的记录 diff_result = pd.DataFrame(diff_records) print(diff_result)
测试用例运行输出
匹配标识 差异内容 0 Soccer:MLS Remove `Soccer:MLS` 1 Football:XFL Change from 2019 and 0 to 2021 and 1 2 Football:NFL Change from 2022 and 2 to 2021 and 1 3 Baseball:MLB Change from 2022 and 2 to 2022 and 3
适配说明
- 兼容同一个Sport在xyz中对应多条记录(如示例中Football对应NFL、XFL两个联赛条目)的场景,会逐行校验不遗漏
- 输出的匹配标识统一使用xyz表的
SportLeague字段值,符合输出要求,不会直接返回Sport原值 - 无需提前对齐两个表的索引、列数、行数,不存在内置compare方法的列不匹配报错问题
内容的提问来源于stack exchange,提问作者HelpMeCode
相关产品推荐
相关产品推荐

