基于规则的分词是一种机械分词方法,主要是通过维护词典,在切分语句时,将语句的每个字符串与词表中的词进行逐一匹配,找到则切分,否则不予切分。按照匹配切分的方式,主要有正向最大匹配法、逆向最大匹配法以及双向最大匹配法三种方法。
正向最大匹配算法
先设定扫描的窗口大小maxLen(最好是字典最长的单词长度),从左向右取待切分汉语句的maxLen个字符作为匹配字段。查找词典并进行匹配。若匹配成功,则将这个匹配字段作为一个词切分出来,并将窗口向右移动这个单词的长度。若匹配不成功,则将这个匹配字段的最后一个字去掉,剩下的字符串作为新的匹配字段,进行再次匹配,重复以上过程,直到切分出所有词为止。
反向最大匹配算法
该算法是正向的逆向算法,区别是窗口是从后向左扫描,若匹配不成功,则去掉第一个字符,重复上述的匹配步骤。
双向最大匹配算法
双向最大匹配法是将正向最大匹配法得到的分词结果和逆向最大匹配法的到的结果进行比较,从而决定正确的分词方法。定义的匹配规则如下:
- 如果正反向匹配算法得到的结果相同,我们则认为分词正确,返回任意一个结果即可。
- 如果正反向匹配算法得到的结果不同,则考虑单字词、非字典词、总词数数量的数量,三者的数量越少,认为分词的效果越好。我们设定一个惩罚分数(score_fmm / score_bmm = 0),例如:正向匹配中单字词数量多于反向匹配,则正向匹配的分值score_fmm += 1。其他两个条件相同。可以根据实际的分词效果调整惩罚分数的大小,但由于没有正确分词的数据,因此惩罚分数都设为1。最后比较惩罚分数,返回较小的匹配结果。
分词算法python 实现
word_dict = {'我', '要', '爱', '携程', '携程旅游网', '旅行网', '旅行'}
def fmm(text, word_dict):
"""
正向最大匹配算法
:param text: 输入待分词文本
:param word_dict: 词典
:return:分词结果
"""
result = []
len_text = len(text)
window_size = max({len(word) for word in word_dict})
start_index = 0
while start_index < len_text:
is_match = False
for i in range(window_size, 0, -1):
end_index = start_index + i
sub_text = text[start_index: end_index]
if sub_text in word_dict:
result.append(sub_text)
start_index = end_index
is_match = True
break
if not is_match:
result.append(text[start_index])
start_index += 1
return result
def bmm(text, word_dict):
"""
反向最大匹配算法
:param text: 输入的待分词文本
:param word_dict: 词典
:return: 分词结果
"""
result = []
len_text = len(text)
window_size = max({len(word) for word in word_dict})
end_index = len_text
while end_index > 0:
is_match = False
for i in range(window_size, 0, -1):
start_index = end_index - i
sub_text = text[start_index: end_index]
if sub_text in word_dict:
result.append(sub_text)
end_index = start_index
is_match = True
break
if not is_match:
result.append(text[end_index - 1])
end_index -= 1
result.reverse()
return result
def bi_mm(text, word_dict):
"""
双向最大匹配算法
:param text: 待分词文本
:param word_dict: 词典
:return: 分词结果
"""
forward = fmm(text, word_dict)
backward = bmm(text, word_dict)
if forward == backward:
return forward
else:
score_fmm = 0
score_bmm = 0
# 总词数
tot_fmm = len(forward)
tot_bmm = len(backward)
# 单字词个数
single_word_fmm = len([word for word in forward if len(word) == 1])
single_word_bmm = len([word for word in backward if len(word) == 1])
# 不在词典的词个数
oov_fmm = len([word for word in forward if word not in word_dict])
oov_bmm = len([word for word in forward if word not in word_dict])
if tot_bmm < tot_fmm:
score_bmm += 1
elif tot_fmm < tot_bmm:
score_fmm += 1
if single_word_bmm < single_word_fmm:
score_bmm += 1
elif single_word_fmm < single_word_bmm:
score_fmm += 1
if oov_bmm < oov_fmm:
score_bmm += 1
elif oov_fmm < oov_bmm:
score_fmm += 1
if score_bmm < score_fmm:
return backward
else:
return forward
if __name__ == '__main__':
print(fmm('我爱fdsf携程旅游网', word_dict))
print(bmm('我爱速度携程旅游网', word_dict))
print(bi_mm('我爱速度携程旅游网', word_dict))