编辑距离(LD)算法的python实现

来源:互联网 发布:mac照片怎么翻页 编辑:程序博客网 时间:2024/05/01 10:09

每篇一句:

God made relatives.Thank God we can choose our friends. ——《加菲猫》


编辑距离算法简介:

  • 定义:
    设A和B是两个字符串。将字符串A转换为字符串B所用的最少字符操作数称为字符串A到字符串B的编辑距离。(这里所说的字符操作包括:删除一个字符,插入一个字符,修改一个字符)是由俄国科学家Levenshtein提出的,故又叫Levenshtein Distance 。(LD算法)

  • 基本性质:
    1.LD(A,A)=0

    2.LD(A,”“)=Len(A)

    3.LD(A,B)=LD(B,A)

    4.0≤LD(A,B)≤Max(Len(A),Len(B))

    5.LD(A,B)=LD(Rev(A),Rev(B))

    6.LD(A+C,B+C)=LD(A,B)

    7.LD(A+B,A+C)=LD(B,C)

    8.LD(A,B)≤LD(A,C)+LD(B,C)

    9.LD(A+C,B)≤LD(A,B)+LD(B,C)

    为了讲解计算LD(A,B), 给予一下几个定义:
    A=a1a2…aN,表示A是由a1a2…aN这N个字符组成,Len(A)=N
    B=b1b2…bN,表示B是由b1b2…bM这M个字符组成,Len(B)=M
    定义LD(i, j)=LD(a1a2…ai, b1b2…bj),其中0<=N, 0<=M
    故:

    • LD(N,M) = LD(A,B)
    • LD(0,0) = 0
    • LD(0,j) = j
    • LD(i,0) = i

    对于1<=i<=N, 1<=j<=M, 有公式一:
    若ai=bj, 则LD(i, j) = LD(i-1, j-1)
    若ai≠bj, 则LD(i, j) = Min(LD(i-1, j-1), LD(i-1, j), LD(i, j-1))+1

  • 简单例子:
    A=GGATCGA
    B=GAATTCAGTTA
    将较短字符串A置于矩阵左侧,较长字符串B置于矩阵上侧:
    第一步:根据公式一填充第一行结果

    GAATTCAGTTA01234567891011G1012345678910G2A3T4C5G6A7

    第二步:填充其他表格,取最右下角的数字即为编辑距离。

    GAATTCAGTTA01234567891011G1012345678910G211234566789A321123456788T432212345678C543322234567G654433333456A765444434455

python实现

具体解释说明见代码中注释

# coding=utf-8# 这里的实现过程对算法进行了稍微的优化(运算结果应该稍快一些):首先计算两个字符串开头以及结尾# 的共同字符子串,然后去掉相同部分,重新构造新字符串,减少迭代过程次数。# 如:string_a = "GGATCGA" string_b = "GAATTCAGTTA"构造的新字符串为:# new_a = "AATTCAGTT" new_b = "GATCG" def LD(string_a, string_b):    diff_start = -1    diff_end = -1    len_a = len(string_a)    len_b = len(string_b)    short = min(len_a, len_b)    # 寻找开头和结尾的共同字符串,并记录位置    for i in range(0, short):        if string_a[i] != string_b[i]:            diff_start = i            break    if diff_start == -1:        return abs(len_b - len_a)    for i in range(0, short):        if string_a[len_a - i -1] != string_b[len_b - i - 1]:            diff_end = i            break    if diff_end == -1:        return abs(len_b - len_a)    # L(A+C, B+C) = LD(A, B)    # 出去开头以及结尾相同的字符串,构建新的字符串    long_str = unicode(string_a[diff_start: len_a - diff_end] if len_a >= len_b else string_b[diff_start: len_b - diff_end])    short_str = unicode(string_a[diff_start: len_a - diff_end] if len_a < len_b else string_b[diff_start: len_b - diff_end])    # print long_str    # print short_str    long_len = len(long_str)    short_len = len(short_str)    # store保存迭代过程中每次计算的结果    store = range(0, long_len + 1)    for i in range(short_len):        temp = [i+1] * (long_len + 1)        for j in range(long_len):            if long_str[j] == short_str[i]:                temp[j+1] = store[j]            else:                # 注意这时各个位置数据的对应关系                temp[j+1] = min(store[j], store[j+1], temp[j]) + 1        store = temp        # print store    # 最右下角即为编辑距离    return store[-1]# Teststring_a = "GGATCGA"string_b = "GAATTCAGTTA"ld = LD(string_a, string_b)print ld

写在后面:

以上即为LD算法的基本内容以及python实现,如果有什么错误或者改进意见,欢迎在下面评论或着私信博主。
代码下载:码云-LD算法的python实现