
本文介绍如何在 Pandas 中高效对比两个结构相同的 DataFrame,逐列比较并生成含原始值与布尔结果的宽格式结果表,同时规避 DataFrame is highly fragmented 性能警告。
本文介绍如何在 pandas 中高效对比两个结构相同的 dataframe,逐列比较并生成含原始值与布尔结果的宽格式结果表,同时规避 `dataframe is highly fragmented` 性能警告。
在数据验证、ETL 测试或 A/B 结果比对等场景中,常需将两个 DataFrame(如开发环境 vs 测试环境输出)按列逐项对比,并将原始值与比较结果并排展示。若采用循环 + df.insert() 的方式动态构建结果 DataFrame(如原代码中用 while 循环反复赋值列),Pandas 会因频繁内存重分配导致 DataFrame 高度碎片化,触发 PerformanceWarning,严重影响执行效率和可维护性。
推荐使用向量化、一次性拼接的方案,核心思路是:利用 DataFrame.eq() 进行全量布尔比较,再通过 pd.concat() 或 DataFrame.join() 批量合并原始列与结果列,避免逐列插入。
✅ 推荐方案一:join() 实现简洁拼接(推荐首选)
import pandas as pd
import numpy as np
# 示例数据
df1 = pd.DataFrame({'Claim_number': [1001, 1002], 'Claim_Status': ['Closed', 'In Progress']})
df2 = pd.DataFrame({'Claim_number': [1001, 1002], 'Claim_Status': ['Closed', 'Open']})
# 一步到位:左表加后缀、右表加后缀 → 拼接比较结果(自动添加前缀)
out = (df1.join(df2, lsuffix='_df1', rsuffix='_df2')
.join(df1.eq(df2).add_prefix('Comparison_of_'))
)
print(out)
输出:
Claim_number_df1 Claim_Status_df1 Claim_number_df2 Claim_Status_df2 Comparison_of_Claim_number Comparison_of_Claim_Status 0 1001 Closed 1001 Closed True True 1 1002 In Progress 1002 Open True False
✅ 优势:语义清晰、链式调用、零循环、无碎片警告;列名自动区分来源,比较列带统一前缀便于识别。
✅ 推荐方案二:pd.concat() + MultiIndex 灵活重构
若需更精细控制列顺序或命名规则(如要求 Claim_number_df1, Claim_number_df2, Comparison_of_Claim_number 严格相邻),可借助 concat 构建 MultiIndex,再重排并扁平化列名:
# 按层级拼接:'df1', 'df2', 'comparison' 作为一级索引
out = pd.concat({'df1': df1, 'df2': df2, 'comparison': df1.eq(df2)}, axis=1)
# 交换层级使列名在内层,再按 df1 列顺序筛选 + 重命名
out = out.swaplevel(axis=1)[df1.columns]
out.columns = out.columns.map(lambda x: f'{x[1]}_{x[0]}'
if x[0] == 'comparison'
else f'{x[1]}_{x[0]}')
print(out)
输出(完全匹配题目期望格式):
Claim_number_df1 Claim_number_df2 comparison_Claim_number Claim_Status_df1 Claim_Status_df2 comparison_Claim_Status 0 1001 1002 True Closed Closed True 1 1002 1002 True In Progress Open False
⚠️ 注意事项:
- df1.eq(df2) 要求两 DataFrame 索引对齐且列名完全一致;若索引不同,需先 reset_index(drop=True) 对齐;
- 列名含空格或特殊字符时,add_prefix() 和 map() 命名逻辑需额外处理(建议预清洗列名);
- 对于超大 DataFrame,eq() 比较本身为内存密集型操作,必要时可分块处理或使用 dask。
✅ 总结
| 方案 | 适用场景 | 关键优势 | 是否规避警告 |
|---|---|---|---|
| join() + eq() | 快速原型、列数不多、命名规则宽松 | 代码最简,性能最优 | ✅ 完全规避 |
| concat() + MultiIndex | 需精确控制列序/命名、复杂报告需求 | 灵活性高,扩展性强 | ✅ 完全规避 |
永远避免在循环中反复向 DataFrame 添加列——这是引发 PerformanceWarning 的根源。坚持“一次性构造、向量化计算、批量拼接”原则,即可写出高性能、易维护的 DataFrame 对比逻辑。











