对比两个DataFrame,定位数据不匹配的行、列及对应值
DataFrame数据对比与不匹配信息提取
需求说明
我有两个DataFrame需要对比,需返回数据不匹配发生的行号、列名,以及实际值与预期值的对应信息。两个DataFrame均包含ID、Name、Location、Program列,要求输出格式如下:
Mismatched Rows: (Row 2, columns=[channelName,sublobName]),(Row 3, columns=[sublobName])
原始代码(存在问题)
df_actual = pd.DataFrame({'Partner': ['P1', 'P2', 'P3'], 'lobName': ['L1', 'L2', 'L3'], 'sublobName': ['S1', 'S2', 'S3'], 'channelName': ['C1', 'C5', 'C3'], 'value1': [1, 2, 3]}) df_rpt_all1 = pd.DataFrame({'Partner': ['P1', 'P2', 'P3'], 'lobName': ['L1', 'L2', 'L3'], 'sublobName': ['S1', 'S2', 'S3'], 'channelName': ['C1', 'C2', 'C3'], 'value1': [1, 2, 6]}) merged_df = df_rpt_all1.merge(df_actual, how='left', on=['ID','Name','Location','Program'], indicator=True) mismatched_info = [] for index, row in merged_df.iterrows(): if row['_merge'] == 'left_only': non_matching_cols = [] non_matching_vals = [] for col in merged_df.columns: if col.endswith('_x') and row[col] != row[col.replace('_x', '_y')]: non_matching_cols.append(col) non_matching_vals.append(row[col]) mismatched_info.append(f"(Row {index + 1}, columns={non_matching_cols}, values={dict(zip(non_matching_cols, non_matching_vals))})") if mismatched_info: result = '\n'.join(mismatched_info) print(f"Mismatched Rows:\n{result}") else: print("No mismatches found.")
问题分析与修正方案
原始代码的问题
- 合并键错误:代码中用
['ID','Name','Location','Program']作为合并键,但实际定义的DataFrame里只有Partner、lobName等列,不存在这些键,导致合并后无法正确匹配行。 - 不匹配判断逻辑错误:
left_only只代表左表有但右表没有的行,但我们需要的是同一主键行中列值不匹配的情况,而非行存在性差异。 - 列名处理错误:对比时保留了
_x、_y后缀,应该还原为原始列名,同时需要同时记录预期值和实际值。
修正后的代码
import pandas as pd # 定义两个DataFrame(这里假设用Partner作为唯一标识主键,实际可替换为ID等列) df_actual = pd.DataFrame({'Partner': ['P1', 'P2', 'P3'], 'lobName': ['L1', 'L2', 'L3'], 'sublobName': ['S1', 'S2', 'S3'], 'channelName': ['C1', 'C5', 'C3'], 'value1': [1, 2, 3]}) df_expected = pd.DataFrame({'Partner': ['P1', 'P2', 'P3'], 'lobName': ['L1', 'L2', 'L3'], 'sublobName': ['S1', 'S2', 'S3'], 'channelName': ['C1', 'C2', 'C3'], 'value1': [1, 2, 6]}) # 用主键合并两个表,区分预期值和实际值的后缀 merged_df = df_expected.merge(df_actual, on='Partner', suffixes=('_expected', '_actual'), indicator=True) mismatched_info = [] # 遍历每一行 for idx, row in merged_df.iterrows(): row_num = idx + 1 non_matching_cols = [] # 遍历所有需要对比的列(排除主键) for col in df_expected.columns: if col == 'Partner': continue expected_val = row[f"{col}_expected"] actual_val = row[f"{col}_actual"] # 处理空值情况,避免NaN != NaN的逻辑错误 if pd.notna(expected_val) and pd.notna(actual_val): if expected_val != actual_val: non_matching_cols.append(col) elif pd.isna(expected_val) != pd.isna(actual_val): # 一个为空一个不为空,判定为不匹配 non_matching_cols.append(col) # 记录不匹配信息 if non_matching_cols: col_str = f"[{','.join(non_matching_cols)}]" mismatched_info.append(f"(Row {row_num}, columns={col_str})") # 输出结果 if mismatched_info: result = ','.join(mismatched_info) print(f"Mismatched Rows: {result}") else: print("No mismatches found.")
输出结果
运行修正后的代码,会得到符合要求的输出:
Mismatched Rows: (Row 2, columns=[channelName]),(Row 3, columns=[value1])
内容的提问来源于stack exchange,提问作者Abinash Mohanty
相关产品推荐
相关产品推荐

