最大匹配算法


中文分詞:最大匹配算法

(一)引言

分詞是自然語言處理中非常常見的操作,也是必不可少的文本數據預處理步驟。各國語言的表達方式和書寫方式截然不同,因此分詞的方式和難度也不同。英文分詞是最簡單的,因為每個單詞已經用空格自動分詞了,比如"I like Chinese" 這個句子已經被分成了三個單詞。當然,英文分詞也是有難點的,比如單詞大小寫所代表的含義不同以及各種符號的用法,這里暫不討論。中文是漢字為基本書寫單位,詞語甚至句子之間並沒有明顯的區分標記,並且不同的詞組合容易產生歧義。比如:“結婚的和尚未結婚的”,計算機很難判斷是分成“結婚/的/和/尚未/結婚/的”還是“結婚/的/和尚/未/結婚/的”。因此,中文分詞是一項非常具有挑戰性的工作。
現今,中文分詞方法一般被分為三類:
(1)基於字典的分詞方法
(2)基於統計的分詞方法
(3)基於機器學習的分詞方法
本篇文章主要介紹最直接粗暴的方法----基於詞典的分詞方法。

(二)正向最大匹配算法

顧名思義,正向最大匹配是從左到右掃描字符串,在一個給定的詞典中尋找詞的最大匹配。先看一個例子:
給定一個句子:“他是研究生物化學的”。
給定一個詞典:["他","是","研究","研究生","生物","物化","化學","學","的"]。
思路:先獲得詞典中詞的最大長度m,這個例子中m為3;給字符串初始位置一個指針pi,即在“他”的位置;從當前指針起取m個字作為詞(也可以直接到字符串末尾作為詞,但是效率低),即“他是研”;選出的詞如果在詞典中,就在詞的后面進行划分,然后指針移動到這個詞后面的一個字,如果選出的詞不在詞典中,就把選出的詞長度減一(即m-1),“他是研”就變成了“他是”,然后在進行此步驟的操作。
算法流程:
輸入:字符串 s
過程:

  1. 令指針 pi 指向 s 的初始位置
  2. repeat
  3. 計算當前指針 pi 到字串末端的字數(即未被切分字串的長度) n
  4. 令 m=詞典中最長單詞的字數,如果 n<m, 令 m=n
  5. 從當前 pi 起取 m 個漢字作為詞 wi
  6. **if  wi **在詞典中
  7. then 在 wi 后添加一個切分標志,根據 wi 的長度修改指針 pi
  8. ** else**
  9. 將 wi 從右端去掉一個字
  10. until pi 指向字串末端
    輸出: 添加切分標志后的字符串 s

示例代碼:

text = "他是研究生物化學的"
Dict = ["他","是","研究","研究生","生物","物化","化學","學","的"]

def forword_Match(text, Dict):
    '''前向最大匹配'''
    word_list = []
    pi = 0    #初始位置
    #找出字典中的最長的詞的長度
    m = max([len(word) for word in Dict])
    while pi != len(text):
        n = len(text[pi:])    #當前指針到字符串末尾的長度
        if n < m:
            m = n
        for index in range(m,0,-1):      #從當前 pi 起取 m 個漢字作為詞 
            if text[pi:pi+index] in Dict:
                word_list.append(text[pi:pi+index])
                pi = pi + index         # 根據詞的長度修改指針pi
                break
    print('/'.join(word_list))
    
forword_Match(text, Dict)    
 ## 輸出:  他/是/研究生/物化/學/的

(三)逆向最大匹配算法

可以想到,逆向最大匹配是從右到左掃描字符串,在一個給定的詞典中尋找詞的最大匹配。先看一個例子:
給定一個句子:“他是研究生物化學的”。
給定一個詞典:["他","是","研究","研究生","生物","物化","化學","學","的"]。
思路:先獲得詞典中詞的最大長度m,這個例子中m為3;給字符串末尾位置一個指針pi,即在“的”的位置;從當前指針向左取m個字作為詞(也可以直接到字符串開頭作為詞,但是效率低),即“化學的”;選出的詞如果在詞典中,就在詞的前面進行划分,然后指針移動到這個詞前面的一個字,如果選出的詞不在詞典中,就把選出的詞長度減一(即m-1),“化學的”就變成了“學的”,然后在進行此步驟的操作。
算法流程:
輸入:字符串 s
過程:

  1. 令指針 pi 指向 s 的末尾位置
  2. repeat
  3. 計算當前指針 pi 到字串開頭的字數(即未被切分字串的長度) n
  4. 令 m=詞典中最長單詞的字數,如果 n<m, 令 m=n
  5. 從當前 pi 起取往左取m個漢字作為詞 wi
  6. **if  wi **在詞典中
  7. then 在 wi 前面添加一個切分標志,根據 wi 的長度修改指針 pi
  8. ** else**
  9. 將 wi 從左端去掉一個字
  10. until pi 指向字串開頭
    輸出: 添加切分標志后的字符串 s

示例代碼:

text = "他是研究生物化學的"
Dict = ["他","是","研究","研究生","生物","物化","化學","學","的"]

def back_Match(text, Dict):
    '''逆向最大匹配'''
    word_list = []
    pi = len(text) - 1
    m = max(len(word) for word in Dict)
    while pi >= 0:
        n = len(text[0:pi+1])
        if n < m:
            m = n
        for index in range(m-1,-1,-1):
            if text[pi-index:pi+1] in Dict:
                word_list.append(text[pi-index:pi+1])
                pi = pi - index -1
                break

    print('/'.join(word_list[::-1]))

back_Match(text, Dict)
## 輸出:  他/是/研究/生物/化學/的

至此就完成了基於詞典的中文分詞方法,但是這種方法過度依賴於詞典。如果詞典質量不高(比如容量小、記錄不全等)會影響分類效果,還有一些會產生歧義的句子也不適合用這種方法。接下來我們會一起學習基於統計的分詞方法......


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM