自定义DataFrame.compare函数实现浮点型数据容差比较
Pandas中让DataFrame.compare忽略浮点微小差异的实现方法
原生pandas.DataFrame.compare可以高效对比结构一致的DataFrame,值相同的单元格会返回NaN,能快速定位差异。但处理浮点型数据时,哪怕是极小的精度差异(比如1.11和1.1099999999),都会被判定为不同,导致输出里全是差异,无法快速找到真正的大差异。
示例对比
整数对比的正常表现
import pandas as pd df1 = pd.DataFrame({'A': [10, 11], 'B': [20, 22]}) df2 = pd.DataFrame({'A': [10, 11], 'B': [20, 23]}) print(df1.compare(df2))
输出:
A B self other self other 0 NaN NaN NaN NaN 1 NaN NaN 22 23
浮点对比的问题场景
df3 = pd.DataFrame({'A': [1.11, 1.12], 'B': [1.21, 1.22]}) df4 = pd.DataFrame({'A': [1.1099, 1.1199], 'B': [1.2099, 1.2001]}) print(df3.compare(df4))
原生输出会把所有浮点行标记为差异,但我们期望只保留真正超出容忍度的差异(比如示例中第1行的B列),其余显示NaN:
A B self other self other 0 NaN NaN NaN NaN 1 NaN NaN 1.22 1.2001
解决方案:自定义带容忍度的对比函数
不需要重写__ge__、__le__这类魔法方法,我们可以基于np.isclose自定义对比逻辑,生成和原生compare结构一致的输出:
import pandas as pd import numpy as np def compare_with_tolerance(df_self, df_other, rtol=1e-05, atol=1e-08): # 生成近似相等的掩码,通过rtol和atol控制容忍度 mask = np.isclose(df_self, df_other, rtol=rtol, atol=atol) # 提取self中不相等的值,相等位置设为NaN self_diff = df_self.where(~mask) # 提取other中不相等的值,相等位置设为NaN other_diff = df_other.where(~mask) # 组合成多级列结构,和原生compare对齐 result = pd.concat([self_diff, other_diff], axis=1, keys=['self', 'other']) # 调整列顺序,匹配原生的「列名 -> self/other」层级 result = result.swaplevel(axis=1).sort_index(axis=1) return result # 测试:设置宽松的容忍度,忽略微小浮点差异 df3 = pd.DataFrame({'A': [1.11, 1.12], 'B': [1.21, 1.22]}) df4 = pd.DataFrame({'A': [1.1099, 1.1199], 'B': [1.2099, 1.2001]}) print(compare_with_tolerance(df3, df4, rtol=1e-3))
逻辑说明
np.isclose通过**相对误差(rtol)和绝对误差(atol)**判断浮点数是否近似相等,默认参数适合大多数场景,可根据业务需求调整阈值。- 通过掩码筛选出真正不相等的值,相等位置填充
NaN,再组合成和原生compare完全一致的多级列结构。 - 交换列层级顺序后,输出格式和原生
compare完全对齐,无需额外适配。
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

