【自然语言处理】正向最大匹配算法(FMM),反向最大匹配算法(BMM)和双向最大匹配算法(BM)原理及实现

目录

一,正向最大匹配算法(FMM)

 二,反向最大匹配算法(RMM)


一,正向最大匹配算法(FMM)

        正向最大匹配分词(Forward maximum matching segmentation)通常简称为FMM法。其基本思想为:假定分词词典中的最长词有i个汉字字符,则用被处理文档的当前字串中的前i个字作为匹配字段,查找字典。若字典中存在这样的一个字词,则匹配成功,匹配字段被作为一个词切分出来。如果词典中找不到这样的一个字词,则匹配失败,将匹配字段中的最后一个字去掉,对剩下的字串重新进行匹配处理。如此进行下去,直到匹配成功,即切分出一个词或剩余字串的长度为零为止。这样就完成了一轮匹配,然后取下一个i字字串进行匹配处理,直到文档被扫描完为止。

例子:

设变量dt为字典,s为待切字符串,result为被切后的词

令dt = ['abc', 'bcd'] ,s = ['abcd'],则 result = ['abc', 'd']

原理:字典中最大字符长度为‘abc’和‘bcd’,正向选取‘abc’,则拿‘abc’去匹配,s中匹配到‘abc’后切出,之后字典中最长的是‘d’,匹配到s的‘d’后切出,得到切片后的result = ['abc', 'd']

代码实现: 

def FMM(dt, s):  # 正向最大匹配算法
    result = []   
    max_len = max([len(i) for i in dt])    # 选取字典里长度最大的字符串
    start = 0
    while start != len(s):    # 判断列表不为空,建立循环                
        index = start + max_len    # 从0开始正向索引最大长度的字符串
        if index > len(s):         # 判断是否溢出列表
            index = len(s)
        for _ in range(max_len):    
            t = s[start:index]       # t是切片
            if t in dt or len(t) == 1:
                result.append(t)
                start = index
                break
            index -= 1 # 为了保证算法能够扫描到所有字符
    return result

 二,反向最大匹配算法(RMM)

        逆向最大匹配算法(Reserve maximum matching segmentation)的基本原理与正向最大匹配法相同,不同的是分词切分的方向与FMM法相反。逆向最大匹配法从被处理文档的末端开始匹配扫描,每次取最末端的i个字符(为词典中最长词数)作为匹配字段,若匹配失败,则去掉匹配字段最前面的一个字,继续匹配。相应地,它使用的分词词典是逆序词典,其中的每个词条都将按逆序方式存放。在实际处理时,先将文档进行倒排处理,生成逆序文档。然后,根据逆序词典,对逆序文档用正向最大匹配法处理即可。

例子:

设变量dt为字典,s为待切字符串,result为被切后的词

令dt = ['abc', 'bcd'] ,s = ['abcd'],则 result = ['a', 'bcd']

原理:字典中最大长度为'abc',‘bcd’,反向选取‘bcd’,则拿‘bcd’去匹配,s中匹配到‘bcd’后切出,之后字典中最长的是‘a’,匹配到s的‘a’后切出,得到切片后的result = ['a', 'bcd']

代码实现:

def RMM(dt, s): # 反向最大匹配算法
    result = []
    max_len = max([len(i) for i in dt]) # 选取字典里长度最大的字符串
    start = len(s)
    while start != 0:    #判断列表不为空,建立循环
        index = start - max_len    # 从列表最后开始索引最大长度的字符串
        if index < 0:        # 判断是否溢出列表
            index = 0
        for _ in range(max_len):
            t = s[index:start]    # t是切片
            if t in dt or len(t) == 1:
                result.insert(0, t)    # 在最前面插入
                start = index
                break
            index += 1
    return result

三,双向匹配算法(BM)

        双向最大匹配算法的原理就是将正向最大匹配算法和逆向最大匹配算法进行比较,从而选择正确的分词方式。

        比较原则/步骤:

        1.比较两种匹配算法的结果

        2.如果分词数量结果不同:选择数量较少的那个

        3.如果分词数量结果相同

​                 1.分词结果相同,返回任意一个

​                 2.分词结果不同,返回单字数较少的一个

​                 3.若单字数也相同,任意返回一个

例子:

设变量dt为字典,s为待切字符串,result_1为被正向切后的词,result_2为被反向切后的词

令dt = ['abc', 'deab'] ,s = ['abcdeabc'],则 result_1 = ["abc", "deab", "c"],result_2=["c", "deab"]

原理:字典中最大长度为'deab',则拿‘deab’去匹配,s中匹配到‘deab’后切出,之后字典中最长的是‘abc’,匹配到s的‘abc’后切出,得到切片后的result_1 = ["abc", "deab", "c"],同理result_2=["c", "deab"],其中正向的切词有三个,逆向有两个,数量不相等选择分词数量 少的,则输出逆向切词result_2=["c", "deab"]

def BM(dt, s): # 双向最大切词
    r1 = FMM(dt, s)
    r2 = RMM(dt, s)
    if len(r1) == len(r2):
        if r1 == r2:
            return r1
        else:
            r1_cnt = len([i for i in r1 if len(i)==1])
            r2_cnt = len([i for i in r2 if len(i)==1])
            return r1 if r1_cnt < r2_cnt else r2
    else:
        return r1 if len(r1) < len(r2) else r2

你可能感兴趣的:(自然语言处理,自然语言处理,人工智能)