隐马尔可夫链真相——从理论证明、算法实现到实际应用

目录

历史简述

概念引入

马尔科夫链

初始分布

状态转移矩阵

观测矩阵

一般表述

齐次马尔科夫链假设

观测独立性假设

观测序列生成机理

HMM模型的三个经典问题

经典问题一之前向算法

经典问题二

经典问题三之viterbi算法

viterbi算法求解案例

viterbi算法代码实现

HMM模型应用

中文分词

股市分析


历史简述

        对于马尔可夫链,比较多的说法是:由俄国数学家安德雷·马尔可夫(Андрей Андреевич Марков)在1906-1907年间发表的一篇研究中而来,研究中为了证明随机变量间的独立性不是弱大数定律(weak law of large numbers)和中心极限定理(central limit theorem)成立的必要条件,构造了一个按条件概率相互依赖的随机过程,并证明其在一定条件下收敛于一组向量。在这个研究被提出之后,真的是一发不可收拾,后人在此基础上相继提出了各种模型,比如保罗·埃伦费斯特(Paul Ehrenfest)和Tatiana Afanasyeva在1907年使用马尔可夫链建立了Ehrenfest扩散模型(Ehrenfest model of diffusion) 。1912年亨利·庞加莱(Jules Henri Poincaré)研究了有限群上的马尔可夫链并得到了庞加莱不等式(Poincaré inequality)  。1931年,安德雷·柯尔莫哥洛夫(Андрей Николаевич Колмогоров)在对扩散问题的研究中将马尔可夫链推广至连续指数集得到了连续时间马尔可夫链,并推出了其联合分布函数的计算公式  。独立于柯尔莫哥洛夫,1926年,Sydney Chapman在研究布朗运动时也得到了该计算公式,即后来的Chapman-Kolmogorov等式  。二十世纪50年代,前苏联数学家Eugene Borisovich Dynkin完善了柯尔莫哥洛夫的理论并通过Dynkin公式(Dynkin formula)将平稳马尔可夫过程与鞅过程(martingale process)相联系。不幸地是,今天,马尔可夫模型被应用在了机器学习中,困扰着我…… 

        对于历史真实性,我们不做过多考证,就随它遗留在历史长河中吧……


概念引入

        在机器学习中,马尔可夫链(Markov chain)得到了极大的应用。它究竟是什么?又能解决什么样问题呢?先从一个最简单的生活案例谈起(以下简称该案例为“小宝出行”)。

        小宝有3天假期,每天可以从郊游、逛街或者在家打游戏3种活动中选择一种,3天假期究竟要干啥,他自己浑然不知,他想看看天气情况再做决定。如果是晴天,小宝更可能选择去郊游,而如果下雨,小宝就可能会待在家打游戏了。天气这个事情不是小宝所能左右的。但不管怎样,小宝知道如下信息:

(1)每天的天气只与前一天的天气是关联的,也就是说如果今天下雨,那么明天很有可能也是雨天,但这并不是一定的,具有一定概率,同样,如果今天是晴天,明天也是晴天的可能就很大;

(2)如果前一天下雨,那么第二天仍然下雨的概率就有0.7,而转为晴天的概率只有0.3;但是如果前一天是晴天,则第二天有0.6的概率是晴天,而有0.4的概率将会下雨;

(3)第一天下雨的概率为0.6,晴天的概率为0.4;

小宝根据天气情况如下选择活动:

(a)如果下雨,3个活动的选择概率分别为:0.1,  0.4,  0.5,也就是说小宝更有可能选择在家打游戏(因为0.5的可能性最大);

(b)如果是晴天,3个活动的选择概率分别是:0.6,  0.3,  0.1,也就是说小宝更有可能选择出去郊游(因为0.6的可能性最大);

“小宝出行”案例已经讲完,现在我们会面临如下几个问题:

(i)小宝根据知道的这些消息,如何选择3天假期的活动呢?

(ii)如果已经知道了小宝3天假期安排的活动按顺序分别是:郊游、逛街、游戏。那么据此如何推算这3天的天气情况呢?

        下面引出马尔科夫链的相关概念。

马尔科夫链

        我们用x_i表示第i天小宝选择的活动,它可能的取值x_i\in { 郊游,逛街,游戏 } ,比如小宝最后做出的选择如下:

x1=郊游,x2=逛街,x3=游戏

        我们用y_i表示第i天的天气情况,它可能的取值y_i\in { 下雨,晴天 },那么3天的天气情况就可以表示为y1,y2,y3,它们就是需要去推算的。对于条件概率P(y_i|y_{i-1},...,y_1),它表示在已经知道第1天到第i-1天的天气情况下,第i天天气出现各种天气的概率。根据信息(1),每一天的天气情况只与前一天的天气有关,也就是说y_i只与y_{i-1}有关,所以这个概率就等于条件概率P(y_i|y_{i-1}}),即:

