利用隱馬爾科夫鏈(HMM)模型實現中文分詞


1.什么是HMM?

隱馬爾科夫鏈(HMM)是一個五元組:

  • 隱狀態集合 ;
  • 觀測狀態集合;
  • 狀態概率轉移矩陣;
  • 觀察狀態概率矩陣;
  • 初始狀態概率分布;

2.HMM有兩個假設:

  • 齊次馬爾可夫鏈假設:任意時刻的隱藏狀態只依賴與前一時刻的隱藏狀態。
  • 觀測獨立性假設:任意時刻的觀察狀態,只依賴與當前時刻的隱藏狀態。

3.HMM可以解決3類基本問題:

  • 評估觀察序列的概率。
  • 學習模型參數。即給定觀察序列,估計模型的參數,是觀察序列出現的概率最大。
  • 預測問題。即給定觀察序列和模型,求最有可能出現的對應狀態序列。

4.中文分詞

<1>抽象出五元組

  • StatusSet。狀態集合為{B, M, E, S}.其中B表示詞首,M表示詞中間,E表示詞尾,S表示單字成詞。
  • ObservedSet。觀察狀態集合就是所有的漢字,甚至包括標點符號組成的集合。
  • TransProbMatrix。狀態轉移概率矩陣,就是{B, M, E, S} X {B, M, E, S}的一個4X4矩陣。
  • EmitProbMatrix。觀察矩陣的每個元素都是一個條件概率,代表P(Observed[i]|Status[j])。
  • InitStatus。初始狀態概率分布表示句子的第一個字屬於{B,E,M,S}這四種狀態的概率。

<2>模型訓練

A_dic = {}        #狀態轉移概率矩陣
B_dic = {} #觀察概率矩陣
Count_dic = {} #記錄每一個狀態出現的次數
Pi_dic = {} #記錄了每一行第一個狀態出現的次數
word_set = set() #存放所有出現的字(包括數字,標點符號等)
state_list = ['B','M','E','S']
line_num #記錄樣本行數


按行遍歷訓練樣本:

(1) 獲取每行樣本對應的字符列表 word_list 以及狀態列表  line_state;

(2)記錄字符集合 word_set 以及行數 line_num;

(3)記錄每行第一個狀態出現的次數 Pi_dic[line_state[0]]+=1;

(4)記錄第 i-1 到 第 i 個狀態轉移的次數 A_dic[line_state[i-1]][line_state[i]]+=1;

(5)記錄每個狀態出現的次數 count_dic[line_state[i]]+=1;

(6)記錄每個狀態對應的發射概率 B_dic[line_state[i]][word_list[i]]+=1;

(7)統計概率

    Pi_dic[state] = pi_dic[state] / line_num

    A_dic[state1][state2] = A_dic[state1][state2] / count_dic[state1]

    B_dic[state][word]  = B_dic[state][word] / count_dic[state]

 

<3>利用Viterbi算法進行分詞

 1 #obs:待分詞的字符串
 2 #states:狀態列表('B','M','E','S')
 3 #start_p:初始概率分布
 4 #trans_p:轉移概率矩陣
 5 #emit_p: 發射概率矩陣
 6 def viterbi(obs, states, start_p, trans_p, emit_p):  #維特比算法
 7     V = [{}]#每個字對應一個字典,構成一個字典列表。字典格式:{‘B’:val,'M':val,'E':val,'S':val},val表示概率。字典表示當前字符對應的狀態概率
 8     path = {}#以狀態y結尾的路徑如:{‘B’:['S','B'],'M':['B','M'],'E':['B','E'],'S':['S','S']}
 9     for y in states:   #字符串的第0個位置。初始值
10         V[0][y] = start_p[y] * emit_p[y].get(obs[0],0)   #初始概率*發射概率。在位置0,以y狀態為末尾的狀態序列的最大概率
11         path[y] = [y]#
12     for t in range(1,len(obs)):#遍歷字符串后面的字符
13         V.append({})
14         newpath = {}
15         for y in states:      #從y0 -> y狀態的遞歸,y表示當前時刻的狀態,y0表示前一個時刻的狀態。
16             #prob對應狀態的最大概率,state對應最大概率下上一時刻的狀態。
17             #(prob, state) = max([(V[t-1][y0] * trans_p[y0].get(y,0) * emit_p[y].get(obs[t],0) ,y0) for y0 in states if V[t-1][y0]>0])
18             (prob, state) = max([(V[t-1][y0] * trans_p[y0].get(y,0) * emit_p[y].get(obs[t],0) ,y0) for y0 in states])
19 
20             V[t][y] =prob
21             newpath[y] = path[state] + [y]#以狀態y結尾的路徑如:{‘B’:['S','B'],'M':['B','M'],'E':['B','E'],'S':['S','S']}
22         path = newpath  #記錄狀態序列
23     (prob, state) = max([(V[len(obs) - 1][y], y) for y in states])  #在最后一個位置,以y狀態為末尾的狀態序列的最大概率
24     return (prob, path[state])  #返回概率和狀態序列
View Code

 


免責聲明!

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



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