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]) #返回概率和状态序列