天天看點

hmm中文分詞

from collections import Counter
from math import log

hmm_model = {i:Counter() for i in 'sbme'}
#dict.txt 就是一個字頻檔案
with open('dict.txt','r',encoding="utf-8") as f:
    for line in f:
        lines = line.split(' ')
        # 單字
        if len(lines[0]) == 1:
            hmm_model['s'][lines[0]] += int(lines[1])

        else:
            # 多字
            # 首字
            hmm_model['b'][lines[0][0]] += int(lines[1])
            # 尾字
            hmm_model['e'][lines[0][-1]] += int(lines[1])
            print(hmm_model['e']["氣"])
            if len(lines[0])>2:
            # 中間字
                for m in lines[0][1:-1]:
                    hmm_model['m'][m] += int(lines[1])
#計算機率P(λ[k]|o[k]) log 的值
log_total = {i:log(sum(hmm_model[i].values())) for i in 'sbme'}
# 這些值決定了分詞的準确率如果
# 一句話作為輸入,這些值作為輸出
# 輸出8個值 直接将8個值softmax 得到的值
# 分詞後的标注使用這個進行循序計算出來 這樣就有了資料進行訓練了訓練出來在模型預測出每句話的8個轉移機率值。最後通過此法計算 出分詞
trans = {'ss':0.3,
    'sb':0.6,
    'bm':0.3,
    'be':0.85,
    'mm':0.3,
    'me':0.7,
    'es':0.3,
    'eb':0.7
 }

trans = {i:log(j) for i,j in trans.items()}
# 最大路勁計算
def viterbi(nodes):
    paths = nodes[0]
    for l in range(1, len(nodes)):
        paths_ = paths
        paths = {}
        # 從第一個字開始 評估所有 每個字和下一個字之間的關系  開頭結尾組合起來的機率 log值
        for i in nodes[l]:
            nows = {}
            for j in paths_:
                #
                if j[-1]+i in trans:

                    nows[j+i]= paths_[j]+nodes[l][i]+trans[j[-1]+i]
            # 求出最大組合比如ss se
            # log (P(o[k]|o[k−1]) )
            k = [k  for k,v in nows.items() if max(nows.values())==v ][0]
            # print(k)
            paths[k] = nows[k]
    #傳回組合最大的
    return [k  for k,v in paths.items() if max(paths.values())==v ][0]

def hmm_cut(s):
    # 計算每個字在開頭結尾中間 單個字的和 平均 機率的log值的誤差
    nodes = [{i:log(j[t]+1)-log_total[i] for i,j in hmm_model.items()} for t in s]
    tags = viterbi(nodes)
    print(tags)
    words = [s[0]]
    print(words)
    for i in range(1, len(s)):
        if tags[i] in ['b', 's']:
            words.append(s[i])
        else:
            words[-1] += s[i]
    return words
if __name__ == '__main__':
    print(' '.join(hmm_cut(u'今天天氣不錯')))      

繼續閱讀