如何匹配两个Pandas DataFrame,识别匹配行并展示差异内容
问题原因
你原有代码是基于行索引位置逐行对比,两个DataFrame仅行顺序不同时,同索引位置的内容不一致就会被误识别为差异。
修复代码(按行内容匹配,忽略顺序)
方案1:基于唯一主键对齐对比(推荐,适用有唯一标识列的场景,比如本例的Name列)
这种方式可以精准找到两个表中同主键的行差异,也能自动识别行数不同的情况:
import pandas as pd import numpy as np # 样例数据 df1 = pd.DataFrame([['tom', 10],['nick',15], ['juli',14]], columns = ['Name', 'Age']) df2 = pd.DataFrame([['nick', 15],['tom', 10], ['juli',14]], columns = ['Name', 'Age']) # 以Name为唯一主键做外连接对齐,标记行来源 df_compare = df1.merge(df2, on='Name', how='outer', suffixes=('_df1', '_df2'), indicator=True) # 处理行数不同的情况:提取仅在单表存在的行 only_df1 = df_compare[df_compare['_merge'] == 'left_only'] only_df2 = df_compare[df_compare['_merge'] == 'right_only'] # 提取两表都存在的行的字段差异 common_rows = df_compare[df_compare['_merge'] == 'both'].copy() diff_rows = [] for col in df1.columns: if col == 'Name': # 跳过主键列 continue mask = common_rows[f'{col}_df1'] != common_rows[f'{col}_df2'] diff_part = common_rows[mask][['Name', f'{col}_df1', f'{col}_df2']] diff_part['diff_col'] = col diff_rows.append(diff_part) # 合并所有差异 if diff_rows: divergences = pd.concat(diff_rows).set_index(['Name', 'diff_col']).rename(columns={'Age_df1':'df1', 'Age_df2':'df2'}) else: divergences = pd.DataFrame(columns=['df1', 'df2']) print("仅在df1存在的行:") print(only_df1[['Name', 'Age_df1']] if len(only_df1) > 0 else "无") print("\n仅在df2存在的行:") print(only_df2[['Name', 'Age_df2']] if len(only_df2) > 0 else "无") print("\n共同存在行的字段差异:") print(divergences)
你的样例运行后,共同存在行的差异会输出你期望的空DataFrame结果。
方案2:无主键时,校验行集合完全一致(忽略顺序)
如果没有唯一主键,仅需要判断两个表的所有行的集合完全相等,直接排序后对比即可:
# 按所有列排序后重置索引,消除行顺序影响 df1_sorted = df1.sort_values(by=list(df1.columns)).reset_index(drop=True) df2_sorted = df2.sort_values(by=list(df2.columns)).reset_index(drop=True) # 优先判断行数是否相等 if len(df1_sorted) != len(df2_sorted): print(f"两个DataFrame行数不同,df1有{len(df1)}行,df2有{len(df2)}行") else: # 复用你原有逻辑对比排序后的表 ne_stacked = (df1_sorted != df2_sorted).stack() changed = ne_stacked[ne_stacked] changed.index.names = ['id', 'col'] difference_locations = np.where(df1_sorted != df2_sorted) changed_from = df1_sorted.values[difference_locations] changed_to = df2_sorted.values[difference_locations] divergences = pd.DataFrame({'df1': changed_from, "df2": changed_to}, index=changed.index) print(divergences)
行数不同的处理逻辑
- 用方案1的外连接方式时,会自动识别
仅在df1存在的行和仅在df2存在的行,可以直接输出这些行告知用户哪边多了数据 - 用方案2的排序对比方式时,优先判断
len(df1) == len(df2),不相等直接提示行数差异,不需要再做字段级对比
内容的提问来源于stack exchange,提问作者danielssl
相关产品推荐
相关产品推荐