P(y_i|y_{i-1},...,y_1)=P(y_i|y_{i-1}})

称之为隐马尔科夫链(Hidden Markov Model),简称HMM,“隐”指的是天气情况y_i是不可观察的,是一个隐藏的随机变量。当然,隐马尔科夫链不单单指的是这个条件概率假设,它有完整的理论。之所以这么说是因为它在隐马尔科夫链中是一个重要的假设。

初始分布

        “小宝出行”案例中的信息(3)是天气的初始状态,也就是y_1,概率分布F(y_1)如下:

y_1 下雨 晴天
P(y_1) 0.6  0.4

称之为状态初始分布。

状态转移矩阵

        我们把y_i所有可能的取值集合称之为马尔科夫链的状态空间,每一个值称为一个状态,记为S。比如对于“小宝出行”案例,S= { 下雨,晴天 }。有了状态这个概念,就容易表达相邻两天的天气变化了,只需要将天气变化理解成是yi从一个状态转移到了另一个状态。根据状态空间S中所有可能的状态转移,我们得到如下矩阵:

               下雨    晴天

Q= 下雨   0.7     0.3

      晴天   0.4     0.6

矩阵的第k行第j列元素表示:从状态k转移到状态j的概率,比如矩阵Q的第1行第1列元素0.7表示天气从雨天转移到雨天的概率。矩阵Q被称为状态转移矩阵。如果状态空间S中有n个不同的状态,那么对应的状态转移矩阵也就变为n×n阶矩阵了,注意到这个矩阵的每一行元素的和是1,比如矩阵Q的第一行0.7+0.3=1,它表示状态是下雨时,转移到下雨或者晴天的概率,因为任何天气只能转移到晴天或者下雨,当然概率之和为1。

观测矩阵

        案例中的信息(b)表示在已知天气状态的情况下选择活动的概率,也就是条件概率P(x_i|y_i),所有这些条件概率组成一个矩阵,如下:

                 郊游   逛街    打游戏

G= 雨天     0.1     0.4       0.5

      晴天     0.6     0.3       0.1

小宝最后选择的活动{ 郊游,逛街,游戏 }是我们所能观测到的,所以这个矩阵被称为观测矩阵。

        有了上面这些基本概念之后,马尔科夫链就可以如下形式地表示:

\lambda=(F,Q,G)

即马尔科夫链由状态空间S的状态初始分布F,状态转移矩阵Q和观测矩阵G确定。

“小宝出行”的马尔科夫链可以直观地用下面这个图来表示:

图中实心圆表示每天可能出现的天气状态,晴天或者下雨,带数字的箭头表示状态转移和相应状态转移概率。注意到相邻两天的所有箭头正好构成一个状态转移矩阵。

        当然,马尔科夫链的相关理论是相当复杂的,比如它可以推广到某个随机变量与前两个随机变量相关的情况,或者连续的情况(随机过程)等等。本文只带读者入门,不做深入讨论。


一般表述

        下面我们给出HMM模型的一般表述,请与“小宝出行”案例进行对照帮助理解。首先我们假设YY是所有可能的隐藏状态的集合,XX是所有可能的观测状态的集合,即:

YY=\{{Y_1,Y_2,...,Y_N}\},XX=\{{X_1,X_2,...,X_M}\}

其中,N是隐藏状态的个数,M是所有可能观察状态的个数。

  对于一个长度为T的序列,Y是对应的状态序列, X是对应的观测序列,即:

T=\{{i_1,i_2,...,i_T}\},Y=\{{y_1,y_2,...,y_T}\},X=\{{x_1,x_2,...,x_T}\}

其中y_t\in YY,x_t\in XX

        我们对这里提到的序列做些解释:比如长度T是和“小宝出行”案例中的3天假期的长度是一致的。后面使用“时刻t“”来描述序列的概念,比如第一天,就对应t=1时刻,依次类推。在t时刻和t+1时刻的状态序列和观测序列分别是:

t时刻:Y=\{{y_1,y_2,...,y_t}\},X=\{{x_1,x_2,...,x_t}\}

