基於Hanlp--詞典分詞:切分算法

1 詞典加載

from pyhanlp import *
def load_dictionary():
    """
    加載Hanlp中的Mini詞庫
    :return:一個set形式的詞庫
    """
    IOUtil = JClass('com.hankcs.hanlp.corpus.io.IOUtil')
    path = HanLP.Config.CoreDictionaryPath.replace('.txt','.mini.txt')
    dic = IOUtil.loadDictionary([path])
    return set(dic.keySet())

這裏使用的是hanlp提供的詞庫,後面的切分算法也可以使用自己的詞典,hanlp相關的配置安裝可以參考

hanlp安裝配置

2 完全切分算法

    完全切分指的是,找出一段文本中的所有單詞。這並不是標準意義上的分詞,有些人將這個過程誤稱爲分詞,其實不準確。

    不考慮效率的話,樸素的完全切分算法其實很簡單。只要遍歷文本中連續序列,查詢該序列是否在字典中即可。定義詞典爲dic,文本爲txt,當前處理位置爲i,代碼如下:

def fully_segment(txt,dic):
    res = []
    for i in range(len(txt)):
        for j in range(i+1,len(txt)+1):
            tmp = txt[i:j]
            if(tmp in dic):
                res.append(tmp)
    return res

調用樣例:

a = load_dictionary()
aa = '就讀北京大學'
fully_segment(aa,a)

#結果:['就', '就讀', '讀', '北', '北京', '北京大學', '京', '大', '大學', '學']

3 最長匹配算法

上面的輸出並不是中文分詞,我們更需要那種有意義的詞語序列,而不是所有出現在詞典中的單詞所構成的鏈表。比如,我們希望“北京大學”成爲一整個詞,而不是“北京”+“大學”之類的碎片。爲了達到這個目的,需要完善一下我們的規則,考慮到越長的單詞表達的意義越豐富,於是我們定義單詞越長優先級越高。具體說來,就是在某個下標爲起點遞增查詞的過程中,優先輸出更長的單詞,這種規則被稱爲最長匹配算法。該下標的掃描順序如果從前往後,稱爲正向最長匹配,反之則稱逆向最長匹配。

3.1 正向最長匹配

def forward_segment(txt,dic):
    res = []
    i = 0
    while(i<len(txt)):
        maxl = 0
        r = ''
        for j in range(i+1,len(txt)+1):
            tmp = txt[i:j]
            if(tmp in dic):
                r = tmp
                maxl = j
        i = maxl
        res.append(r)
    return res

調用樣例和結果展示:

forward_segment(aa,a)

#結果:['就讀', '北京大學']

3.2 逆向最長匹配

def backward_segment(txt,dic):
    res = []
    i = len(txt)
    while(i > 0):
        minl = 0
        j = i - 1
        r = ''
        while(j >= 0):
            tmp = txt[j:i]
            if(tmp in dic):
                r = tmp
                minl = j
            j-=1
        i = minl
        res.append(r)
    res.reverse()
    return res

調用樣例和結果展示:

backward_segment(aa,a)

#結果:['就讀', '北京大學']

3.3 雙向最長匹配

提出這種方法的原因是爲了綜合上面兩種最長匹配算法的優勢。這是一種融合兩種匹配方法的複雜規則:

  1. 同時執行正向和逆向最長匹配,若兩者的詞數不同,則返回詞數更少的那一個。
  2. 否則,返回兩者中單字更少的那一個。當單字數也相同時,優先返回逆向最長匹配的結果。
def bidrectional_segment(txt,dic):
    f = forward_segment(txt,dic)
    b = backward_segment(txt,dic)
    lf = len(f)
    lb = len(b)
    return b if(lf>=lb) else f

調用和結果樣例:

bb = '研究生命起源'
bidrectional_segment(bb,a)

#結果:['研究', '生命', '起源']

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章