pandas.dataframe.compare()仅适用于≥1.1.0版本,且要求两表索引、列名、长度完全一致;需先验证版本与结构,合理设置keep_shape和keep_equal,注意列顺序与数据类型兼容性。

用 pandas.DataFrame.compare() 前先确认版本和数据结构
这个方法只在 pandas ≥ 1.1.0 才有,低于这版本会报 AttributeError: 'DataFrame' object has no attribute 'compare'。而且它默认只比较同索引、同列名、同长度的两表——哪怕只是索引顺序不一致,结果也会全是 NaN 或直接报错。
实操建议:
- 先跑
pandas.__version__确认版本;低于 1.1.0 就别折腾,改用merge(how='outer', indicator=True)或手动 diff - 用
df1.equals(df2)快速判断是否完全一致,省得白跑compare() - 务必确保
df1.index.equals(df2.index)和df1.columns.equals(df2.columns)都为True;不满足就先reindex或sort_index(axis=0).sort_index(axis=1)
compare() 的 keep_shape 和 keep_equal 怎么选
这两个参数控制输出“看起来多干净”,但影响信息完整性。默认 keep_shape=False 会删掉所有没差异的行/列,keep_equal=False 会把相同值全换成 NaN——看着清爽,但容易漏掉“某列全相同却该被关注”的情况(比如配置字段本就不该变)。
实操建议:
- 查数据漂移或 ETL 异常时,设
keep_shape=True, keep_equal=True,保留原始行列结构,靠颜色或notna()定位差异 - 做发布前核对,且确认只有少数字段可能变,可用
keep_equal=False让结果更紧凑 -
keep_shape=True下,空行/空列仍存在,但内容是NaN;注意别误判成“没变化”
对比结果里 self 和 other 列方向反了怎么办
结果 DataFrame 的列是 MultiIndex:(col_name, 'self') 和 (col_name, 'other')。新手常以为 'self' 是旧版、'other' 是新版,其实完全取决于你调用时的顺序:df_old.compare(df_new) 中 df_old 是 self,df_new 是 other——名字不带时间含义,纯按参数位置定。
实操建议:
- 命名变量时就体现意图,比如
before.compare(after),别用df1.compare(df2) - 需要导出给人看,立刻重命名列:
diff.columns = diff.columns.map(lambda x: (x[0], 'before' if x[1]=='self' else 'after')) - 用
diff.stack(0).swaplevel().sort_index()展开成三元组(列名,行索引,self/other),更适合进一步分析
性能差、内存爆了?不是数据大,是 compare() 默认太“老实”
它内部会把两表广播对齐再逐元素比,遇到 10w 行 × 100 列的表,中间对象可能膨胀数倍。尤其当两表仅几列不同,却硬要生成完整差异矩阵时,纯属浪费。
实操建议:
- 先用
df1.columns != df2.columns和df1.dtypes != df2.dtypes快速扫一遍 schema 差异,避免进compare()前就翻车 - 只关心特定列?提前切片:
df1[cols].compare(df2[cols]),别喂全量 - 真要处理大表,放弃
compare(),改用df1.eq(df2).all().all()先粗筛,再对 False 列单列计算df1[col] != df2[col]
最常被忽略的一点:compare() 不支持 category / nullable integer 类型的稳定比较,遇到 Int64Dtype 或混入 pd.NA,结果可能错漏——务必先 astype('object') 或统一转成 string 再比。