t+1时刻:Y=\{{y_1,y_2,...,y_{t+1}\},X=\{{x_1,x_2,...,x_{t+1}\}

它们之间有一个关系,也就是在t+1时刻只是在t时刻的基础上增加了状态y_{t+1}和对应的观测值x_{t+1}。因为只有经历了t时刻才能到达t+1时刻,然后才出现状态y_{t+1}和对应的观察值x_{t+1}。理解这一点对后面的理论证明会很有帮助。

        HMM模型做了两个很重要的假设,如下:

齐次马尔科夫链假设

        即任意时刻t的隐藏状态y_t只依赖于它前一个隐藏状态y_{t-1}。当然这样假设有些极端,因为很多时候某一个隐藏状态不仅仅只依赖于它的前一个隐藏状态,可能依赖于前两个或者是前三个。但是这样假设的好处就是让模型简单,易于求解。假设在时刻t的隐藏状态是y_t=Y_i,在时刻t+1的隐藏状态是y_{t+1}=Y_j, 则从t时刻到t+1时刻的状态转移概率q_{ij}可以表示为:

q_{ij}=P(y_{t+1}=Y_j|y_t=Y_i)

这样q_{ij}构成的状态转移矩阵Q为:

Q=[q_{ij}]_{N\times N}

实际上,任意两个相邻时刻的状态转移矩阵都是一样的,也就是说状态转移矩阵和时刻t无关。这样q_{ij}就可以理解为第i个状态(Y_i)转移到第j个状态(Y_j)的概率。

观测独立性假设

        即任意时刻t的观测状态x_t只仅仅依赖于当前时刻的隐藏状态y_t,这也是为了简化模型假设。如果在时刻t的隐藏状态为y_t=Y_i, 而对应的观察状态为x_t=X_j, 则该时刻在隐藏状态y_t下观察值到x_t的的概率记为g_{ij},满足:

g_{ij}=P(x_t=X_j|y_t=Y_i)

这样由g_{ij}构成观测矩阵G为:

G=[g_{ij}]_{N\times M}

除此之外,我们需要在时刻t=1的初始状态概率分布F(y_1),如下:

y_1 Y_1 Y_2 ... Y_N
P(y_1) P(y_1=Y_1) P(y_1=Y_2) ... P(y_1=Y_N)

初始概率分布简记为:F=(f_1,f_2,...,f_N)     

一个HMM模型就可以由一个三元组λ表示如下:

\lambda=(F,Q,G)


观测序列生成机理

        观测序列生成机理指的是HMM在已知模型\lambda=(F,Q,G)后,就可以生成观测序列X=\{{x_1,x_2,...,x_T}\}了。它有助于我们理解HMM为什么可以表示成\lambda=(F,Q,G)形式。仍以“小宝出行”为例。模型\lambda=(F,Q,G)对应的初始分布,状态转移矩阵,观测矩阵分别如下:

y_1 下雨 晴天
P(y_1) 0.6  0.4

               下雨    晴天

Q= 下雨   0.7     0.3

      晴天   0.4     0.6

                 郊游   逛街    打游戏

G= 雨天     0.1     0.4       0.5

      晴天     0.6     0.3       0.1

小宝应该如下做出选择:

(1)第一天

根据初始分布和观测矩阵,就能计算出第一天选择3种活动的概率分布,如下:

P(x1=郊游)=P(x1=郊游,y1=晴天)+P(x1=郊游,y1=下雨)

=P(x1=郊游|y1=晴天)P(y1=晴天)+P(x1=郊游|y1=下雨)P(y1=下雨)=0.6*0.4+0.1*0.6=0.3

同理,P(x1=逛街)=0.3*0.4+0.4+0.6=0.36,P(x1=游戏)=0.1*0.4+0.5+0.6=0.34

因为P(x1=逛街)>P(x1=游戏)>P(x1=郊游),所以小宝第一天很可能会选择逛街。

(2)第二天

P(x2=郊游)=P(x2=郊游,y2=晴天)+P(x2=郊游,y2=下雨)

=P(x2=郊游|y2=晴天)P(y2=晴天)+P(x2=郊游|y2=下雨)P(y2=下雨)

式子中P(y2=晴天)可以如下计算:

P(y2=晴天)=P(y2=晴天,y1=晴天)+P(y2=晴天,y1=雨天)

=P(y2=晴天|y1=晴天)P(y1=晴天)+P(y2=晴天|y1=雨天)P(y1=雨天)

同理计算出P(y2=下雨)。这样就能得到P(x2=郊游),同理得到P(x2=逛街)和P(x2=游戏),最后根据计算结果,做出活动选择。

(3)第三天

计算与第二天相同。

        以上HMM观测序列的生成思路,可以一般地如下叙述:

(1)生成x1

由初始分布F和观测矩阵G,得到第一个观测值x1;

(2)生成xi(i = 2,...,T)

分为两步:

a、由转移矩阵Q和y_{i-1}的状态概率分布Q生成y_i的状态概率分布;

b、将y_i的状态概率分布看成是初始分布,重复步骤(1)生成xi;


HMM模型的三个经典问题

        HMM模型一共有三个经典的问题需要解决:

  1) 估计观察序列X概率。即给定模型\lambda=(F,Q,G)和观测序列X=\{{x_1,x_2,...,x_T}\},计算在模型λ下观测序列X出现的概率P(X|λ)。

     2)模型参数的学习问题。即给定观测序列X=\{{x_1,x_2,...,x_T}\},估计模型\lambda=(F,Q,G)的参数,使该模型下观测到序列X的条件概率P(X|λ)最大。即:\hat{\lambda}=argmax_{\lambda }P(X|\lambda)。这个问题的求解需要用到基于EM算法的鲍姆-韦尔奇算法。

  3)预测问题,也称为解码问题。即给定模型\lambda=(F,Q,G)和观测序列X=\{{x_1,x_2,...,x_T}\},求给定观测序列条件下,最可能出现的对应的状态序列Y=\{{y_1,y_2,...,y_T}\}。它的求解需要用到基于动态规划的维特比(viterbi)算法。

