Android 分词查询_最大匹配


本文主要介绍中文分词基于规则分词的个人学习笔记。

下期预告:中文分词—统计分词笔记

自中文自动分词被提出以来,30年的探索,提出了很多方法,可主要归纳为“规则分词”“统计分词”和“混合分词(规 +统计)”这三个主要流派。规则分词是最早兴起的方法,主要是通过人工设立词库,按照一定方式进行匹配切分,其实现简单高效,但是对新词很难进行处理。随后统计机器学习技术的兴起,应用于分词任务上后,就有了统计分词,能够较好地应对新词发现等特殊场景。

规则分词

  • 正向最大匹配法(Maximum Match Method)
  • 逆向最大匹配法(Reversw Maximum Match)
  • 双向最大匹配法

基于规则的分词是一种机械分词方法,主要是通过维护词典,在切分语句时,将语句的每个字符串与词表中的词进行逐一匹配,找到则切分,否则不予切分。

按照匹配切分的方式,主要有正向最大匹配法、逆向最大匹配法以及双向最大匹配法。

正向最大匹配法

正向最大匹配(Maximum Match Method)的基本思想为:假定分词中的最长词有i个汉字字符,则用被处理文档的当前字符串的前i个字符作为匹配字段,查找字典。若字典中存在这样的一个i字词,则匹配成功,匹配字段被作为一个词切分出来。

如果词典中找不到这样的一个i字词,则匹配失败,将匹配字段中的最后一个字去掉,对剩下的字符串进行匹配处理。如此进行下去,直到匹配成功,即切分出一个词或剩余字符串的长度为零为止。


word_dic = []  

def init():
    with open('dic.txt', 'r', encoding='utf-8') as dic_input:
        for word in dic_input:
            word_dic.append(word.strip())
            
def cut_words(raw_sentence, words_dic):
    max_length = max(len(word) for word in word_dic)
    sentence = raw_sentence.strip()
    words_length = len(sentence)
    cut_word_list = []
    while words_length > 0:  
        max_cut_length = min(max_length, words_length)
        subSentence = sentence[0: max_cut_length]
        while max_cut_length > 0:
            if subSentence in word_dic:
                cut_word_list.append(subSentence)
                break
            elif max_cut_length == 1:
                cut_word_list.append(subSentence)
                break
            else:
                max_cut_length = max_cut_length - 1
                subSentence = subSentence[0: max_cut_length]
        sentence = sentence[max_cut_length:]  
        words_length = words_length - max_cut_length  

    return cut_word_list
    
def main():
    init()
    while True: 
        print("请输入您要分词的序列")
        input_str = input()
        if not input_str:
            break
        result = cut_words(input_str, word_dic)
        print("分词的结果")
        print(result)

main()


Android 分词查询_Android 分词查询_02


逆向最大匹配法

逆向最大匹配(Reversw Maximum Match)的基本思想是:假定分词中的最长词有i个汉字字符,则从被处理的文档末端开始匹配,每次取末端的i个字符(i为词典中最长词数)作为匹配字段。若匹配失败,则去掉匹配字段的最前面一个字,继续匹配。相应地,它使用的分词词典是逆序词典,其中的每个词条都将按逆序方式存放。

由于汉语中偏正结构较多,若从后向前匹配,可以适当提高精确度。所以逆向最大匹配算法比正向最大匹配算法的误差要小。统计结果表明,单纯使用正向最大匹配算法的错误率1/169,单纯的逆向最大匹配的错误率为1/254,比如之前的“南京市长江大桥”,按照逆向最大匹配,最终得到“南京市”“长江大桥”。当然,如此切分并不代表完全正确,可能有个“江大桥”的“南京市长”也说不定。


words_dic = []
def init():

    with open('dic.txt', 'r',encoding='utf-8') as dic_input:
        for word in dic_input:
            words_dic.append(word.strip())

def cut_words(raw_sentence, words_dic):
    max_length = max(len(word) for word in words_dic)
    sentence = raw_sentence.strip()
    words_length = len(sentence)
    cut_words_list = []

    while words_length >0:
        max_cut_length = min(max_length, words_length)
        subSentence = sentence[-max_cut_length:]
        while max_cut_length >0:  
            if subSentence in words_dic:
                cut_words_list.append(subSentence)
                break
            elif max_cut_length == 1:
                cut_words_list.append(subSentence)
                break
            else:  
                max_cut_length = max_cut_length - 1 
                subSentence = subSentence[-max_cut_length:]
  
        sentence = sentence[0:-max_cut_length]
        words_length = words_length - max_cut_length  
    cut_words_list.reverse()
    return  cut_words_list

def main():
    init()
    while True:
        print("请输入你要分词的序列:")
        input_str = input()
        if not input_str:
            break
        result = cut_words(input_str, words_dic)
        print("分词结果")
        print(result)
main()


Android 分词查询_Android 分词查询_02


双向最大匹配法

双向最大匹配法是将正向最大匹配法得到的分词结果和逆向最大匹 配法的到的结果进行比较,从而决定正确的分词方法。据SunM.S. 和 Benjamin K.T.(1995)的研究表明,中文中90.0%左右的句子, 正向最大匹配法和逆向最大匹配法完全重合且正确,只有大概9.0% 的句子两种切分方法得到的结果不一样,但其中必有一个是正确的 (歧义检测成功),只有不到1.0%的句子,或者正向最大匹配法和 逆向最大匹配法的切分虽重合却是错的,或者正向最大匹配法和逆 向最大匹配法切分不同但两个都不对(歧义检测失败)。这正是双 向最大匹配法在实用中文信息处理系统中得以广泛使用的原因所在。

启发式算法

  • 如果正反向分词结果词数不同,则取分词数量较少的那个
  • 如果分词结果词数相同
  • 分词结果相同,就说明没有歧义,可返回任意一个。
import BMM
import RMM

word_dic = []  # 申请一个词典
def init():
    with open('dic.txt', 'r', encoding='utf-8') as dic_input:
        for word in dic_input:
            word_dic.append(word.strip())

def cut_words(raw_sentence, words_dic):
    bmm_words_list = BMM.cut_words(raw_sentence, words_dic)
    fmm_words_list = RMM.cut_words(raw_sentence, words_dic)
    bmm_words_list_size = len(bmm_words_list)
    fmm_words_list_size = len(fmm_words_list)
    if bmm_words_list_size != fmm_words_list_size:
        if bmm_words_list_size < fmm_words_list_size:
            return bmm_words_list_size
        else:
            return fmm_words_list_size
    else:
        FSingle = 0
        RSingle = 0
        isSame = True
        for i in range(len(fmm_words_list)):   
            if fmm_words_list[i] not in bmm_words_list:
                isSame = False
            if len(fmm_words_list[i]) == 1:
                FSingle = FSingle +1
            if len(bmm_words_list[i]) == 1:
                RSingle = RSingle + 1
        if isSame:
            return fmm_words_list
        elif RSingle > FSingle:
            return fmm_words_list
        else:
            return bmm_words_list

def main():
    init()
    while True:
        print("请输入您要分词的序列")
        input_str = input()
        if not input_str:
            break
        result = cut_words(input_str, word_dic)
        print("分词的结果")
        print(result)
main()


Android 分词查询_Android 分词查询_02


参考书籍:

  • python自然语言处理
  • AI壹号堂