正向最大匹配分詞
- 最大正向匹配(FMM)的基本思想是:假設自動分詞詞典中的最長詞條所含漢字個數為L,則從左往右取被處理材料S1的前L個字作為匹配欄位,查詢分詞詞典。若詞典中有這樣的一個長度為L的相同詞,則匹配成功,匹配欄位作為一個詞被切分出來;否則,匹配失敗,匹配欄位去掉最後一個漢字,剩下的字元作為新的匹配欄位,進行新的匹配,如此進行下去,直至切分成功或匹配欄位為單字為止。
- 舉例說明:詞典wordDict={u"計算語言學",u"課程",u"課時"},待處理材料S1=u"計算語言學課程有三個課時",詞典中所含最大詞條包含的漢字個數為5,那麼正向最大匹配分詞的過程如下:
(1)S2="",S1不為空,從S1左邊取出候選子串W="計算語言學";
(2)查詞表,“計算語言學”在詞表中,將W加入到S2中,S2=“計算語言學/”,並將W從S1中去掉,此時 S1="課程有三個課時";
(3)S1不為空,於是從S1左邊取出候選子串W="課程有三個";
(4)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="課程有三";
(5)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="課程有";
(6)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="課程"
(7)查詞表,W在詞表中,將W加入到S2中,S2=“計算語言學/課程/”,並將W從S1中去掉,此時S1="有三個課時";
(8)S1不為空,於是從S1左邊取出候選子串W="是三個課時";
(9)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="有三個課";
(10)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="有三個";
(11)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="有三"
(12)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W=“有”,這時 W是單字,將W加入到S2中,S2=“計算語言學/課程/有/”,並將W從S1中去掉,此時S1="三個課時";
(13)S1不為空,從S1左邊取出候選子串W="三個課時";
(14)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="三個課";
(15)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="三個";
(16)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W=“三”,這時 W是單字,將W加入到S2中,S2=“計算語言學/課程/有/三/”,並將W從S1中去掉,此時S1="個課時";
(17)S1不為空,從S1左邊取出候選子串W="個課時";
(18)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="個課";
(19)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W=“個”,這時W是單字,將W加入到S2中,S2=“計算語言學/課程/有/三/個/",並將W從S1中去掉,此時S1="課時";
(20)S1不為空,從S1左邊取出候選子串W="課時";
(21)查詞表,W在詞表中,將W加入到S2中,S2=“計算語言學/課程/有/三/個/課時/",並將W從S1中去掉,此時S1=""。
(22)S1為空,輸出S2作為分詞結果,分詞過程結束。
- 與FMM方法相對應的方法是反向最大匹配分詞方法,也稱為RMM方法。它的分詞過程與FMM方法相同,不過是從句子(或文章)末尾開始處理,每次匹配不成功時去掉的是前面的一個漢字。
- python 程式碼示例
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
中文分詞演算法
"""
def FMM(wordDict, maxLen, match_string):
"""
正向最大匹配演算法
:param wordDict: 詞典
:param maxLen: 匹配最大長度
:param match_string: 待匹配字串
:return: 匹配結果
"""
wordList = []
segStrLen = len(match_string)
while segStrLen > 0:
if segStrLen > maxLen:
wordLen = maxLen
else:
wordLen = segStrLen
subStr = match_string[0:wordLen]
while wordLen > 1:#詞典中有匹配詞/單字,退出
if subStr in wordDict:
break
else:
wordLen = wordLen - 1
subStr = subStr[0:wordLen]
wordList.append(subStr)
match_string = match_string[wordLen:]
segStrLen = segStrLen - wordLen
return "/".join(wordList)
def RMM(wordDict, maxLen, match_string):
"""
逆向最大匹配演算法
:param wordDict: 詞典
:param maxLen: 匹配最大長度
:param match_string: 待匹配字串
:return: 匹配結果
"""
wordList = []
segStrLen = len(match_string)
while segStrLen > 0:
if segStrLen > maxLen:
wordLen = maxLen
else:
wordLen = segStrLen
subStr = match_string[-wordLen:]
while wordLen > 1:#詞典中有匹配詞/單字,退出
if subStr in wordDict:
break
else:
wordLen = wordLen - 1
subStr = subStr[-wordLen:]
wordList.append(subStr)
match_string = match_string[0:-wordLen]
segStrLen = segStrLen - wordLen
return "/".join(wordList)
def exper():
wordDict = [u"計算語言學",u"課程",u"課時"]
S1 = u"計算語言學課程有三個課時"
maxLen = 5
print FMM(wordDict,maxLen,S1)
print RMM(wordDict, maxLen, S1)
if __name__ == '__main__':
exper()
- 與基於詞網格分詞的第一步是候選詞網格構造:利用詞典匹配,列舉輸入句子所有可能的切分詞語,並以詞網格形式儲存。實際上,詞網格是一個有向無環圖,它蘊含了輸入句子所有可能的切分,其中的每一條路徑代表一種切分。如下圖“中國人民生活“的切分詞網:
- 詞網分詞的第二步是計算詞網格中的每一條路徑的權值,權值通過計算圖中每一個節點(每一個詞)的一元統計概率和節點之間的二元統計概率的相關資訊。然後根據圖搜尋演算法在圖中找到一條權值最小的路徑,對應的路徑即為最後的分詞結果。
- 比較FMM法與RMM法的切分結果,從而決定正確的切分(比較規則可以自定義),可以識別出分詞中的交叉歧義。