本次實驗內容是基於詞典的雙向匹配算法的中文分詞算法的實現。
正向最大匹配算法
先設定掃描的窗口大小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))