机器学习算法 01 —— K-近邻算法(数据集划分、归一化、标准化)
机器学习算法 02 —— 线性回归算法(正规方程、梯度下降、模型保存)
机器学习算法 03 —— 逻辑回归算法(精确率和召回率、ROC曲线和AUC指标、过采样和欠采样)
机器学习算法 04 —— 决策树(ID3、C4.5、CART,剪枝,特征提取,回归决策树)
机器学习算法 05 —— 集成学习(Bagging、随机森林、Boosting、AdaBost、GBDT)
机器学习算法 06 —— 聚类算法(k-means、算法优化、特征降维、主成分分析PCA)
机器学习算法 07 —— 朴素贝叶斯算法(拉普拉斯平滑系数、商品评论情感分析案例)
机器学习算法 08 ——支持向量机SVM算法(核函数、手写数字识别案例)
机器学习算法 09 —— EM算法(马尔科夫算法HMM前置学习,EM用硬币案例进行说明)
机器学习算法 10 —— HMM模型(马尔科夫链、前向后向算法、维特比算法解码、hmmlearn)
学习目标:
在机器学习算法中,⻢尔可夫链是个很重要的概念。
⻢尔可夫链(Markov chain),⼜称离散时间⻢尔可夫链(discrete-time Markov chain),因俄国数学家安德烈·⻢尔可夫(俄语:Андрей Андреевич Марков)得名。
⻢尔科夫链是状态空间中从⼀个状态到另⼀个状态转换的随机过程。 如下图所示,
该过程要求具备“⽆记忆”的性质: 下⼀状态的概率分布只能由当前状态决定,在时间序列中它前⾯的所有事件都与之⽆关。这种特定类型的“⽆记忆性”称作⻢尔可夫性质。
在⻢尔可夫链的每⼀步,系统根据概率分布,可以从⼀个状态变到另⼀个状态,也可以保持当前状态。就像上图,可能从A到B,也可能A到A。
状态的改变称为转移,与不同的状态改变相关的概率叫做转移概率。
⻢尔可夫链的数学表示为:
P ( x t + 1 ∣ . . . , x t − 2 , x t − 1 , x t ) = P ( x t + 1 ∣ x t ) P(x_{t+1}|...,x_{t-2},x_{t-1},x_t)=P(x_{t+1}|x_t) P(xt+1∣...,xt−2,xt−1,xt)=P(xt+1∣xt)
可以看出,状态 x t + 1 x_{t+1} xt+1只由它前一个状态 x t x_t xt决定,与时间序列中前面的其他事件 x t − 1 , x t − 2 . . . x_{t-1},x_{t-2}... xt−1,xt−2...都无关。
既然某⼀时刻状态转移的概率只依赖前⼀个状态,那么**只要求出系统中任意两个状态之间的转移概率,这个⻢尔科夫链的模型就定了。 **
下图中的⻢尔科夫链是⽤来表示股市模型,共有三种状态:⽜市(Bull market), 熊市(Bear market)和横盘(Stagnant market)。
每⼀个状态都以⼀定的概率转化到下⼀个状态。⽐如,⽜市以0.9的概率转化到自身状态,以0.075的概率转化到熊市的状态。
这个状态概率转化图可以以矩阵的形式表示。
如果我们定义矩阵P某⼀位置 P ( i , j ) P(i, j) P(i,j)的值为 P ( i ∣ j ) P(i|j) P(i∣j),即从状态i变为状态j的概率。
另外定义⽜市、熊市、横盘的状态分别为0、1、2,这样我们得到了⻢尔科夫链模型的状态转移矩阵为:
P = [ 0.9 0.075 0.025 0.15 0.8 0.05 0.25 0.25 0.5 ] P = \left[ \begin{matrix} 0.9 & 0.075 & 0.025\\ 0.15 & 0.8 & 0.05\\ 0.25 & 0.25 & 0.5 \end{matrix} \right] P=⎣⎡0.90.150.250.0750.80.250.0250.050.5⎦⎤
隐⻢尔可夫模型(Hidden Markov Model,HMM)是统计模型,它⽤来描述⼀个含有隐含未知参数的⻢尔可夫过程。
其难点是从可观察的参数中确定该过程的隐含参数,然后利⽤这些参数来作进⼀步的分析,例如模式识别。
假设我⼿⾥有三个不同的骰⼦。
第⼀个骰⼦是我们平常⻅的骰⼦(称这个骰⼦为D6),6个⾯,每个⾯(1,2,3,4,5,6)出现的概率是1/6。
第⼆个骰⼦是个四⾯体(称这个骰⼦为D4),每个⾯(1,2,3,4)出现的概率是1/4。
第三个骰⼦有⼋个⾯(称这个骰⼦为D8),每个⾯(1,2,3,4,5,6,7,8)出现的概率是1/8。
我们先从三个骰⼦⾥挑⼀个,挑到每⼀个骰⼦的概率都是1/3。
然后我们掷骰⼦,会得到1、2、3、4、5、6、7、8中的某个数字。不停的重复上述过程,我们会得到⼀串数字,每个数字都是1至8中的⼀个。
例如我们可能得到这么⼀串数字(掷骰⼦10次):1、6、3、5、2、7、3、5、2、4
这串数字叫做可⻅状态链。
但是在隐⻢尔可夫模型中,我们不仅仅有这么⼀串可⻅状态链,还有⼀串隐含状态链。
在这个例⼦⾥,这串隐含状态链就是你⽤的骰⼦的序列,例如隐含状态链有可能是:D6、D8、D8、D6、D4、D8、D6、D6、D4、D8
⼀般来说,HMM中说到的⻢尔可夫链其实是指隐含状态链,因为隐含状态(骰⼦)之间存在转换概率(transition probability)
同样的,尽管可⻅状态之间没有转换概率,但是隐含状态和可⻅状态之间有⼀个概率叫做输出概率(emission probability)。
就我们的例⼦来说,六⾯骰(D6)产⽣1的输出概率是1/6。产⽣2,3,4,5,6的概率也都是1/6。
我们同样可以对输出概率进⾏其他定义。⽐如,我有⼀个被赌场动过⼿脚的六⾯骰⼦,掷出来是1的概率更⼤,是1/2,掷出来是2,3,4,5,6的概率是1/10。
其实对于HMM来说,如果提前知道所有隐含状态之间的转换概率和所有隐含状态到所有可⻅状态之间的输出概率,做模拟是相当容易的。但是应⽤HMM模型时候呢,往往是缺失了⼀部分信息的。
有时候你知道骰⼦有⼏种,每种骰⼦是什么,但是不知道掷出来的骰⼦序列;
有时候你只是看到了很多次掷骰⼦的结果,剩下的什么都不知道。
如果应⽤算法去估计这些缺失的信息,就成了⼀个很重要的问题。这些算法会在后⾯详细讲。
和HMM模型相关的算法主要分为三类,分别解决三种问题:
1)知道骰⼦有⼏种(隐含状态数量),每种骰⼦有几面(转换概率),根据掷骰⼦掷出的结果(可⻅状态链),我想知道每次掷出来的都是哪种骰⼦(隐含状态链)。
这个问题在语音识别领域叫解码问题,它其实有两种解法,会给出两个不同的答案。每个答案都对,只不过这些答案的意义不⼀样。
第⼀种解法求最⼤似然状态路径,说通俗点呢,就是我求⼀串骰⼦序列,这串骰⼦序列产⽣观测结果的概率最⼤。
第⼆种解法呢,就不是求⼀组骰⼦序列了,⽽是求每次掷出的骰⼦分别是某种骰⼦的概率。⽐如说我看到结果后,我可以求得第⼀次掷骰⼦是D4的概率是0.5,D6的概率是0.3,D8的概率是0.2。
2)还是知道骰⼦有⼏种(隐含状态数量),每种骰⼦有几面(转换概率),根据掷骰⼦掷出的结果(可⻅状态链), 我想知道掷出这个结果的概率。
看似这个问题意义不⼤,因为你掷出来的结果很多时候都对应了⼀个⽐较⼤的概率。
问这个问题的⽬的呢,其实是检测观察到的结果和已知的模型是否吻合。
如果很多次结果都对应了⽐较⼩的概率,那么就说明我们已知的模型很有可能是错的,有⼈偷偷把我们的骰⼦給换了。
3)知道骰⼦有⼏种(隐含状态数量),不知道每种骰⼦有几面(转换概率),观测到很多次掷骰⼦的结果(可⻅状态链),我想反推出每种骰⼦是什么(转换概率)。
这个问题很重要,因为这是最常⻅的情况。
很多时候我们只有可⻅结果,不知道HMM模型⾥的参数,我们需要从可⻅结果估计出这些参数,这是建模的⼀个必要步骤。
这个问题实⽤价值不⾼。由于对下⾯较难的问题有帮助,所以先在这⾥提⼀下。
知道骰⼦有⼏种(3种),每种骰⼦是什么(6面、4面、8面),每次掷的都是什么骰⼦(如下图),根据掷骰⼦掷出的结果,求产⽣这个结果的概率。
第一次掷的6面骰子,掷出1;第二次掷的8面骰子,掷出6;第三次掷的8面骰子,掷出3。
计算出现这个结果的概率:
P = P ( D 6 ) ∗ P ( D 6 → 1 ) ∗ P ( D 6 → D 8 ) ∗ P ( D 8 → 6 ) ∗ P ( D 8 → D 8 ) ∗ P ( D 8 → 3 ) = 1 3 ∗ 1 6 ∗ 1 3 ∗ 1 8 ∗ 1 3 ∗ 1 8 P=P(D6)*P(D6 \to 1)*P(D6 \to D8)*P(D8\to 6)*P(D8 \to D8)*P(D8 \to 3)\\ =\frac{1}{3}*\frac{1}{6}*\frac{1}{3}*\frac{1}{8}*\frac{1}{3}*\frac{1}{8} P=P(D6)∗P(D6→1)∗P(D6→D8)∗P(D8→6)∗P(D8→D8)∗P(D8→3)=31∗61∗31∗81∗31∗81
解释一下, P ( D 6 ) = P ( D 6 → D 8 ) = P ( D 8 → D 8 ) = 1 3 P(D6)=P(D6 \to D8)=P(D8 \to D8)=\frac{1}{3} P(D6)=P(D6→D8)=P(D8→D8)=31因为掷出每种骰子的概率都是 1 3 \frac{1}{3} 31, P ( D 6 → 1 ) = 1 6 P(D6\to 1)=\frac{1}{6} P(D6→1)=61是6面骰掷出1的概率。
这⾥用的是第⼀种解法,解最⼤似然路径问题。
知道骰⼦有⼏种(3种),每种骰⼦有几面(6面、4面、8面),根据掷骰⼦掷出的结果(例如1 6 3 5 2 7 3 5 2 4),我想知道每次掷出来的都是哪种骰⼦(最大可能的骰子序列)。
最简单⽽暴⼒的⽅法就是穷举所有可能的骰⼦序列,然后依照上⼀个问题的解法把每个序列对应的概率算出来,接着从⾥⾯把对应最⼤概率的序列挑出来就⾏了。如果⻢尔可夫链不⻓,当然可⾏。如果⻓的话,穷举的数量太⼤,就很难完成了。
另外⼀种很有名的算法叫做维特⽐算法(Viterbi Algorithm)。要理解这个算法,我们先看⼏个简单的列⼦。
⾸先,如果我们只掷⼀次骰⼦,看到结果为1。对应的最⼤概率骰⼦序列就是D4,因为D4产⽣1的概率是1/4,⾼于1/6和1/8。即 P 1 ( D 4 ) = 1 4 P_1(D4)=\frac{1}{4} P1(D4)=41
把这个情况扩展,我们掷两次骰子,看到结果为1、6。显然,要取到最⼤概率,第⼀个骰⼦必须为D4,第二个骰子得是D6(D4不可能掷出6,8面骰出现6的概率小于6面骰)。这时,第⼆个骰⼦取到D6的最⼤概率是:
P 2 ( D 6 ) = P ( D 4 ) ∗ P ( D 4 → 1 ) ∗ P ( D 4 → D 6 ) ∗ P ( D 6 → 6 ) = 1 3 ∗ 1 4 ∗ 1 3 ∗ 1 6 P_2(D6)=P(D4)*P(D4 \to 1)*P(D4 \to D6)*P(D6 \to 6)\\ =\frac{1}{3}*\frac{1}{4}*\frac{1}{3}*\frac{1}{6} P2(D6)=P(D4)∗P(D4→1)∗P(D4→D6)∗P(D6→6)=31∗41∗31∗61
继续拓展,我们掷三次骰⼦,看到结果为1、6、3。同样,我们计算第三个骰⼦分别是D6,D4,D8的最⼤概率。我们再次发现,要取到最⼤概率,第⼆个骰⼦必须为D6。这时,第三个骰⼦取到D4的最⼤概率是:
P 3 ( D 4 ) = P 2 ( D 6 ) ∗ P ( D 6 → D 4 ) ∗ P ( D 4 → 3 ) = 1 216 ∗ 1 3 ∗ 1 4 P_3(D4)=P_2(D6)*P(D6 \to D4)*P(D4 \to 3)\\ =\frac{1}{216}*\frac{1}{3}*\frac{1}{4} P3(D4)=P2(D6)∗P(D6→D4)∗P(D4→3)=2161∗31∗41
所以掷三次骰子的最大概率序列的D4、D6、D4,写到这里⼤家应该看出点规律了。既然掷骰⼦⼀、⼆、三次可以算,掷多少次都可以以此类推。我们发现,我们要求最⼤概率骰⼦序列时要做这么⼏件事情。
⾸先,不管序列多⻓,要从序列⻓度为1算起,算序列⻓度为1时取到每个骰⼦的最⼤概率。
然后,逐渐增加⻓度,每增加⼀次⻓度,重新算⼀遍在这个⻓度下最后⼀个位置取到每个骰⼦的最⼤概率。因为上⼀个⻓度下的取到每个骰⼦的最⼤概率都算过了,重新计算的话其实不难。
当我们算到最后⼀位时,就知道最后⼀位是哪个骰⼦的概率最⼤了。然后,我们要把对应这个最⼤概率的序列从后往前推出来。
知道骰⼦有⼏种(隐含状态数量),不知道每种骰⼦有几面(转换概率),观测到很多次掷骰⼦的结果(可⻅状态链),我想反推出每种骰⼦是什么(转换概率)。
不知道每种骰子有几面,就是说不知道每个骰子掷出某个数字的概率。
⽐如说你怀疑⾃⼰的六⾯骰被赌场动过⼿脚了,有可能被换成另⼀种六⾯骰,这种六⾯骰掷出来是1的概率更⼤,是1/2,掷出来是2,3,4,5,6的概率是1/10。这该如何处理呢?
答案很简单,算⼀算正常的三个骰⼦掷出⼀段序列的概率,再算⼀算不正常的六⾯骰和另外两个正常骰⼦掷出这段序列的概率。如果前者⽐后者⼩,你就要⼩⼼了。
⽐如说掷骰⼦的结果是:
要算⽤正常的三个骰⼦掷出这个结果的概率,其实就是将所有可能情况的概率进⾏加和计算。
我们会应⽤⼀个和前⼀个问题类似的解法,只不过前⼀个问题关⼼的是概率最⼤值,这个问题关⼼的是概率之和。解决这个问题的算法叫做前向算法(forward algorithm)。
⾸先,如果我们只掷⼀次骰⼦,看到结果为1。产⽣这个结果的总概率为0.18。
简单解释一下,掷一次骰子出现1,可能投的骰子是D6、D4、D8,将可能求和,得到出现这个结果的总概率。
我们掷两次骰⼦,看到结果为1,6。产⽣这个结果的总概率可以按照如下计算,总概率为0.05:
解释下P2中第一格, P 1 ( D 6 ) ∗ 1 3 ∗ 1 6 P1(D6)*\frac{1}{3}*\frac{1}{6} P1(D6)∗31∗61表示第一次投D6出现1且第二次也投的D6出现6, P 1 ( D 4 ) ∗ 1 3 ∗ 1 6 P1(D4)*\frac{1}{3}*\frac{1}{6} P1(D4)∗31∗61表示第一次投D4出现1且第二次投的D6出现6, P 1 ( D 8 ) ∗ 1 3 ∗ 1 6 P1(D8)*\frac{1}{3}*\frac{1}{6} P1(D8)∗31∗61表示第一次投D8出现1且第二次投的D6出现6
解释下P2中第二格, P 1 ( D 6 ) ∗ 1 3 ∗ 0 P1(D6)*\frac{1}{3}*0 P1(D6)∗31∗0表示第一次投D6出现1且第二次投的D4出现6,由于D4不可能出现6,所以其概率为0
我们掷三次骰⼦,看到结果为1,6,3。产⽣这个结果的总概率可以按照如下计算,总概率为0.03:
同样的,我们⼀步⼀步的算,有多⻓算多⻓,再⻓的⻢尔可夫链总能算出来的。
⽤同样的⽅法,也可以算出不正常的六⾯骰和另外两个正常骰⼦掷出这段序列的概率,然后我们⽐较⼀下这两个概率⼤⼩,就能知道你的骰⼦是不是被⼈换了。
⾸先我们来看看什么样的问题解决可以⽤HMM模型。使⽤HMM模型时我们的问题⼀般有这两个特征:
1)我们的问题是基于序列的,⽐如时间序列,或者状态序列。
2)我们的问题中有两类数据, ⼀类序列数据是可以观测到的,即观测序列; ⽽另⼀类数据是不能观察到的,即隐藏状态序列,简称状态序列。
有了这两个特征,那么这个问题⼀般可以⽤HMM模型来尝试解决。这样的问题在实际⽣活中是很多的。
⽐如我在键盘上敲出来的⼀系列字符就是观测序列,⽽我实际想写的⼀段话就是隐藏状态序列,输⼊法的任务就是从敲⼊的⼀系列字符尽可能的猜测我要写的⼀段话,并把最可能的词语放在最前⾯让我选择,这就可以看做⼀个HMM模型了。
再比如,我们和别人说话所发出的⼀串连续的声⾳就是观测序列,⽽实际要表达的⼀段话就是隐藏状态序列,⼤脑的任务,就是从这⼀串连续的声⾳中判断出最可能要表达的话的内容。
从这些例⼦中,我们可以发现,HMM模型可以⽆处不在。但是上⾯的描述还不精确,下⾯我们⽤精确的数学符号来表述我们的HMM模型。
对于HMM模型,⾸先我们假设Q是所有可能的隐藏状态的集合,V是所有可能的观测状态的集合,即:
其中,N是所有可能的隐藏状态数,M是所有可能的观察状态数。
对于⼀个⻓度为T的序列,i是对应的状态序列, O是对应的观察序列,即:
其中,任意⼀个隐藏状态 i t ∈ Q i_t \in Q it∈Q,任意⼀个观察状态 o t ∈ V o_t \in V ot∈V
HMM模型做了两个很重要的假设:
1)齐次马尔科夫链假设
即任意时刻的隐藏状态只依赖于它前⼀个隐藏状态。 当然这样假设有点极端,因为很多时候我们的某⼀个隐藏状态不仅仅只依赖于前⼀个隐藏状态,可能是前两个或者是前三个。 但是这样假设的好处就是模型简单,便于求解。
如果在时刻t的隐藏状态是 i t = q i i_t = q_i it=qi,在时刻t+1的隐藏状态是 i t + 1 = q j i_{t+1} = q_j it+1=qj, 则从时刻t到时刻t+1的HMM状态转移概率 a i j a_{ij} aij可以表示为: $a_{ij} = P(i_{t+1} = q_j|i_t = q_i ) $
这样 a i j a_{ij} aij可以组成⻢尔科夫链的状态转移矩阵 A = [ a i j ] N × N A=[a_{ij}]_{N \times N} A=[aij]N×N
2)观测独立性假设
即任意时刻的观察状态只仅仅依赖于当前时刻的隐藏状态,这也是⼀个为了简化模型的假设。
如果在时刻t的隐藏状态是 i t = q j i_t=q_j it=qj,⽽对应的观察状态为 o t = v k o_t=v_k ot=vk,则该时刻观察状态 v k v_k vk在隐藏状态 q j q_j qj下⽣成的概率为 b j ( k ) b_j(k) bj(k)满⾜: b j ( k ) = P ( o t = v k ∣ i t = q j ) b_j(k)=P(o_t=v_k|i_t=q_j) bj(k)=P(ot=vk∣it=qj)
这样 b j ( k ) b_j(k) bj(k)可以组成观测状态生成的概率矩阵B: B = [ b j ( k ) ] N × N B=[b_j(k)]_{N\times N} B=[bj(k)]N×N
除此之外,我们需要一组在时刻 t = 1 t=1 t=1的隐藏状态概率分布 Π = [ Π i ] N \Pi=[\Pi_i]_N Π=[Πi]N,其中 Π i = P ( i 1 = q i ) \Pi_i=P(i_1=q_i) Πi=P(i1=qi)
⼀个HMM模型,由隐藏状态初始概率分布 Π \Pi Π ,态转移概率矩阵A和观测状态概率矩阵B决定。
Π \Pi Π、A决定状态序列,B决定观测序列,因此HMM模型可以由一个三元组表示: λ = ( A , B , Π ) = ( 状 态 序 列 , 观 测 序 列 , 初 始 状 态 分 布 ) \lambda=(A,B,\Pi)=(状态序列,观测序列,初始状态分布) λ=(A,B,Π)=(状态序列,观测序列,初始状态分布)
下面用一个简单例子来描述上面的HMM模型。例子来源于李航《统计学习方法》。
假设我们有3个盒⼦,每个盒⼦⾥都有红⾊和⽩⾊两种球,这三个盒⼦⾥球的数量分别是:
开始的时候, 以下面的概率抽⼀次球后,将球放回。
从第⼀个盒⼦抽球的概率是0.2,
从第⼆个盒⼦抽球的概率是0.4,
从第三个盒⼦抽球的概率是0.4。
然后从当前盒⼦转移到下⼀个盒⼦进⾏抽球。规则是:
如果当前抽球的盒⼦是第⼀个盒⼦,则以0.5的概率仍然留在第⼀个盒⼦继续抽球,以0.2的概率去第⼆个盒⼦抽球,以0.3的概率去第三个盒⼦抽球。
如果当前抽球的盒⼦是第⼆个盒⼦,则以0.5的概率仍然留在第⼆个盒⼦继续抽球,以0.3的概率去第⼀个盒⼦抽球,以0.2的概率去第三个盒⼦抽球。
如果当前抽球的盒⼦是第三个盒⼦,则以0.5的概率仍然留在第三个盒⼦继续抽球,以0.2的概率去第⼀个盒⼦抽球,以0.3的概率去第⼆个盒⼦抽球。
如此下去,直到重复三次,得到⼀个球的颜⾊的观测序列: O = { 红 , 白 , 红 } O=\{红,白,红\} O={红,白,红}
注意在这个过程中,观察者只能看到球的颜⾊序列,却不能看到球是从哪个盒⼦⾥取出的。
那么按照我们前⾯HMM模型的定义,
观察状态集合是: V = { 红 , 白 } , M = 2 V=\{红,白\},M=2 V={红,白},M=2
隐藏状态集合是: Q = { 盒 子 1 , 盒 子 2 , 盒 子 3 } , N = 3 Q=\{盒子1,盒子2,盒子3\},N=3 Q={盒子1,盒子2,盒子3},N=3
初始状态分布是: Π = ( 0.2 , 0.4 , 0.4 ) T \Pi=(0.2,0.4,0.4)^T Π=(0.2,0.4,0.4)T,第一次是在盒子1抽的概率0.2,第一次在盒子2抽的概率0.4,第一次在盒子3抽的概率0.4。
状态转移概率矩阵A:由上面的转移抽球规则可得,第一行表示当前是在盒子1抽的,下次抽球0.5概率还是盒子1中抽,0.2概率是盒子2中抽,0.3概率是在盒子3中抽。第二行表示当前是在盒子2抽的,第三行表示当前是在盒子3抽的。
A = [ 0.5 0.2 0.3 0.3 0.5 0.2 0.2 0.3 0.5 ] A=\left[\begin{matrix} 0.5 & 0.2 & 0.3\\ 0.3 & 0.5 & 0.2\\ 0.2 & 0.3 & 0.5 \end{matrix}\right] A=⎣⎡0.50.30.20.20.50.30.30.20.5⎦⎤
观测状态概率矩阵B:由表可观测到,盒子1有5个白球5个红球,所以矩阵B第一行表示盒子1抽出红球的概率是0.5,抽出白球的概率是0.5。第二行是盒子2,第三行是盒子3。
B = [ 0.5 0.5 0.4 0.6 0.7 0.3 ] B=\left[\begin{matrix} 0.5 & 0.5\\ 0.4 & 0.6\\ 0.7 & 0.3 \end{matrix}\right] B=⎣⎡0.50.40.70.50.60.3⎦⎤
从上⾯的例⼦,我们也可以抽象出HMM观测序列⽣成的过程。
输⼊的是HMM的模型 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π),观测序列的⻓度T
输出是观测序列 O = o 1 , o 2 , . . . o T O=o_1,o_2,...o_T O=o1,o2,...oT
⽣成的过程如下:
1)根据初始状态概率分布 Π \Pi Π⽣成隐藏状态 i 1 i_1 i1
2)for t from 1 to T
a. 按照隐藏状态 i t i_t it的观测状态分布 b i t ( k ) b_{it}(k) bit(k)⽣成观察状态 o t o_t ot
b. 按照隐藏状态 i t i_t it的状态转移概率分布 a i t , i t + 1 a_{it},i_{t+1} ait,it+1产⽣隐藏状态 i t + 1 i_{t+1} it+1
所有的 o t o_t ot⼀起形成观测序列 O = o 1 , o 2 , . . . o T O=o_1,o_2,...o_T O=o1,o2,...oT
HMM模型⼀共有三个经典的问题需要解决:
1)评估观察序列概率 —— 前向后向的概率计算
2)预测问题,也称为解码问题 ——维特⽐(Viterbi)算法
即给定模型 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)和观测序列, O = o 1 , o 2 , . . . o T O={o_1,o_2,...o_T} O=o1,o2,...oT,求给定观测序列条件下,最可能出现的对应的状态序列。
这个问题的求解需要⽤到基于动态规划的维特⽐算法,是HMM模型三个问题中复杂度居中的算法。
3)模型参数学习问题 —— 鲍姆-⻙尔奇(Baum-Welch)算法
即给定观测序列 O = o 1 , o 2 , . . . o T O={o_1,o_2,...o_T} O=o1,o2,...oT,估计模型的 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)参数,使该模型下观测序列的条件概率最⼤ P ( O ∣ λ ) P(O|\lambda) P(O∣λ)。
这个问题的求解需要⽤到基于EM算法的鲍姆-⻙尔奇算法,是HMM模型三个问题中最复杂的。
接下来的三节,我们将基于这个三个问题展开讨论。
⾸先我们回顾下HMM模型的问题⼀。
我们已知HMM模型的参数 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π),同时我们也已经得到了观测序列 O = { o 1 , o 2 , . . . o T } O=\{o_1,o_2,...o_T\} O={o1,o2,...oT},
A是隐藏状态转移概率的矩阵,B是观测状态⽣成概率的矩阵, Π \Pi Π 是隐藏状态的初始概率分布。
现在我们要求观测序列 O O O在模型 λ \lambda λ下出现的条件概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)。
乍⼀看,这个问题很简单。因为我们知道所有的隐藏状态之间的转移概率和所有从隐藏状态到观测状态⽣成概率,那么我们是可以暴⼒求解的。 我们可以列举出所有可能出现的⻓度为T的隐藏序列 i = { i i , i 2 , . . . i T } i=\{i_i,i_2,...i_T\} i={ii,i2,...iT},分别求出这些隐藏序列与观测序列 O = { o 1 , o 2 , . . . , o T } O=\{o_1,o_2,...,o_T\} O={o1,o2,...,oT}的联合概率分布 P ( O , i ∣ λ ) P(O,i|\lambda) P(O,i∣λ),这样我们就可以很容易的求出边缘分布 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)了。
具体暴⼒求解的⽅法是这样的:
⾸先,任意隐藏序列 i = i 1 , i 2 , . . . , i T i=i_1,i_2,...,i_T i=i1,i2,...,iT出现的概率是: P ( i ∣ λ ) = Π i 1 a i 1 , a i 2 , . . . , a i T P(i|\lambda)=\Pi_{i_1}a_{i1},a_{i2},...,a_{iT} P(i∣λ)=Πi1ai1,ai2,...,aiT
对于固定的状态序列 i = i 1 , i 2 , . . . i T i=i_1,i_2,...i_T i=i1,i2,...iT,我们要求的观测序列 O = o 1 , o 2 , . . . o T O=o_1,o_2,...o_T O=o1,o2,...oT出现的概率是: P ( O ∣ i , λ ) = b i 1 ( o 1 ) b i 2 ( o 2 ) . . . b i T ( o T ) P(O|i,\lambda)=b_{i1}(o_1)b_{i2}(o_2)...b_{iT}(o_T) P(O∣i,λ)=bi1(o1)bi2(o2)...biT(oT)
则O和i联合出现的概率是: P ( O , I ∣ λ ) = P ( I ∣ λ ) P ( O ∣ I , λ ) = π i 1 b i 1 ( o 1 ) a i 1 i 2 b i 2 ( o 2 ) . . . a i T − 1 i T b i T ( O T ) P(O,I|\lambda)=P(I|\lambda)P(O|I,\lambda)=\pi_{i1}b_{i1}(o_1)a_{i1i2}b_{i2}(o_2)...a_{iT-1iT}b_{iT}(O_T) P(O,I∣λ)=P(I∣λ)P(O∣I,λ)=πi1bi1(o1)ai1i2bi2(o2)...aiT−1iTbiT(OT)
然后求边缘概率分布,即可得到观测序列O在模型 λ \lambda λ下出现的条件概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ):
虽然上述⽅法有效,但是如果我们的隐藏状态数N⾮常多的那就麻烦了,此时我们预测状态有N 种组合,算法的时间复杂度是 O ( T N T ) O(TN^T) O(TNT)阶的。
因此对于⼀些隐藏状态数极少的模型,我们可以⽤暴⼒求解法来得到观测序列出现的概率,但是如果隐藏状态多,则上述算法太耗时,我们需要寻找其他简洁的算法。
前向后向算法就是来帮助我们在较低的时间复杂度情况下求解这个问题的。
前向后向算法是前向算法和后向算法的统称,这两个算法都可以⽤来求HMM观测序列的概率。我们先来看看前向算法是如何求解这个问题的。
前向算法本质上属于动态规划的算法,也就是我们要通过找到局部状态递推的公式,这样⼀步步的从⼦问题的最优解拓展到整个问题的最优解。
在前向算法中,通过定义“前向概率”来定义动态规划的这个局部状态。
什么是前向概率呢, 其实定义很简单:定义时刻t时隐藏状态为q , 观测状态的序列为o , o , …o 的概率为前向概率。记为: α t ( i ) = P ( o 1 , o 2 , . . . o t , i t = q i ∣ λ ) \alpha_t(i)=P(o_1,o_2,...o_t,i_t=q_i|\lambda) αt(i)=P(o1,o2,...ot,it=qi∣λ)
既然是动态规划,我们就要递推了,现在假设我们已经找到了在时刻t各个隐藏状态的前向概率,我们需要递推出时刻t+1时各个隐藏状态的前向概率。
我们可以基于时刻t时各个隐藏状态的前向概率,再乘以对应的状态转移概率,即 α t ( j ) ⋅ a j i \alpha_t(j)\cdot a_{ji} αt(j)⋅aji,就是在时刻t观测到 o 1 , o 2 , . . . o t o_1,o_2,...o_t o1,o2,...ot,并且时刻t隐藏状态 q j q_j qj,时刻t+1隐藏状态 q i q_i qi的概率。
如果将下面的所有的线对于的概率求和,即 ∑ j = 1 N α t ( j ) a j i \sum\limits_{j=1}^N \alpha_t(j)a_{ji} j=1∑Nαt(j)aji就是在时刻t观测到 o 1 , o 2 , . . . o t o_1,o_2,...o_t o1,o2,...ot,并且时刻t+1隐藏状态 q i q_i qi的概率。
继续一部,由于观测状态 o t + 1 o_{t+1} ot+1只依赖于 t + 1 t+1 t+1时刻隐藏状态 q i q_i qi,这样 [ ∑ i = 1 N α t ( j ) a j i ] b i ( o t + 1 ) [\sum\limits_{i=1}^N \alpha_t(j)a_{ji}]b_i(o_{t+1}) [i=1∑Nαt(j)aji]bi(ot+1)就是在时刻t+1观测到 o 1 , o 2 , . . . , o t + 1 o_1,o_2,...,o_{t+1} o1,o2,...,ot+1,并且时刻t+1隐藏状态 q i q_i qi的概率
而这个概率,恰恰是时刻t+1对应的隐藏状态i的前向概率,这样我们得到了前向概率的递推关系式如下:
α t + 1 ( i ) = [ ∑ j = 1 N α t ( j ) a j i ] b i ( o t + 1 ) \alpha_{t+1}(i)=[\sum\limits_{j=1}^N \alpha_t(j)a_{ji}]b_i(o_{t+1}) αt+1(i)=[j=1∑Nαt(j)aji]bi(ot+1)
我们的动态规划从时刻1开始,到时刻T结束,由于 α T ( i ) \alpha_T(i) αT(i)表示在时刻T观测序列为 o 1 , o 2 , . . . o T o_1,o_2,...o_T o1,o2,...oT,并且时刻T隐藏状态 q i q_i qi的概率,我们只要将所有隐藏状态对应的概率相加,即 ∑ i = 1 N α T ( i ) \sum\limits_{i=1}^N \alpha_T(i ) i=1∑NαT(i),就得到了在时刻T观测序列为 o 1 , o 2 , . . . , o t o_1,o_2,...,o_t o1,o2,...,ot的概率。
算法总结
输入:HMM模型 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π),观测序列 O = ( o 1 , o 2 , . . . o T ) O=(o_1,o_2,...o_T) O=(o1,o2,...oT)
输出:观测序列概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)
1)计算时刻1的各个隐藏状态前向概率:
2)递推时刻2,3,… …T时刻的前向概率:
3)计算最终结果: P ( O ∣ λ ) = ∑ i = 1 N α T ( i ) P(O|\lambda)=\sum\limits_{i=1}^N \alpha_T(i) P(O∣λ)=i=1∑NαT(i)
从递推公式可以看出,算法的时间复杂度是 O ( T N 2 ) O(TN^2) O(TN2),比暴力解法的时间复杂度 O ( T N T ) O(TN^T) O(TNT)要少了几个数量级
为了便于理解,这里我们用前面盒子与球的例子来显示前向概率的计算。
观测集合: V = { 红 , 白 } , M = 2 V=\{红,白\},M=2 V={红,白},M=2
状态集合: Q = { 盒 子 1 , 盒 子 2 , 盒 子 3 } , N = 3 Q=\{盒子1,盒子2,盒子3\},N=3 Q={盒子1,盒子2,盒子3},N=3
球的颜色的观测序列: O = { 红 , 白 , 红 } O=\{红,白,红\} O={红,白,红}
初始状态分布: Π = ( 0.2 , 0.4 , 0.4 ) T \Pi=(0.2,0.4,0.4)^T Π=(0.2,0.4,0.4)T
状态转移概率分布矩阵:
A = [ 0.5 0.2 0.3 0.3 0.5 0.2 0.2 0.3 0.5 ] A=\left[\begin{matrix} 0.5 & 0.2 & 0.3\\ 0.3 & 0.5 & 0.2\\ 0.2 & 0.3 & 0.5 \end{matrix}\right] A=⎣⎡0.50.30.20.20.50.30.30.20.5⎦⎤
观测状态概率矩阵:
B = [ 0.5 0.5 0.4 0.6 0.7 0.3 ] B=\left[\begin{matrix} 0.5 & 0.5\\ 0.4 & 0.6\\ 0.7 & 0.3 \end{matrix}\right] B=⎣⎡0.50.40.70.50.60.3⎦⎤
现在我们可以开始递推了,⾸先递推时刻2三个状态的前向概率:
时刻2是白色球
继续递推,现在我们递推时刻3三个状态的前向概率:
时刻3是红⾊球
最终我们求出观测序列:O=红,⽩,红的概率为: P ( O ∣ λ ) = ∑ i = 1 N α 3 ( i ) = 0.13022 P(O|\lambda)=\sum\limits_{i=1}^N \alpha_3(i)=0.13022 P(O∣λ)=i=1∑Nα3(i)=0.13022
熟悉了⽤前向算法求HMM观测序列的概率,现在我们再来看看怎么⽤后向算法求HMM观测序列的概率。
后向算法和前向算法⾮常类似,都是⽤的动态规划,唯⼀的区别是选择的局部状态不同,后向算法⽤的是“后向概率”。
以下是后向算法的流程,注意下和前向算法的相同点和不同点:
输⼊:HMM模型 λ = P ( A , B , Π ) \lambda=P(A,B,\Pi) λ=P(A,B,Π),观测序列 O = ( o 1 , o 2 , . . . o T ) O=(o_1,o_2,...o_T) O=(o1,o2,...oT)
输出:观测序列概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)
1)初始化时刻T的各个隐藏状态后向概率: β T ( i ) = 1 , i = 1 , 2 , . . N \beta_T(i)=1,i=1,2,..N βT(i)=1,i=1,2,..N
3)计算最终结果: P ( O ∣ λ ) = ∑ i = 1 N π i b i ( o 1 ) β 1 ( i ) P(O|\lambda)=\sum\limits_{i=1}^N \pi_i b_i(o_1)\beta_1(i) P(O∣λ)=i=1∑Nπibi(o1)β1(i)
此时我们的算法时间复杂度仍然是 O ( T N 2 ) O(TN^2) O(TN2)
在本篇我们会讨论维特⽐算法解码隐藏状态序列,即给定模型和观测序列,求给定观测序列条件下,最可能出现的对应的隐藏状态序列。
HMM模型的解码问题最常⽤的算法是维特⽐算法,当然也有其他的算法可以求解这个问题。
同时,维特⽐算法是⼀个通⽤的求序列最短路径的动态规划算法,也可以⽤于很多其他问题。
HMM模型的解码问题即: 给定模型 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)和观测序列 O = o 1 , o 2 , . . . , o T O=o_1,o_2,...,o_T O=o1,o2,...,oT,求给定观测序列O条件下,最可能出现的对应的状态序列 I ∗ = i 1 ∗ , i 2 ∗ , . . . , i T ∗ I^*=i^*_1,i^*_2,...,i^*_T I∗=i1∗,i2∗,...,iT∗,即 P ( I ∗ ∣ O ) P(I^*|O) P(I∗∣O)的最⼤化。
⼀个可能的近似解法是求出观测序列O在每个时刻t最可能的隐藏状态 i t ∗ i^*_t it∗,然后得到⼀个近似的隐藏状态序列 I ∗ = i 1 ∗ , i 2 ∗ , . . . , i T ∗ I^*=i^*_1,i^*_2,...,i^*_T I∗=i1∗,i2∗,...,iT∗,要这样近似求解不难,利⽤前向后向算法评估观察序列概率的定义:
近似算法很简单,但是却不能保证预测的状态序列整体是最可能的状态序列,因为预测的状态序列中某些相邻的隐藏状态可能存在转移概率为0的情况。
⽽维特⽐算法可以将HMM的状态序列作为⼀个整体来考虑,避免近似算法的问题,下⾯我们来看看维特⽐算法进⾏HMM解码的⽅法。
维特⽐算法是⼀个通⽤的解码算法,是基于动态规划的求序列最短路径的⽅法。既然是动态规划算法,那么就需要找到合适的局部状态,以及局部状态的递推公式。在HMM中,维特⽐算法定义了两个局部状态⽤于递推。
1)第⼀个局部状态是**在时刻t隐藏状态为i所有可能的状态转移路径 i 1 , i 2 , . . . , i t i_1,i_2,...,i_t i1,i2,...,it中的概率最⼤值。**记为 δ t ( i ) \delta_t(i) δt(i)
由 δ t ( i ) \delta_t(i) δt(i)的定义可以得到 δ \delta δ的表达式:
2)第⼆个局部状态由第⼀个局部状态递推得到。
我们定义在时刻t隐藏状态为i的所有单个状态转移路径 ( i 1 , i 2 , . . . , i t − 1 , i ) (i_1,i_2,...,i_{t-1},i) (i1,i2,...,it−1,i)中概率最⼤的转移路径中第t-1个节点的隐藏状态为 ψ t ( i ) \psi_t(i) ψt(i)。其递推表达式为:
有了这两个局部状态,我们就可以从时刻0⼀直递推到时刻T,然后利⽤ ψ t ( i ) \psi_t(i) ψt(i)记录的前⼀个最可能的状态节点回溯,直到找到最优的隐藏状态序列。
维特比算法总结
流程如下:
1)初始化局部状态:
2) 进⾏动态规划递推时刻t = 2, 3, …T时刻的局部状态:
3)计算时刻T最⼤的 δ T ( i ) \delta_T(i) δT(i),即为最可能隐藏状态序列出现的概率。计算时刻T最⼤的 ψ t ( i ) \psi_t(i) ψt(i),即为时刻T最可能的隐藏状态。
4)) 利⽤局部状态 ψ t ( i ) \psi_t(i) ψt(i)开始回溯。对于t = T − 1, T − 2, …, 1:
最终得到最有可能的隐藏状态序列 I ∗ = i 1 ∗ , i 2 ∗ , . . . , i T ∗ I^*=i^*_1,i^*_2,...,i^*_T I∗=i1∗,i2∗,...,iT∗
下⾯我们仍然⽤盒⼦与球的例⼦来看看HMM维特⽐算法求解。
为了便于理解,这里我们用前面盒子与球的例子来显示前向概率的计算。
观测集合: V = { 红 , 白 } , M = 2 V=\{红,白\},M=2 V={红,白},M=2
状态集合: Q = { 盒 子 1 , 盒 子 2 , 盒 子 3 } , N = 3 Q=\{盒子1,盒子2,盒子3\},N=3 Q={盒子1,盒子2,盒子3},N=3
球的颜色的观测序列: O = { 红 , 白 , 红 } O=\{红,白,红\} O={红,白,红}
初始状态分布: Π = ( 0.2 , 0.4 , 0.4 ) T \Pi=(0.2,0.4,0.4)^T Π=(0.2,0.4,0.4)T
状态转移概率分布矩阵:
A = [ 0.5 0.2 0.3 0.3 0.5 0.2 0.2 0.3 0.5 ] A=\left[\begin{matrix} 0.5 & 0.2 & 0.3\\ 0.3 & 0.5 & 0.2\\ 0.2 & 0.3 & 0.5 \end{matrix}\right] A=⎣⎡0.50.30.20.20.50.30.30.20.5⎦⎤
观测状态概率矩阵:
B = [ 0.5 0.5 0.4 0.6 0.7 0.3 ] B=\left[\begin{matrix} 0.5 & 0.5\\ 0.4 & 0.6\\ 0.7 & 0.3 \end{matrix}\right] B=⎣⎡0.50.40.70.50.60.3⎦⎤
按照我们前⾯的维特⽐算法,⾸先需要得到三个隐藏状态在时刻1时对应的各⾃两个局部状态,此时观测状态为1:
现在开始递推三个隐藏状态在时刻2时对应的各⾃两个局部状态,此时观测状态为2:
继续递推三个隐藏状态在时刻3时对应的各⾃两个局部状态,此时观测状态为1:
此时已经到最后的时刻,我们开始准备回溯。此时最⼤概率为 δ 3 ( 3 ) \delta_3(3) δ3(3),从⽽得到 i 3 ∗ = 3 i^*_3=3 i3∗=3
由于 ψ 3 ( 3 ) \psi_3(3) ψ3(3),所以 i 2 ∗ = 3 i^*_2=3 i2∗=3,⽽⼜由于 ψ 2 ( 3 ) = 3 \psi_2(3)=3 ψ2(3)=3,所以 i 1 ∗ = 3 i^*_1=3 i1∗=3。从⽽得到最终的最可能的隐藏状态序列为:(3,3,3)。
模型参数学习问题 —— 鲍姆-⻙尔奇(Baum-Welch)算法(状态未知)
即给定观测序列 O = { o 1 , o 2 , . . . , o T } O=\{o_1,o_2,...,o_T\} O={o1,o2,...,oT},估计模型 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π)的参数,使该模型下观测序列的条件概率 P ( O ∣ λ ) P(O|\lambda) P(O∣λ)最⼤。
它的解法最常⽤的是鲍姆-⻙尔奇算法,其实就是基于EM算法的求解,只不过鲍姆-⻙尔奇算法出现的时代,EM算法还没有被抽象出来,所以被叫为鲍姆-⻙尔奇算法。
算法原理
鲍姆-⻙尔奇算法原理既然使⽤的就是EM算法的原理
那么我们需要在E步求出联合分布 P ( O , I ∣ λ ) P(O,I|\lambda) P(O,I∣λ)基于条件概率 P ( I ∣ O , λ ˉ ) P(I|O,\bar\lambda) P(I∣O,λˉ)的期望,其中 λ ˉ \bar\lambda λˉ为当前的模型参数,
然后在M步最⼤化这个期望,得到更新的模型参数 λ \lambda λ。
接着不停的进⾏EM迭代,直到模型参数的值收敛为⽌。
⾸先来看看E步,当前模型参数为λ, 联合分布 P ( O , I ∣ λ ) P(O,I|\lambda) P(O,I∣λ)基于条件概率的 P ( I ∣ O , λ ˉ ) P(I|O,\bar\lambda) P(I∣O,λˉ)期望表达式如下:
L ( λ , λ ˉ ) = ∑ I P ( I ∣ O , λ ˉ ) l o g P ( O , I ∣ λ ) L(\lambda,\bar\lambda)=\sum\limits_IP(I|O,\bar\lambda)logP(O,I|\lambda) L(λ,λˉ)=I∑P(I∣O,λˉ)logP(O,I∣λ)
在M步,我们极⼤化上式,然后得到更新后的模型参数如下:
λ ˉ = a r g m a x λ ∑ I P ( I ∣ O , λ ˉ ) l o g P ( O , I ∣ λ ) \bar\lambda=arg \ max_{\lambda} \sum\limits_{I} P(I|O, \bar\lambda)logP(O,I|\lambda) λˉ=arg maxλI∑P(I∣O,λˉ)logP(O,I∣λ)
通过不断的E步和M步的迭代,直到λ收敛。
官⽹链接:https://hmmlearn.readthedocs.io/en/latest/
这里我们是用的
hmmlearn
而不是sklearn
,需要我们先安装hmmlearn
,我是MacOS且用的Anaconda,这里就说明下我是如何安装的。Python3.6环境下,打开终端,输入命令
conda install -c omnia hmmlearn
如果下载失败可以考虑用梯子或者换镜像,参考知乎:https://www.zhihu.com/question/316914691/answer/628881977
hmmlearn实现了三种HMM模型类,按照观测状态是连续状态还是离散状态,可以分为两类。
GaussianHMM和GMMHMM是连续观测状态的HMM模型,⽽MultinomialHMM是离散观测状态的模型,也是我们在这个系列⾥⾯使⽤的模型。 (本文章都是基于离散观测状态说明的)
在这⾥主要介绍我们前⾯⼀直讲的关于离散状态的MultinomialHMM模型。
对于MultinomialHMM的模型,使⽤⽐较简单,⾥⾯有⼏个常⽤的参数:
"startprob_"参数对应我们的隐藏状态初始分布 Π \Pi Π,
"transmat_"对应我们的状态转移矩阵 A A A,
"emissionprob_"对应我们的观测状态概率矩阵 B B B。
下⾯我们⽤我们在前⾯讲的关于球的那个例⼦使⽤MultinomialHMM跑⼀遍。
import numpy as np
from hmmlearn import hmm
import math
# 设定隐藏状态的集合
states = ["盒子1", "盒子2", "盒子3"]
n_states = len(states)
# 设定观察状态的集合
observations = ["红色", "白色"]
n_observations = len(observations)
# 设定初始状态分布 Pi
start_probability = np.array([0.2, 0.4, 0.4])
# 设定状态转移概率分布矩阵 A
transition_probability = np.array([[0.5, 0.2, 0.3],
[0.3, 0.5, 0.2],
[0.2, 0.3, 0.5]])
# 设定观测状态概率矩阵 B
emission_probability = np.array([[0.5, 0.5],
[0.4, 0.6],
[0.7, 0.3]])
# 设定模型参数
model = hmm.MultinomialHMM(n_components=n_states)
model.startprob_=start_probability # 初始状态分布
model.transmat_=transition_probability # 状态转移概率分布矩阵
model.emissionprob_=emission_probability # 观测状态概率矩阵
# HMM问题三 —— 维比特算法的解码过程
# 设定观测序列
seen = np.array([0,1,0])
print("球的观测顺序为:", ",".join(map(lambda x: observations[x], seen)))
# 模型训练预测
box = model.predict(seen)
print("最可能的隐藏状态序列为:", ",".join(map(lambda x: states[x], box)))
# HMM问题一 —— 观测序列概率的问题
# 是score函数返回的是以⾃然对数为底的对数概率值,我们在HMM问题⼀中⼿动计算的结果是未取对数的原始概率0.13022
print("取对数的概率值:",model.score(seen))
print("未取对数的原始概率值:",math.exp(model.score(seen)))