正向逆向最大匹配算法實現自動分詞python

原理指路
直接上實驗過程。

1、199801人民日報語料

在這裏插入圖片描述
這是已經分詞而且詞性標記好的,我們用來獲取裏面的詞,作爲後續自己分詞的底表。

2、生成底表

# 匹配詞性
def cixing(data):
    dic = {}
    for line in data:   # 匹配普通詞性標註
        pattern = re.findall(r'/[A-Za-z]{1,30}', line)
        for p in pattern:
                if p in dic:
                    dic[p] += 1
                else:
                    dic[p] = 1
    for line in data:   # 匹配實體詞性標註,如[江  峽  大道]ns
        pattern2 = re.findall(r'][A-Za-z]{1,30}', line)
        for p in pattern2:
                #print(p)
                if p in dic:
                    dic[p] += 1
                else:
                    dic[p] = 1
    print(dic)
    print(len(dic))
    return dic


# 去除詞性標註
def restore(dic, data):
    raw_data=[]
    final=[]
    for line in data:
        #print(line)  這裏其實可以對字典排序一下 但是我懶得改了
        line=line.strip(' ').replace('[','')
        for i in dic.keys():
            if len(i)>=3:
                line = line.replace(i,'')  # 防止部分詞性前綴相似導致的錯誤匹配
        raw_data.append(line)
    for l in raw_data:
        for i in dic.keys():
            l = l.replace(i,'').strip(' ')
        final.append(l)
    #print(final)
    return final


# 統計詞彙
def wordlist(data):
    wordlist={}
    for line in data:
        line=line.split(' ')
        for word in line:
            if word in wordlist.keys():
                wordlist[word] += 1
            else:
                wordlist[word] = 1
    #wordlist.pop('')
    print(wordlist)
    return wordlist


def write_excel(path,dic):
    workbook = xlsxwriter.Workbook(path)
    worksheet = workbook.add_worksheet('sheet1')
    worksheet.write(0, 0, '詞彙')
    worksheet.write(0, 1, '頻次')
    for k, i in zip(range(len(dic)), dic.keys()):
        j = dic[i]
        #print(i, j)
        worksheet.write(k+1, 0, i)
        worksheet.write(k+1, 1, j)
    workbook.close()

形成下面形式的一個詞表,我還統計了一下頻次。
在這裏插入圖片描述

3、正向和逆向最大匹配算法實現

最大步長我設置爲5,一般都是設置爲5。

# 逆向最大匹配分詞
def segword(data):
    wordlis= sorted(wordlexicon, key=lambda i: len(i), reverse=True)  # 按長度大小排序
    #print(wordlis)
    re=[]
    for i in range(len(data)):
        s1 = data[i]
        #print(s1)
        s2 = ''
        maxlen = 5
        w = s1[-maxlen:]  # 逆向
        while (w):
            if len(w) != 1:
                if w in wordlis:
                    s2 = w + ' ' + s2
                    n=len(s1)-len(w)
                    s1 = s1[0:n]
                    w = s1[-maxlen:]
                    #print(s2,s1)
                else:
                    w = w[1:len(w)]
                    #print(w)
            else:
                s2 = w + ' ' + s2
                n = len(s1) - len(w)
                s1 = s1[0:n]
                w = s1[-maxlen:]
                #print(s2, s1)
        re.append(s2)
    print(re)
    return re


# 正向最大匹配分詞
def segword_2(data):
    wordlis= sorted(wordlexicon, key=lambda i: len(i), reverse=True)  # 按長度大小排序
    # print(wordlis)
    re=[]
    for i in range(len(data)):
        s1 = data[i]
        #print(s1)
        s2 = ''
        maxlen = 5
        w = s1[:maxlen]  # 逆向
        #print(w)
        while (w):
            if len(w) != 1:
                if w in wordlis:
                    s2 = s2 + w+ ' '
                    s1 = s1[len(w):]
                    w = s1[:maxlen]
                    #print(s2,s1)
                else:
                    w = w[:len(w)-1]
                    #print(w)
            else:
                s2 = s2 + w + ' '
                s1 = s1[len(w):]
                w = s1[:maxlen]
                #print(s2, s1)
        re.append(s2)
    print(re)
    return re

4、實踐

我選了一篇新聞,用作待分詞文本。
在這裏插入圖片描述
逆向結果:
在這裏插入圖片描述
正向結果:
在這裏插入圖片描述

5、評估

從處理速度、總體詞數、分詞粒度、以及未登錄詞等各方面都可以進行評估比較正向和逆向分詞的效果。
一般來說,總體詞數越少越好,在相同字數的情況下,總詞數越少,說明語義單元越少,那麼相對的單個語義單元的權重會越大,因此準確性會越高。
一般又說,分詞的顆粒度越大,即單字詞的數量越少,所能表示的含義越確切,比如對於“公安局長”可以分爲“公安 局長”、“公安局 長”、“公安局長”都算對,但是要用於語義分析,則“公安局長”的分詞結果最好。
下面是一個簡單實現計算單字的程序。

# 單字
def word(data):
    sum=0
    for word in data.keys():
        if len(word)==1:
            sum+=1
    return sum


# 非詞典單字
def non_word(data):
    num=0
    for word in data.keys():
        if len(word)==1 and word not in wordlist:
            num+=1
    return num

完整代碼見

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