自然語言處理:分詞方法

hit-wxb發表於2018-03-29

正向最大匹配分詞

  • 最大正向匹配(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法的切分結果,從而決定正確的切分(比較規則可以自定義),可以識別出分詞中的交叉歧義。

相關文章