正向最大匹配(Maximum Match Method, MM法)的基本思想为:假定分词词典中的最长词有i个汉字字符,则用被处理文档的当前字串中的前i个字作为匹配字段,查找字典。若字典中存在这样的一个i字词,则匹配成功,匹配字段被作为一个词切分出来。如果词典中找不到这样的一个i字词,则匹配失败,将匹配字段中的最后一个字去掉,对剩下的字串重新进行匹配处理。如此进行下去,直到匹配成功,即切分出一个词或剩余字串的长度为零为止。这样就完成了一轮匹配,然后取下一个i字字串进行匹配处理,直到文档被扫描完为止。
# 正向最大匹配法MM
class MM(object):
def __init__(self):
self.window_size = 3
def cut(self, text):
result = []
index = 0
text_length = len(text)
dic = ['研究', '研究生', '生命', '命', '的', '起源']
while text_length > index:
for size in range(self.window_size + index, index, -1):
piece = text[index:size]
if piece in dic:
index = size - 1
break
index = index + 1
result.append(piece + '----')
return result
if __name__ == '__main__':
text = '研究生命的起源'
tokenizer = MM()
print(tokenizer.cut(text))
分词结果:
['研究生----', '命----', '的----', '起源----']
逆向最大匹配(Reverse Maximum Match Method, RMM法)的基本原理与MM法相同,不同的是分词切分的方向与MM法相反。逆向最大匹配法从被处理文档的末端开始匹配扫描,每次取最末端的i个字符(i为词典中最长词数)作为匹配字段,若匹配失败,则去掉匹配字段最前面的一个字,继续匹配。相应地,它使用的分词词典是逆序词典,其中的每个词条都将按逆序方式存放。在实际处理时,先将文档进行倒排处理,生成逆序文档。然后,根据逆序词典,对逆序文档用正向最大匹配法处理即可。
# 逆向最大匹配法RMM
class RMM(object):
def __init__(self):
self.window_size = 3
def cut(self, text):
result = []
index = len(text)
dic = ['研究', '研究生', '生命', '命', '的', '起源']
while index > 0:
for size in range(index - self.window_size, index):
piece = text[size:index]
if piece in dic:
index = size + 1
break
index = index - 1
result.append(piece + '----')
result.reverse()
return result
if __name__ == '__main__':
text = '研究生命的起源'
tokenizer = RMM()
print(tokenizer.cut(text))
分词结果:
['研究----', '生命----', '的----', '起源----']
双向最大匹配法(Bi-direction Matching Method)是将正向最大匹配法得到的分词结果和逆向最大匹配法得到的结果进行比较,然后按照最大匹配原则,选取词数切分最少的作为结果。
例如“南京市长江大桥”,正向最大匹配的结果为“南京市/长江/大桥”,逆向最大匹配的结果为“南京市/长江大桥”,选取词数较少的“南京市/长江大桥”这一结果。
双向最大匹配的规则是:
(1)如果正反向分词结果词数不同,则取分词数量较少的那个。
(2)如果分词结果词数相同:
1)分词结果相同,就说明没有歧义,可返回任意一个。
2)分词结果不同,返回其中单字较少的那个。
代码如下:
# 双向最大匹配法BMM
class BMM(object):
def __init__(self):
self.window_size = 3
def cut(self, text):
dic = ['研究', '研究生', '生命', '命', '的', '起源']
result_MM = []
index = 0
text_length = len(text)
while text_length > index:
for size in range(self.window_size + index, index, -1):
piece = text[index:size]
if piece in dic:
index = size - 1
break
index = index + 1
result_MM.append(piece + '----')
result_RMM = []
index = len(text)
while index > 0:
for size in range(index - self.window_size, index):
piece = text[size:index]
if piece in dic:
index = size + 1
break
index = index - 1
result_RMM.append(piece + '----')
result_RMM.reverse()
if len(result_MM) > len(result_RMM):
return result_RMM
elif len(result_MM) < len(result_RMM):
return result_MM
elif len(result_MM) == len(result_RMM):
if result_MM == result_RMM:
return result_MM
else:
single_MM = 0
single_RMM = 0
for s_MM in result_MM:
if s_MM[1] == '-':
single_MM += 1
for s_RMM in result_RMM:
if s_RMM[1] == '-':
single_RMM += 1
if single_MM > single_RMM:
return result_RMM
elif single_MM < single_RMM:
return result_MM
if __name__ == '__main__':
text = '研究生命的起源'
tokenizer = BMM()
print(tokenizer.cut(text))
分词结果:
['研究----', '生命----', '的----', '起源----']