Skip to content

Latest commit

 

History

History
145 lines (103 loc) · 6.72 KB

基于词典的正向最大匹配和逆向最大匹配中文分词.md

File metadata and controls

145 lines (103 loc) · 6.72 KB

中文分词中基于词典的正向最大匹配和逆向最大匹配

正向最大匹配和逆向最大匹配步骤类似,只是方向不同,我以正向匹配为例,先用一句话去总结它:

在做整个正向成词的过程中,我们做了两个步骤,首先按照字典最大长度进行对原始文本进行切分,然后逐渐去掉右边一个单字,去查看剩余文本在字典是否存在,依次迭代。

上面这句话只看不太好理解,我来个简单的例子,如下:

我要被切分的句子是这样的:”今天天气真不错啊“

我的字典是这样的:[今天,天天,天气,真不错,不错,啊,哈哈哈哈哈]

对于字典这一块,最粗糙的就是存成列表,优化一点可以存成字典树,这里简化一点,我们存成列表。

我字典的最大长度是 “哈哈哈哈哈”,为5

所以我第一次正向匹配就是:

今天天气真 # 取原始文本前五个单词,查看是否存在于字典,否,删除底部

今天天气 # 查看是否存在于字典,否,删除底部

今天天 # 查看是否存在于字典,否,删除底部

今天 #匹配到字典中的“天气”这个词

第二次正向匹配是这样的:

天气真不错啊 # 因为”今天“已经被匹配到了,所以我们不在考虑,取剩余文本的前五个单词,查看是否存在于字典,否,删除底部

天气真不错 #查看是否存在于字典,否,删除底部

天气真不 #查看是否存在于字典,否,删除底部

天气真 #查看是否存在于字典,否,删除底部

天气 #匹配到字典中的“天气“这个单词

第三次正向匹配的过程:

真不错啊 # 剩余文本不够5个,我们取小,取4个,查看是否存在于字典,否,删除底部

真不错 # 匹配到”真不错“ 这个单词

第四次正向匹配的过程:

啊 # 字典中没有与之相关的单词,由于长度已经为1,直接单独成词就可以

在做整个正向成词的过程中,我们做了两个步骤,首先按照字典最大长度进行对原始文本进行切分(需要比对最大长度和文本的长度,如果文本长度不够的话,就取文本长度,总之取小。比如第三次正向匹配”真不错啊“这剩余的四个字就不够5个), 然后逐渐去掉右边一个单字,去查看剩余文本在字典是否存在,依次迭代。

其实逆向匹配是很类似的过程,只不过方向变了,需要注意的是我们始终删除的是底部单词:

第一次逆向匹配:

气真不错啊 # 查看是否存在于字典,否,删除底部

真不错啊 # 查看是否存在于字典,否,删除底部

不错啊 # 查看是否存在于字典,否,删除底部

错啊 # 查看是否存在于字典,否,删除底部

啊 # 字典中没有与之相关的单词,由于长度已经为1,直接单独成词就可以

...... ...... ......

双向最大匹配算法就是两种方法都切一遍,从中选择一种比较好的,标准就是:大颗粒度词越多越好,非词典词和单字词越少越好.

对于代码的实现,我记得是好久之前从网上down下来的,具体来源忘了,不过都大同小异,自己写也没啥问题。

我在这里啰嗦的讲一下大致思路,如果您觉得比较简单,或者只想看代码,跳过就可以:

基本思路是这样的,我有一个存储我词典的列表,以词典中最大长度为基线顺序对原始文本进行切分,迭代查看当前切分词是否在词典,在就算一个词,不在的话,当前词长度减一,就是往前缩小一个词,继续进行上述活动。直至长度为1,是最后的一个迭代条件。

在写代码的时候,我自己觉得从两个方面来掌握,一个是从小方面,怎么讲,就是比如说我的字典最大的长度是5个单词,我在5个单词迭代的去找有没有在字典的中的词,这是一个while循环。

还有一个方面是大的方面,就是我现在5个单词迭代完了,比如找到了一个长度为2的在字典中的词(需要注意的是如果没有在字典中,那么长度就是1的单字就可以加进去了),然后我要做的就是把这两个单词之后的字段作为输入,再重复上面这个过程,这个是大的方面,是另一个While循环

## 正向最大匹配算法
def cut_words(split_sentence,words_dic):
    #统计词典中最长的词
    max_length = max(len(word) for word in words_dic)
    sentence = split_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 words_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
input_str="今天天气真不错啊,适合出去旅游"
bmm_word_list = cut_words(input_str, words_dic)
print(bmm_word_list)
##逆向最大匹配
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_word_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_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[-max_cut_length:]
        sentence = sentence[0:-max_cut_length]
        words_length = words_length -max_cut_length
    cut_word_list.reverse()
    return  cut_word_list

参考链接: 中文分词中的正向最大匹配与逆向最大匹配:https://blog.csdn.net/chengzheng_hit/article/details/54752673