利用隐马尔科夫链(HMM)模型实现中文分词

Posted 菜鸟_xf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用隐马尔科夫链(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

 











以上是关于利用隐马尔科夫链(HMM)模型实现中文分词的主要内容,如果未能解决你的问题,请参考以下文章

HMM的中文分词方法

Python实现HMM(隐马尔可夫模型)

理解隐马尔科夫(HMM)模型

深度剖析HMM(附Python代码)1.前言及隐马尔科夫链HMM的背景

自然语言处理hmm隐马尔可夫模型进行中文分词 代码

HMM+三个基本问题