美文网首页
Levenshtein distance(编辑距离)

Levenshtein distance(编辑距离)

作者: ce0b74704937 | 来源:发表于2018-11-06 14:00 被阅读0次

    基本介绍

    Levenshtein distance是一种度量两个序列(字符串)差异大小的方法。

    该方法定义如下:
    两个序列(以单词为例,这里序列也可以表示一个句子)的Levenshtein distance是在使用一个单词修改为另一个单词时,通过编辑单个字符(如插入,删除,修改)所需要的最小次数。

    这个概念由俄罗斯数学家Vladimir Levenshtein于1965年提出。目前这个距离常用来评价字符识别任务的好坏。

    举个例子

    将单词“kitten”修改为“sitting”最少需要3次单字符的操作:

    1. kitten -> sitten(将“k”改为“s”)
    2. sitten -> sittin(将“e”改为“i”)
    3. sittin -> sitting(将“g”删除)

    原理

    假设现在两个字符串A和B,其中A的长度为a,B的长度为b,现要计算A与B之间的Levenshtein distance

    我们可以考虑使用动态规划的思想解决这个问题

    假设A_{i}B_{j}分别为字符串A、B的前i、j个字符组成的子串,现在我们来看看将
    A_{i}:A[1]\quad A[2] \quad ...\quad A[i-1]\quad A[i]
    修改为
    B_{j}:B[1]\quad B[2] \quad ... \quad B[j-1]\quad B[j]
    需要的最少编辑次数,即两个子串的Levenshtein distance,下面我们来分别讨论三种操作的操作次数:

    1. 插入操作

    假设将A[1...i]修改为B[1...j-1]需要操作数为op_{1},那么在A[i]后插入一个字符B[j],这样就可以将A[1...i]修改为B[1...j],这时所需要的操作数为op_{1}+1

    2.删除操作

    假设将A[1...i-1]修改为B[1...j]需要操作数为op_{2},那么删除A[i]就可以将A[1...i]修改为B[1...j],这时所需要的操作数为op_{2}+1

    3.修改操作

    假设将A[1...i-1]修改为B[1...j-1]需要操作数为op_{3},这时要将A[1...i]修改为B[1...j]分两种情况:

    a. A[i]\ne B[j],则将A[i]替换成B[j]即可完成修改,这时操作数为op_{3}+1

    b. A[i]== B[j],则将不需要进行修改操作,操作数仍为op_{3}

    最后可以得到状态转移方程如下

    lev_{a,b}(i, j)= \left\{ \begin{array}{lr} max(i, j),\quad if\ min(i, j) = 0 \\ min\left\{\begin{array}{lr} lev_{a,b}(i-1,j)+1 \\ lev_{a,b}(i,j-1)+1 \\ lev_{a,b}(i-1,j-1)+1_{a_{i}\ne b_{j}} \\ \end{array} \right. , otherwise\\ \end{array} \right.

    上式中1_{a_{i}\ne b_{j}}表示a_{i}\ne b_{j}表达式取0,否则取1

    Python代码如下

    得到上述转移方程后我们就很容易写出下面程序了

    1.按照上述公式编写,没做优化的情况

    import numpy as np
    
    def Lev_distance():
        A = "fafasa"
        B = "faftreassa"
    
        dp = np.zeros((len(A) + 1, len(B) + 1))
    
        for i in xrange(len(A) + 1):
            dp[i][0] = i
        for j in xrange(len(B) + 1):
            dp[0][j] = j
    
        for i in xrange(1, len(A) + 1):
            for j in xrange(1, len(B) + 1):
                if A[i - 1] == B[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    dp[i][j] = min(dp[i - 1][j - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1
    
        print("Levenshtein distance: {}".format(dp[len(A)][len(B)]))
    
    if __name__=="__main__":
        Lev_distance()
    

    2.使用滚动数组优化上述代码

    import numpy as np
    
    def Lev_distance():
        A = "fafasa"
        B = "faftreassa"
    
        dp = np.array(np.arange(len(B)+1))
    
        for i in xrange(1, len(A)+1):
            temp1 = dp[0]
            dp[0] += 1
            for j in xrange(1, len(B)+1):
                temp2 = dp[j]
                if A[i-1] == B[j-1]:
                    dp[j] = temp1
                else:
                    dp[j] = min(temp1, min(dp[j-1], dp[j]))+1
                temp1 = temp2
    
        print("Levenshtein distance: {}".format(dp[len(B)]))
    
    if __name__=="__main__":
        Lev_distance()
    

    参考

    [1] https://en.wikipedia.org/wiki/Levenshtein_distance
    [2] http://www.cnblogs.com/BlackStorm/p/5400809.html

    欢迎加入OCR交流群:785515057(此群已满)
    欢迎加入OCR交流群2:826714963

    相关文章

      网友评论

          本文标题:Levenshtein distance(编辑距离)

          本文链接:https://www.haomeiwen.com/subject/wsayxqtx.html