下面详细介绍三个问题求解方法:

经典问题一之前向算法

问题:给定模型\lambda=(F,Q,G)和观测序列X=\{{x_1,x_2,...,x_T}\},求P(X|λ)。

:实际上我们在<观测序列生成机理>一节已经给出可计算过程。这里我们给出一般情况的计算过程,并介绍一种简便的前向算法。为了方便起见,将P(X|λ)简记为P(X),在本经典问题求解过程中关于λ的条件概率也都如此简记。

        对于任意一个状态序列Y=\{{y_1,y_2,...,y_T}\},其中y_i\in YY=\{{Y_1,Y_2,...,Y_N}\}(i=1,...,T),可能出现的状态序列总共有N^T个。这里先假设Y=\{{y_1,y_2,...,y_T}\}是其中一个。那么

P(Y)=P(y_1,y_2,...,y_T)=P(y_T|y_1,..,y_{T-1})P(y_1,..,y_{T-1})=P(y_T|y_{T-1})P(y_1,..,y_{T-1})

最后一步是由观测独立性假设得到,即y_T只与y_1,..,y_{T-1}中的y_{T-1}有关。同理P(y_1,..,y_{T-1})递推下去,最终得到

P(Y)=P(y_T|y_{T-1})P(y_{T-1}|y_{T-2})...P(y_2|y_1)P(y1)

由转移矩阵和初始分布可以计算得到P(Y)

我们再来计算X和Y的条件概率P(X|Y)

P(X|Y)\\ =P(x_1,x_2,...,x_T|y_1,y_2,...,y_T)\\ =P(x_1|y_1,y_2,...,y_T)P(x_2|y_1,y_2,...,y_T)...P(x_T|y_1,y_2,...,y_T)\\ =P(x_1|y_1)P(x_2|y_2)...P(x_T|y_T)

证明过程中用到了观测独立性假设,即观测值x_i只与当前的状态y_i有关。由观测矩阵可以得到P(X|Y)

有了P(Y)P(X|Y),我们就能计算X和Y的联合概率P(X,Y)了,如下: 

P(X,Y)=P(X|Y)P(Y)

那么最终P(X)就可以如下计算:

P(X)=\sum_{Y}P(X,Y)

等式右边表示在各种可能的状态下(N^T个),所以

P(X)=\sum_{Y}P(X,Y)=\sum_{Y}P(X|Y)P(Y)\\ =\sum_{Y}P(x_1|y_1)P(x_2|y_2)...P(x_T|y_T)\cdot P(y_T|y_{T-1})P(y_{T-1}|y_{T-2})...P(y_2|y_1)P(y1)

