如何优化编辑距离代码?

时间:2011-08-12 06:17:16

标签: python optimization loops hadoop edit

如何优化此编辑距离代码,即查找2个值之间的位数变化!例如word1 ='010000001000011111101000001001000110001'              word2 ='010000001000011111101000001011111111111'

当我试图在Hadoop上运行时,需要很长时间才能完成?

如何减少for循环和比较?

#!/usr/bin/python

import os, re, string, sys

from numpy import zeros

def calculateDistance(word1, word2):

    x = zeros( (len(word1)+1, len(word2)+1) )

    for i in range(0,len(word1)+1):

        x[i,0] = i

    for i in range(0,len(word2)+1):

        x[0,i] = i

    for j in range(1,len(word2)+1):

        for i in range(1,len(word1)+1):

            if word1[i-1] == word2[j-1]:

                x[i,j] = x[i-1,j-1]

            else:

                minimum = x[i-1, j] + 1

                if minimum > x[i, j-1] + 1:

                    minimum = x[i, j-1] + 1

                if minimum > x[i-1, j-1] + 1:

                    minimum = x[i-1, j-1] + 1

                x[i,j] = minimum

    return x[len(word1), len(word2)]

3 个答案:

答案 0 :(得分:4)

我在网上找了一个计数算法,我找到了this page,它有几个很好的算法。我最喜欢的是一个单行函数,声称适用于Python 2.6 / 3.0:

return sum( b == '1' for b in bin(word1 ^ word2)[2:] )

我没有Python,所以我无法测试,但如果这个不起作用,请尝试其中一个。关键是计算两个单词的按位异或的1的数量,因为每个差异都会有1个。

计算Hamming distance,对吗?

编辑:我正在尝试理解你的算法,以及你操纵输入的方式,看起来它们实际上是数组,而不仅仅是二进制数。所以我希望你的代码看起来更像:

return sum( a != b for a, b in zip(word1, word2) )

EDIT2:我已经弄清楚你的代码做了什么,而且根本不是汉明距离!它实际上是Levenshtein distance,它计算将一个字符串转换为另一个字符串需要多少次添加,删除或替换(汉明距离只计算替换,因此仅适用于等长的数字字符串)。查看维基百科页面,您的算法或多或少是他们在那里的伪代码的直接端口。正如他们所指出的,长度 m n 的字符串比较的时间和空间复杂度是 O(mn),这很漂亮坏。根据您的需要,他们有一些优化建议,但我不知道您使用此功能,所以我不能说什么对您最好。如果汉明距离对你来说足够好,上面的代码应该足够了(时间复杂度 O(n)),但它对某些字符串集给出不同的结果,即使它们长度相等,比如'0101010101'和'1010101010',它们的汉明距离为10(翻转所有位)和Levenshtein距离2(删除前0并在末尾添加)

答案 1 :(得分:3)

由于你尚未指定你正在使用的编辑距离,我将继续选择并假设它是Levenshtein距离。在这种情况下,你可以在这里和那里削减一些操作:

def levenshtein(a,b):
    "Calculates the Levenshtein distance between a and b."
    n, m = len(a), len(b)
    if n > m:
        # Make sure n <= m, to use O(min(n,m)) space.
        # Not really important to the algorithm anyway.
        a,b = b,a
        n,m = m,n

    current = range(n+1)
    for i in range(1,m+1):
        previous, current = current, [i]+[0]*n
        for j in range(1,n+1):
            add, delete = previous[j]+1, current[j-1]+1
            change = previous[j-1]
            if a[j-1] != b[i-1]:
                change = change + 1
            current[j] = min(add, delete, change)

    return current[n]

编辑:另外,您没有提及您的数据集。根据其特点,实施可能会改变以从中受益。

答案 2 :(得分:0)

您的算法似乎做了很多工作。它将每个位与相反位向量中的所有位进行比较,这意味着您获得的算法复杂度为O(m * n)。如果你计算汉明距离,这是不必要的,所以我假设你不是。

你的循环构建一个x[i,j]矩阵,如下所示:

   0  1  0  0  0  0  0  0  1  0  0 ... (word1)
0  0  1  0  0  0  0  0  0  1
1  1  0  1  1  1  1  1  1  0
0  0  1  0  1  1  1  1  1  1
0  0  1  1  0  1  1  1  1  2
0  0  1  1  1  0  1  1  1  2
0  0  1  1  1  1  0  1  1  2
1
1
...
(example word2)

这可能对检测某些类型的编辑很有用,但不知道您尝试实施的编辑距离算法,我真的无法告诉您如何优化它。