正-逆向最大匹配分词

正向最大匹配(Maximum Match Method,MM法)的基本思想为:一开始以词典最大词长度len进行分词,如果能够在句子中分出词典中存在的词,那么就匹配成功,继续进行后面的分词,一开始还是以词典最大词进行分词;如果没有匹配成功,那么就减len-1,继续匹配。

比如我们现在有个词典,最长词的长度为5,词典中存在“南京市长”和“长江大桥”两个词。现采用正向最大匹配对句子“南京市长江大桥”进行分词,那么首先从句子中取出前五个字“南京市长江”,发现词典中没有该词,于是缩小长度,取前4个字“南京市长”,词典中存在该词,于是该词被确认切分。再将剩下的“江大桥”按照同样方式切分,得到“江”“大桥”,最终分为“南京市长”“江”“大桥”3个词。

逆向最大匹配(Maximum Match Method,MM法)的基本思想为:一开始以词典最大词长度len进行分词,但是是从句子的末端开始,如果能够在句子中分出词典中存在的词,那么就匹配成功,继续进行后面的分词,一开始还是以词典最大词进行分词;如果没有匹配成功,那么就减len-1,继续匹配。

比如之前的“南京市长江大桥”,按照逆向最大匹配,最终得到“南京市”“长江大桥”。

双向最大匹配法(Bi-directction Matching method)是将正向最大匹配法得到的分词结果和逆向最大匹配法得到的结果进行比较,然后按照最大匹配原则,选取词数切分最少的作为结果。

比如之前的“南京市长江大桥”,就会选用逆向最大匹配

class SegmentMatch(object):
    def __init__(self, dict_path):
        self.dictionary = set()
        self.maximum = 0

        #加载词典
        with open(dict_path, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                self.dictionary.add(line)
                if len(line) > self.maximum:
                    self.maximum = len(line)
    #逆向最大匹配
    def reverseMM(self, text):
         result = []
         index = len(text)
         while index > 0:
             for size in range(self.maximum, 0, -1):
                 if index - size < 0:
                     continue
                 piece = text[(index - size):index]
                 if piece in self.dictionary:
                     result.append(piece)
                     index = index - size
                     break

         return result[::-1]  #反向

    ##正向最大匹配
    def mm(self, text):
        result = []
        index = 0
        while index < len(text):
            for size in range(self.maximum, 0, -1):
                if index + size > len(text):
                    continue
                piece = text[index : (index+size)]
                if piece in self.dictionary:
                    result.append(piece)
                    index = index + size
                    break
        return result


def main():
    text = "南京市长江大桥"
    seg = SegmentMatch('E:/NLP/mytest/imm_dic.utf8')
    result1 = seg.reverseMM(text)
    result2 = seg.mm(text)
    if len(result1) < len(result2): #双向匹配就是选择正向逆向匹配结果所含分词最小的
        print(result1)
    else:
        print(result2)


if __name__ == '__main__':
        main()



参考资料:

《Python自然语言处理实战:核心技术与算法》 — 涂铭 刘祥 刘树春