到此就完成了P(X)的计算。

        下面对以上方法计算的复杂度做个简单说明。根据P(X)的计算公式,完成一个观测值X=\{{x_1,x_2,...,x_T}\}的概率P(X)计算,需要计算2TN^{T}个运算(乘积和加法),使用大O表示就是复O(TN^{T})。这种暴力计算手段,计算复杂度随着T和N的增长成指数级增长,实际中根本无法计算。下面介绍一种更简单的计算方法,称之为“前向算法”。

        假设在时刻t,状态为y_i,观察值为X=\{{x_1,x_2,...,x_t}\}的概率记为P(X^{(t)},y^{(t)}_i),称之为前向概率。为了区分两个不同时刻对应的状态序列和观测序列的区别,我们在右上方添加了相应的符号,比如y^{(t)}_i表示在t时刻,状态为y_iX^{(t)表示时刻t观察值为X。现在假设我们已经找到了t时刻,所有可能状态下,观察值为X的前向概率,分别如下:

P(X^{(t)},Y^{(t)}_1)P(X^{(t)},Y^{(t)}_2),...,P(X^{(t)},Y^{(t)}_N)

现在我们使用递推法计算出在t+1时刻各个状态的前向概率P(X^{(t+1)},y^{(t+1)}_i),即:

P(X^{(t+1)},Y^{(t+1)}_1)P(X^{(t+1)},Y^{(t+1)}_2),...,P(X^{(t+1)},Y^{(t+1)}_N)

P(X^{(t+1)},y^{(t)}_j,y^{(t+1)}_i)表示t时刻状态为y_j,且t+1时刻状态为y_i,观察序列为X的概率,所以

P(X^{(t+1)},y^{(t+1)}_i)\\ =\sum_{j}P(X^{(t+1)},y^{(t)}_j,y^{(t+1)}_i)\\ =\sum_{j}P(X^{(t+1)}|y^{(t)}_j,y^{(t+1)}_i)P(y^{(t+1)}_i,y^{(t)}_j)\\ =\sum_{j}P(X^{(t)},x_{t+1}|y^{(t)}_j,y^{(t+1)}_i)P(y^{(t+1)}_i,y^{(t)}_j)\\ =\sum_{j}P(X^{(t)}|y^{(t)}_j)P(x_{t+1}|y^{(t+1)}_i)P(y^{(t+1)}_i|y^{(t)}_j)P(y^{(t)}_j)\\ =\sum_{j}P(X^{(t)},y^{(t)}_j)P(x_{t+1}|y^{(t+1)}_i)P(y^{(t+1)}_i|y^{(t)}_j)\\ =P(x_{t+1}|y^{(t+1)}_i)\sum_{j}P(X^{(t)},y^{(t)}_j)P(y^{(t+1)}_i|y^{(t)}_j)\\

推导用到下面这个等式:     

P(X^{(t+1)}|y^{(t)}_j,y^{(t+1)}_i)=P(X^{(t)},x_{t+1}|y^{(t)}_j,y^{(t+1)}_i)=P(X^{(t)},y^{(t)}_j)P(x_{t+1}|y^{(t+1)}_i)            

理由是:HMM满足观测独立性假设,而且t+1时刻观察到的整个序列X^{(t+1)必须由t时刻观察到的整个序列X^{(t)和t+1时候观察到的单个x_{t+1}构成。

另外,递推关系的初始值,也就是t=1时刻的前向概率P(X^{(1)},y^{(1)}_i)为:

P(X^{(1)},y^{(1)}_i)=P(x_1,y_1)=P(x_1|y_1)P(y_1)

这样有了前向概率的初始和递推关系,就可以计算任意时刻t的前向概率P(X^{(t)},y^{(t)}_i)了。

经典问题一中需要求的P(X),其实就是在时刻T,观察到X=\{{x_1,x_2,...,x_T}\}的概率,即:

P(X)=P(X^{(T)})=\sum_{i}P(X^{(T)},y^{(T)}_i)       (1)

下面对该算法的计算复杂度说明,我们先计算从P(X^{(t)},y^{(t)}_i)P(X^{(t+1)},y^{(t+1)}_i)的计算量,即:

P(X^{(t+1)},y^{(t+1)}_i)\\ =P(x_{t+1}|y^{(t+1)}_i)\sum_{j}P(X^{(t)},y^{(t)}_j)P(Y^{(t+1)}_i|y^{(t)}_j)\\

总共做2N+1个乘积和加法运算,那么从P(X^{(1)},y^{(1)}_i)P(X^{(T+1)},y^{(T+1)}_i)就需要计算(T-1)(2N+1)个乘积和加法运算,再

再根据(1)式,总共需要计算(T-1)N(2N+1),大O表示为O(TN^2)。从复杂度看,比之前的暴力方法提升了很多。实际上,暴力方法是穷举法,前向概率是递推法。

经典问题二

略。

经典问题三之viterbi算法

        经典问题三就是给定模型\lambda=(F,Q,G)和观测序列X=\{{x_1,x_2,...,x_T}\},然后预测最可能出现的对应的状态序列Y=\{{y_1,y_2,...,y_T}\}。数学表达如下:

\hat{Y}=argmax_{Y}P(Y^{(T)}|X^{(T)})

也就是寻找Y使得条件概率P(Y^{(T)}|X^{(T)})最大。

解:因为P(Y^{(T)}|X^{(T)})=P(Y^{(T)},X^{(T)})/P(X^{(T)})X已经给定,所以P(X^{(T)})是个常数,问题等价于找到Y使得联合概率P(Y^{(T)},X^{(T)})最大即可。

下面结合图介绍viterbi算法,如图:

图中每个实心圆表示某个时刻可能出现的状态,每个方块表示对应的观测值。实心圆之间的箭头,表示状态转移,比如图中的红色箭头,表示t-1时刻状态Y1,在t时刻转移为状态Y2。

         我们注意到,任意一个状态序列Y=\{{y_1,y_2,...,y_T}\}正好与图中的一条路径一一对应,这条路径从t=1时刻状态为y_1的实心圆开始,然后沿着箭头连接到t=2时刻状态为y_2的实心圆,一直连接下去,直到t=T时刻状态为y_T的实心圆。对应的这条路径记为p=(y_1,y_2,...,y_T)。所以求解Y,其实就是从图中寻找一条最优路径p使得联合概率P(Y^{(T)},X^{(T)})最大。这是viterbi算法思想一。下面我们来寻找这样的路径。

        我们知道从时刻1到达时刻t总共有N^t条不同路径,将它们根据时刻t的状态分为N类,也就是在时刻t到达状态Y_1的所有路径分为一类,时刻t到达状态Y_2的路径分为一类,等等,记类别分别为C_i(i=1,...,N)。现在从所有路径中寻找一条使得P(Y^{(T)},X^{(T)})最大的最优路径问题就转化为从N个类中先分别找出一条使得P(Y^{(T)},X^{(T)})最大的路径,然后再从这N条路径中找到使P(Y^{(T)},X^{(T)})最大的路径。这样我们就将一个问题分解成了N个小问题。这是viterbi算法思想二。现在固定t时刻的状态,假设为i,在类别C_i中使P(Y^{(t)},X^{(t)})达到最大的路径记为({\hat{y_1},\hat{y_2},...,\hat{y}_{t-1}},i),最大概率记为\delta_t(i)。另外,我们还需要记录下此时\hat{y}_{t-1}}的状态,也就是倒数第二个节点的状态,记为\varphi_t(i),即\hat{y}_{t-1}}=\varphi_t(i)

根据\delta_t(i)的定义,它可以如下表示:

\delta_t(i)=max_{y_1,...,y_{t-1}}P(y_1,...,y_{t-1},y_t=i,x_1,...,x_t)

同理t+1时刻对应的\delta_{t+1}(i),如下表示:

\delta_{t+1}(i)=max_{y_1,...,y_{t}}P(y_1,...,y_t,y_{t+1}=i,x_1,x_2,...,x_{t+1})

下面推导\delta_t(i)\delta_{t+1}(i)两者的关系,注意到x_{t+1}x_1,...x_t,y_1,...,y_t无关,y_{t+1}只与y_{t}有关,所以

P(y_1,...,y_t,y_{t+1}=i,x_1,x_2,...,x_{t+1})\\ =P(y_{t+1}=i,x_{t+1}|x_1,...x_t,y_1,...,y_t)P(x_1,...x_t,y_1,...,y_t)\\=P(y_{t+1}=i,x_{t+1}|y_t)P(x_1,...x_t,y_1,...,y_t)\\ =P(x_{t+1}|y_t,y_{t+1}=i)P(y_{t+1}=i|y_t)P(x_1,...x_t,y_1,...,y_t)\\ =P(x_{t+1}|y_{t+1}=i)P(y_{t+1}=i|y_t)P(x_1,...x_t,y_1,...,y_t)   (2)

等式(2)两边先对变量y_1,...,y_{t-1}求最大值,然后对变量y_t求最大值:

即:

\delta_{t+1}(i)\\ =max_{y_1,...,y_{t}}P(y_1,...,y_t,y_{t+1}=i,x_1,x_2,...,x_{t+1})\\ =max_{y_t}max_{y_1,...,y_{t-1}}P(y_1,...,y_t,y_{t+1}=i,x_1,x_2,...,x_{t+1}) \\=max_{y_t}max_{y_1,...,y_{t-1}}P(x_{t+1}|y_{t+1}=i)P(y_{t+1}=i|y_t)P(x_1,...x_t,y_1,...,y_t)\\ =P(x_{t+1}|y_{t+1}=i)max_{y_t}max_{y_1,...,y_{t-1}}P(y_{t+1}=i|y_t)P(x_1,...x_t,y_1,...,y_t)\\ =P(x_{t+1}|y_{t+1}=i)max_{y_t}[P(y_{t+1}=i|y_t)max_{y_1,...,y_{t-1}}P(x_1,...x_t,y_1,...,y_t)]\\ =P(x_{t+1}|y_{t+1}=i)max_{y_t}[P(y_{t+1}=i|y_t)max_{j\in YY}\delta_t(j)]\\ =P(x_{t+1}|y_{t+1}=i)max_{j\in YY}[P(y_{t+1}=i|y_t=j)max_{j\in YY}\delta_t(j)]\\ =P(x_{t+1}|y_{t+1}=i)max_{j\in YY}P(y_{t+1}=i|y_t=j)\delta_t(j)     (3)

这样\delta_t(i)\delta_{t+1}(i)递归就建立起来了。

这个递归说明:如果我们已经找到了从时刻1到时刻t的所有可能状态j对应的最大概率\delta_t(j),这个概率乘以转移概率P(y_{t+1}=i|y_t=j),然后求得它们乘积中的最大值,最后再乘以观测概率P(x_{t+1}|y_{t+1}=i),也就找到了从时刻1到时刻t+1状态为i的最大概率\delta_{t+1}(i)。这样

\delta_{t+1}(Y_1)\delta_{t+1}(Y_2),...,\delta_{t+1}(Y_N)

中的最大值对应的那条路径就是我们要找的。假设它们中的最大者是\delta_{t+1}(\hat{y}_{t+1}),那么现在我们至少能够确定最优的路径的最后两个节点,分别是\hat{y}_t=\varphi (\hat{y}_{t+1})\hat{y}_{t+1}。最优路径中前面这些节点如何找到呢?事实上上面的递推公式(3)隐含了一个性质:

\delta_{t+1}(i)的最优路径p=(\hat{y_1},...,\hat{y}_{t-1},\hat{y_t}=j,\hat{y}_{t+1}=i)的前t个节点组成的路径q=(\hat{y_1},...,\hat{y}_{t-1},\hat{y_t}=j)\delta_{t}(j)对应的最优路径。因为p\delta_{t+1}(i)的最优路径,所以公式(3)简化为

\delta_{t+1}(i)=P(x_{t+1}|y_{t+1}=i)P(y_{t+1}=i|y_t=j)\delta_t(j)

当状态i和j固定后,\delta_{t+1}(i)\delta_{t}(j)成正比,那么q就是\delta_{t}(j)的最优路径,如果不是,假设\delta_{t}(j)的最优路径是m=(\hat{k_1},...,\hat{k}_{t-1},\hat{y_t}=j)(m\neq q),那么路径n=(\hat{k_1},...,\hat{k}_{t-1},\hat{y_t}=j,\hat{y}_{t+1}=i)(n\neq p)将是\delta_{t+1}(i)的最优路径,矛盾。

基于上面这些介绍,我们们使用\varphi_{t+1}(i)记录的状态往回追溯就可以找出最优路径。具体如下:

(1)\delta_{t+1}(\hat{y}_{t+1})使得P(Y^{(t+1)},X^{(t+1)})最大,所以\hat{y}_{t+1}就是t+1时刻的状态;

(2)\varphi_{t+1}(i)记录了在t+1时刻时,第t个节点的状态,\varphi_{t+1}(\hat{y}_{t+1})就是这个节点的状态,记作\hat{y}_{t}=\varphi_{t+1}(\hat{y}_{t+1})

(3)\varphi_{t}(\hat{y}_{t})的值记录的就是在t时刻,t-1时刻的状态,记作\hat{y}_{t-1}=\varphi_{t}(\hat{y}_{t})

...

按照递归\hat{y}_{t}=\varphi_{t+1}(\hat{y}_{t+1})可以追溯到t=1时刻的状态,也就能得到

\hat{Y}=\{{\hat{y_1},\hat{y_2},...,\hat{y}_{t+1}}\}

viterbi算法基本思路:

(1)由初始时的\delta_1(i)和递推公式,计算出任意时刻t的\delta_t(i),同时记录前一个节点的状态\varphi_t (i);

(2)找到\delta_t(i)中的最大者,它对应的路径就是我们要找的,此时可以得到最后两个节点状态i和\varphi_t (i)

(3)使用\varphi_t(i)记录的前一个状态,回溯出所有时刻的状态,得到\hat{Y}=\{{\hat{y_1},\hat{y_2},...,\hat{y}_{t+1}}\}

viterbi算法求解案例

下面我们以“小宝出行”案例来熟悉下vertibi算法。

(1)对于时刻t=1,也就是第一天,可能的状态为{下雨,晴天},小宝第一天选择的是郊游,另外,从Start开始只有一条路径到达晴天,所以

\delta_1(晴天)=P(x1=郊游,y1=晴天)=P(x1=郊游|y1=晴天)P(y1=晴天)=0.6*04=0.24

\delta_1(下雨)=P(x1=郊游,y1=下雨)=P(x1=郊游|y1=下雨)P(y1=下雨)=0.1*0.6=0.06

因为第一天的前一天没有状态,所以\varphi_1(i)不存在。

(2)对于时刻t=2,也就是第二天,小宝选择的是逛街,根据递推有:

\delta_2(i)=P(x_{2}|y_{2}=i)max_{j\in YY}P(y_{2}=i|y_1=j)\delta_1(j),所以,

\delta_2(晴天)=P(x2=逛街|y2=晴天)*max{P(y2=晴天|y1=晴天)\delta_1(晴天),P(y2=晴天|y1=下雨)\delta_1(下雨)}

            =0.3*max{0.6*0.24,0.3*0.06}=0.3*max{0.144,0.018}=0.0432

\varphi_2(晴天)=晴天

同理,

\delta_2(下雨)=P(x2=逛街|y2=下雨)*max{P(y2=下雨|y1=晴天)\delta_1(晴天),P(y2=下雨|y1=下雨)\delta_1(下雨)}

             =0.4*max{0.4*0.24,0.7*0.06}=0.4*max{0.096,0.042}=0.0384

\varphi_2(下雨)=晴天

(3)对于时刻t=3,也就是第三天,小宝选择游戏,根据递推:

\delta_3(i)=P(x_{3}|y_{3}=i)max_{j\in YY}P(y_{3}=i|y_2=j)\delta_2(j),所以,

\delta_3(晴天)=P(x3=游戏|y3=晴天)*max{P(y3=晴天|y2=晴天)\delta_2(晴天),P(y3=晴天|y2=下雨)\delta_2(下雨)}

             =0.1*max{0.6*0.0432,0.3*0.0384}=0.1*max{0.02592,0.01152}=0.002592

\varphi_3(晴天)=晴天

\delta_3(下雨)=P(x3=游戏|y3=下雨)*max{P(y3=下雨|y2=晴天)\delta_2(晴天),P(y3=下雨|y2=下雨)\delta_2(下雨)}

             =0.5*max{0.4*0.0432,0.7*0.0384}=0.5*max{0.01728,0.02688}=0.01344

\varphi_3(下雨)=下雨

下面开始回溯:

\delta_3(下雨)>\delta_3(晴天),所以第3天下雨,而\varphi_3(下雨)=下雨,所以第二天也是下雨,根据\varphi_2(下雨)=晴天,所以第一天是晴天。

推算出3天天气是:晴天,下雨,下雨。

viterbi算法代码实现

import numpy as np


def viterbi(trans_prob, emit_prob, init_prob, views, states, obs):
    """
    viterbi算法

    :param trans_prob: 状态转移概率矩阵
    :param emit_prob: 观察概率矩阵,也称为发射概率矩阵
    :param init_prob: 初始状态分布
    :param views: 所有可能的观测值集合
    :param states: 所有可能的状态集合
    :param obs: 实际观测值序列
    :return:
    """

    state_num, obs_len = len(states), len(obs)
    delta = np.array([[0] * state_num] * obs_len, dtype=np.float64)
    phi = np.array([[0] * state_num] * obs_len, dtype=np.int64)
    print('state_num=', state_num, 'obs_len=', obs_len)
    print('delta=', delta)
    print('phi=', phi)
    # 初始化
    for i in range(state_num):
        delta[0, i] = init_prob[i] * emit_prob[i][views.index(obs[0])]
        phi[0, i] = 0
    print('初始化后delta=', delta)
    print('初始化后phi=', phi)

    # 递归计算
    for i in range(1, obs_len):
        for j in range(state_num):
            tmp = [delta[i - 1, k] * trans_prob[k][j] for k in range(state_num)]
            delta[i, j] = max(tmp) * emit_prob[j][views.index(obs[i])]
            phi[i, j] = tmp.index(max(tmp))

    # 最终的概率及节点
    max_prob = max(delta[obs_len - 1, :])
    last_state = int(np.argmax(delta[obs_len - 1, :]))

    # 最优路径path
    path = [last_state]
    for i in reversed(range(1, obs_len)):
        end = path[-1]
        path.append(phi[i, end])

    hidden_states = [states[i] for i in reversed(path)]

    return max_prob, hidden_states


def main():
    # 所有可能的状态集合
    states = ('晴天', '下雨')
    # 观测集合
    views = ['郊游', '逛街', '游戏']
    # 转移概率: Q -> Q
    trans_prob = [[0.6, 0.4],
                  [0.3, 0.7]]
    # 观测概率, Q -> V
    emit_prob = [[0.6, 0.3, 0.1],
                 [0.1, 0.4, 0.5]]
    # 初始概率
    init_prob = [0.4, 0.6]
    # 观测序列
    obs = ['郊游', '逛街', '游戏']

    max_prob, hidden_states = viterbi(trans_prob, emit_prob, init_prob, views, states, obs)
    print('最大的概率为: %.5f.' % max_prob)
    print('隐藏序列为:%s.' % hidden_states)


if __name__ == '__main__':
    main()

HMM模型应用

中文分词

股市分析

发布了89 篇原创文章 · 获赞 79 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/L_15156024189/article/details/104856989