python实现最大公共子序列算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hxcaifly/article/details/79783273

研究目的

最近在做日志文本挖掘,我们要实现的功能之一是对日志事件进行聚类,聚类的方法是每两条日志之间,寻找他们的最大公共子短语(专业术语叫做最大公共子序列)。当公共子序列的长度超过一定时,我们认为这两条日志是相同事件的可能性比较大。所以本文是想实现寻找两条日志文本之间的最大公共子短语算法。

算法设计

最长公共子序列(LCS)是一个十分实用的问题,它可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。
解法就是用动态回归的思想,一个矩阵记录两个字符串中匹配情况,若是匹配则为左上方的值加1,否则为左方和上方的最大值。一个矩阵记录转移方向,然后根据转移方向,回溯找到最长子序列。

代码实现

# -*- coding: UTF-8 -*-
import numpy as np
import sys
sys.setrecursionlimit(10000) #例如这里设置为一万


def find_lcseque(str1, str2):
    s1=str1.split(" ")
    s2=str2.split(" ")
    # 生成字符串长度加1的0矩阵,m用来保存对应位置匹配的结果
    m = [[0 for x in range(len(s2) + 1)] for y in range(len(s1) + 1)]
    # d用来记录转移方向
    d = [[None for x in range(len(s2) + 1)] for y in range(len(s1) + 1)]

    for p1 in range(len(s1)):
        for p2 in range(len(s2)):
            if s1[p1] == s2[p2]:  # 字符匹配成功,则该位置的值为左上方的值加1
                m[p1 + 1][p2 + 1] = m[p1][p2] + 1
                d[p1 + 1][p2 + 1] = 'ok'
            elif m[p1 + 1][p2] > m[p1][p2 + 1]:  # 左值大于上值,则该位置的值为左值,并标记回溯时的方向
                m[p1 + 1][p2 + 1] = m[p1 + 1][p2]
                d[p1 + 1][p2 + 1] = 'left'
            else:  # 上值大于左值,则该位置的值为上值,并标记方向up
                m[p1 + 1][p2 + 1] = m[p1][p2 + 1]
                d[p1 + 1][p2 + 1] = 'up'
    (p1, p2) = (len(s1), len(s2))
    # print np.array(d)
    s = []
    while m[p1][p2]:  # 不为None时
        c = d[p1][p2]
        if c == 'ok':  # 匹配成功,插入该字符,并向左上角找下一个
            s.append(s1[p1 - 1])
            p1 -= 1
            p2 -= 1
        if c == 'left':  # 根据标记,向左找下一个
            p2 -= 1
        if c == 'up':  # 根据标记,向上找下一个
            p1 -= 1
    s.reverse()
    return ' '.join(s)

if __name__ == "__main__":
    print find_lcseque("this is my name zhe ","my name is hxcai zhe")

输出结果为:

my name zhe

注意细节

两个给定文本的最大公共子序列的长度是一定的,但是最大公共子序列不一定只有一个,有可能有多个。

猜你喜欢

转载自blog.csdn.net/hxcaifly/article/details/79783273