自然语言处理——隐马尔可夫模型
序列标注问题
给定一个序列x1x2x3....xn,列出序列中每个元素对应的标签y1y2y3.....yn问题。
应用场景:中文分词,词性标注,命名实体识别
中文分词:{B,M,E,S}:将一句话的每个字打上一个标签,B代表词首,M代表词中, E代表词尾,S代表单字
词性标注:给每个词语标注一个词性,比如:小明打篮球,小明代表名词,打是动词,篮球是物品名。需要考虑前后词的词性决定当前词性的关系。这个时候就需要用到概率模型去预测。
命名实体识别:现实中存在的实体名,比如人名、地名和机构名。同样可以使用打标签的思路。B代表词首,E代表词尾,O代表不构成命名实体的单词。
HMM(Hidden Markov Model 隐马尔科夫模型)
隐马尔科夫为何叫“隐”,因为预测的序列我们看不见,比如我们要猜测一句话的每个单词的词性。
它是基于马尔科夫假设:
1.每一个yi仅仅依赖于前一个状态yi-1。
2.任意时刻xi只依赖于yi,这就好比小明打篮球,这句话,'打'字出现取决于前面的“小明”是什么词性。
HMM模拟时序序列的发生过程:
1.初始状态概率向量:
y1的取值分布,比如,中文分词问题采用{B,M,E,S}标注集时,y1=B、M、E、S的概率
2.状态转移概率矩阵:
yt转移yt+1,假设t时与t+1时都有N种状态,则从状态yt到yt+1的概率就构成了N×N的方阵
比如,中文分词中,如果一个字被打上标签B,则说明他是一个词语的开头,故其后面不可能是S,则矩阵该位置的元素为0。
或者像“副词”后接“动词”的规律可以由状态转移概率来表示。
3.发射概率矩阵:
假设x有M种取值,由于y有N种,根据前面的马尔科夫假设2,我们又可以得到一个N×M的矩阵。
比如在词语“现象”,赋予p(x1='象'|y1=B)较低的概率,防止“现象”被分开。
案例分析
自定义身体状态(发病、健康)与身体感受(头晕、体寒、正常)事件之间发生的概率,通过隐马尔科夫模型为病人N天的身体感受的序列,预测这个N天身体状态。
/**生成样本序列**/ public int[][] generate(int length) { int xy[][]=new int[2][length]; //一个二维数组 2×N xy[1][0]=drawFrom(pi); //为y0 赋一个 初始值 xy[0][0]=drawFrom(B[xy[1][0]]); //由y0经过发射概率矩阵生成x0 for (int t=1;t<length;t++) { xy[1][t]=drawFrom(A[xy[1][t-1]]);//生成yt xy[0][t]=drawFrom(B[xy[1][t]]);//生成xt } return xy }
结果
cold/Healthy normal/Healthy dizzy/fever dizzy/Fever
训练HMM模型
前面的例子相当于,三个矩阵已经有了。我们可以反过来分析:如果我们有这样一批标注的训练数据,采用监督学习,就可以估计出这个三个矩阵。
一:转移概率矩阵的估计:
我们自己有一堆样本,我们此时需要统计状态yt到yt+1的概率。我们就可以统计这样的转移频次,然后矩阵的第i行做一个概率的归一化。
二:初始状态概率向量的估计
与一类似。统计y1所有取值的频次
三:发射概率矩阵的估计。统计样本中观测为xt,状态为yt的频次。
使用HMM预测
给定一组观测序列,求解最可能的状态和概率。
问题转化为求观测序列x,状态序列y,p(x,y)联合概率最大的y
p(x,y)=p(y)p(x|y),将其中的值转化成三个矩阵的相应元素,就能求得任意序列的概率了。
总结
目前市面上的开源分词器依然停留在一阶隐马尔科夫水平。
隐马尔科夫模型是一种生成式模型,因为假设过于强烈、简单,与实际情况不符。所以分词准确率不会很高。
参考网址:viterbi算法:https://www.zhihu.com/question/20136144