python - Python生成两个文件的 "fuzzy"差异,带float的近似比较

标签 python floating-point fuzzy-comparison inexact-arithmetic

我在比较两个文件时遇到了问题。基本上,我想要做的是在两个文件之间进行类似 UNIX 的差异,例如:

$ diff -u 左文件右文件

但是我的两个文件包含 float ;并且因为这些文件是在不同的体系结构上生成的(但计算相同的东西),所以 float 值并不完全相同(它们可能相差 1e-10)。但是我通过“比较”文件寻求的是找到我认为是显着差异的东西(例如差异大于 1e-4);在使用 UNIX 命令 diff 时,我几乎所有包含 float 值的行都不同!这就是我的问题:如何获得像“diff -u”提供的结果差异,但对 float 比较的限制较少?

我想我会写一个 Python 的脚本来做到这一点,并找到了提供 diff-like 比较的模块 difflib。但是我找到的文档解释了如何按原样使用它(通过单一方法),并解释了内部对象,但是我找不到任何关于如何自定义 difflib 对象以满足我的需要的信息(比如只重写比较方法或这样)......我想一个解决方案可能是检索统一的差异,并“手动”解析它以删除我的“错误”差异,这并不优雅;我更愿意使用已经存在的框架。

那么,有人知道如何定制这个库以便我可以做我想做的事吗?或者至少给我指出正确的方向...如果不是用 Python,也许 shell 脚本可以胜任这项工作?

任何帮助将不胜感激!预先感谢您的回答!

最佳答案

在您的情况下,我们专注于 general case :在我们将东西传递给 difflib 之前,我们需要检测并单独处理包含 float 的行。这是一个基本方法,如果你想生成增量、上下文行等,你可以在此基础上构建。请注意,将 float 作为实际 float 而不是字符串进行模糊比较更容易(尽管您可以编写逐列差异代码,并忽略 1-e4 之后的字符)。

import re

float_pat = re.compile('([+-]?\d*\.\d*)')
def fuzzydiffer(line1,line2):
    """Perform fuzzy-diff on floats, else normal diff."""
    floats1 = float_pat.findall(line1)
    if not floats1:
        pass # run your usual diff() 
    else:
        floats2 = float_pat.findall(line2)
        for (f1,f2) in zip(floats1,floats2):
            (col1,col2) = line1.index(f1),line2.index(f2)
            if not fuzzy_float_cmp(f1,f2):
                print "Lines mismatch at col %d", col1, line1, line2
            continue
    # or use a list comprehension like all(fuzzy_float_cmp(f1,f2) for f1,f2 in zip(float_pat.findall(line1),float_pat.findall(line2)))
    #return match

def fuzzy_float_cmp(f1,f2,epsilon=1e-4):
    """Fuzzy-compare two strings representing floats."""
    float1,float2 = float(f1),float(f2)
    return (abs(float1-float2) < epsilon)

一些测试:

fuzzydiffer('text: 558.113509766 +23477547.6407 -0.867086648057 0.009291785451', 
'text: 558.11351 +23477547.6406 -0.86708665 0.009292000001')

作为奖励,这里有一个突出显示列差异的版本:

import re

float_pat = re.compile('([+-]?\d*\.\d*)')
def fuzzydiffer(line1,line2):
    """Perform fuzzy-diff on floats, else normal diff."""
    floats1 = float_pat.findall(line1)
    if not floats1:
        pass # run your usual diff() 
    else:
        match = True
        coldiffs1 = ' '*len(line1)
        coldiffs2 = ' '*len(line2)
        floats2 = float_pat.findall(line2)
        for (f1,f2) in zip(floats1,floats2):
            (col1s,col2s) = line1.index(f1),line2.index(f2)
            col1e = col1s + len(f1)
            col2e = col2s + len(f2)
            if not fuzzy_float_cmp(f1,f2):
                match = False
                #print 'Lines mismatch:'
                coldiffs1 = coldiffs1[:col1s] + ('v'*len(f1)) + coldiffs1[col1e:]
                coldiffs2 = coldiffs2[:col2s] + ('^'*len(f2)) + coldiffs2[col2e:]
            #continue # if you only need to highlight first mismatch
        if not match:
            print 'Lines mismatch:'
            print '  ', coldiffs1
            print '< ', line1
            print '> ', line2
            print '  ', coldiffs2
        # or use a list comprehension like
        #    all()
        #return True

def fuzzy_float_cmp(f1,f2,epsilon=1e-4):
    """Fuzzy-compare two strings representing floats."""
    print "Comparing:", f1, f2
    float1,float2 = float(f1),float(f2)
    return (abs(float1-float2) < epsilon)

关于python - Python生成两个文件的 "fuzzy"差异,带float的近似比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3108274/

相关文章:

python - 在 XML 中查找元素同级的最 Pythonic 方法

objective-c - 如何将 float 舍入到小数点后两位?

c++ - 声明 float 还是强制 float ?

c - C 中 double 数据类型的最大精度是多少?

elasticsearch - 在 ElasticSearch 中以百分比调整模糊级别

python - 使用 TRE : strange unicode behavior 在 python 中近似 RegEx

python - np.array 到 python 中的函数 - 'list' 对象不可调用

用于多选项卡绘图的 python matplotlib 和 PyQT - 导航

python - 从第二个元素开始对python中的列表进行排序

sql - SQL模糊联接-MSSQL