Python中对比同结构DataFrame:如何在差异结果中标记记录所属原DataFrame及差异列
解决DataFrame差异对比的来源标识与列差异问题
没问题!你现在的代码能找出两个DataFrame的差异记录,但缺少了记录来源和具体差异列的信息,我给你两个实用方案:
方案一:实现你期望的输出格式
这个方案会给每个记录加上来源DataFrame的标识,生成你想要的结果:
import pandas as pd # 示例数据(替换成你的真实DataFrame即可) df1 = pd.DataFrame({ 'Name': ['Naxi', 'Karan', 'Tanya'], 'Age': [27, 25, 27], 'Gender': ['Male', 'Male', 'Female'] }) df2 = pd.DataFrame({ 'Name': ['Naxi', 'Tanya', 'Karan'], 'Age': [27, 27, 24], 'Gender': ['Male', 'Female', 'Male'] }) # 1. 给每个DataFrame添加来源标识列 df1['Dataframe'] = 'df1' df2['Dataframe'] = 'df2' # 2. 合并两个DataFrame combined_df = pd.concat([df1, df2]) # 3. 按原始数据列(排除来源列)分组,找出只出现一次的记录(即差异记录) original_columns = df1.columns.drop('Dataframe') grouped = combined_df.groupby(list(original_columns)) # 提取差异记录的索引 diff_indices = [] for group in grouped.groups.values(): if len(group) == 1: diff_indices.extend(group) # 4. 获取最终差异结果并保存 diff_result = combined_df.loc[diff_indices].sort_values('Name') print(diff_result) diff_result.to_csv('diff_with_source.csv', index=False)
运行后生成的diff_with_source.csv内容和你期望的完全一致:
| Name | Age | Gender | Dataframe |
|---|---|---|---|
| Karan | 25 | Male | df1 |
| Karan | 24 | Male | df2 |
方案二:额外标记具体差异列
如果想进一步知道哪些列的值不一样,可以用这个增强版方案,它会新增一列显示差异的列名:
import pandas as pd # 复用前面的df1和df2数据 df1['Dataframe'] = 'df1' df2['Dataframe'] = 'df2' original_columns = df1.columns.drop('Dataframe') # 1. 按主键(这里用Name)做外连接合并 merged = pd.merge( df1.drop('Dataframe', axis=1), df2.drop('Dataframe', axis=1), on='Name', how='outer', suffixes=('_df1', '_df2'), indicator=True ) # 2. 找出所有非完全匹配的行 diff_rows = merged[merged['_merge'] != 'both'] # 3. 定义函数,找出每行的差异列 def get_diff_columns(row): diff_cols = [] for col in original_columns.drop('Name'): if row[f'{col}_df1'] != row[f'{col}_df2']: diff_cols.append(col) return ', '.join(diff_cols) if diff_cols else 'Only in one dataframe' diff_rows['Diff_Columns'] = diff_rows.apply(get_diff_columns, axis=1) # 4. 整理成易读的格式 final_result = pd.DataFrame() for _, row in diff_rows.iterrows(): if row['_merge'] == 'left_only': final_result = pd.concat([final_result, pd.DataFrame({ 'Name': [row['Name']], 'Age': [row['Age_df1']], 'Gender': [row['Gender_df1']], 'Dataframe': ['df1'], 'Diff_Columns': ['Only in df1'] })]) elif row['_merge'] == 'right_only': final_result = pd.concat([final_result, pd.DataFrame({ 'Name': [row['Name']], 'Age': [row['Age_df2']], 'Gender': [row['Gender_df2']], 'Dataframe': ['df2'], 'Diff_Columns': ['Only in df2'] })]) else: # 两边都存在但值有差异的情况 final_result = pd.concat([final_result, pd.DataFrame({ 'Name': [row['Name'], row['Name']], 'Age': [row['Age_df1'], row['Age_df2']], 'Gender': [row['Gender_df1'], row['Gender_df2']], 'Dataframe': ['df1', 'df2'], 'Diff_Columns': [row['Diff_Columns']]*2 })]) final_result = final_result.reset_index(drop=True) print(final_result) final_result.to_csv('diff_with_details.csv', index=False)
这个方案的输出会更详细,能直接看到差异点:
| Name | Age | Gender | Dataframe | Diff_Columns |
|---|---|---|---|---|
| Karan | 25 | Male | df1 | Age |
| Karan | 24 | Male | df2 | Age |
核心思路说明
- 基础方案通过给每个DataFrame添加来源标识,再按原始数据列分组,筛选出只出现一次的记录,就能准确定位差异记录及其来源。
- 增强方案通过外连接合并两个表,对比每行的列值,标记出具体的差异列,让结果的可读性更强。
内容的提问来源于stack exchange,提问作者Naxi
相关产品推荐
相关产品推荐

