1. 前言

隐马尔科夫HMM模型是一类重要的机器学习方法,其主要用于序列数据的分析,广泛应用于语音识别、文本翻译、序列预测、中文分词等多个领域。虽然近年来,由于RNN等深度学习方法的发展,HMM模型逐渐变得不怎么流行了,但并不意味着完全退出应用领域,甚至在一些轻量级的任务中仍有应用。本系列博客将详细剖析隐马尔科夫链HMM模型,同以往网络上绝大多数教程不同,本系列博客将更深入地分析HMM,不仅包括估计序列隐状态的维特比算法(HMM解码问题)、前向后向算法等,而且还着重的分析HMM的EM训练过程,并将所有的过程都通过数学公式进行推导。

由于隐马尔科夫HMM模型是一类非常复杂的模型,其中包含了大量概率统计的数学知识,因此网络上多数博客一般都采用举例等比较通俗的方式来介绍HMM,这么做会让初学者很快明白HMM的原理,但要丢失了大量细节,让初学者处于一种似懂非懂的状态。而本文并没有考虑用非常通俗的文字描述HMM,还是考虑通过详细的数学公式来一步步引导初学者掌握HMM的思想。另外,本文重点分析了HMM的EM训练过程,这是网络上其他教程所没有的,而个人认为相比于维特比算法、前向后向算法,HMM的EM训练过程虽然更为复杂,但是一旦掌握这个训练过程,那么对于通用的链状图结构的推导、EM算法和网络训练的理解都会非常大的帮助。另外通过总结HMM的数学原理,也能非常方便将数学公式改写成代码。

最后,本文提供了一个简单版本的隐马尔科夫链HMM的Python代码,包含了高斯模型的HMM和离散HMM两种情况,代码中包含了HMM的训练、预测、解码等全部过程,核心代码总共只有200~300行代码,非常简单!个人代码水平比较渣=_=||,大家按照我的教程,应该都可以写出更鲁棒性更有高效的代码,附上Github地址:https://github.com/tostq/Easy_HMM

觉得好,就点星哦!

觉得好,就点星哦!

觉得好,就点星哦!

重要的事要说三遍!!!!

为了方便大家学习,我将整个HMM代码完善成整个学习项目,其中包括

hmm.py:HMM核心代码,包含了一个HMM基类,一个高斯HMM模型及一个离散HMM模型

DiscreteHMM_test.py及GaussianHMM_test.py:利用unnitest来测试我们的HMM,同时引入了一个经典HMM库hmmlearn作为对照组

Dice_01.py:利用离散HMM模型来解决丢色子问题的例子

Wordseg_02.py:解决中文分词问题的例子

Stock_03.py:解决股票预测问题的例子

2. 隐马尔科夫链HMM的背景

首先,已知一组序列 :

我们从这组序列中推导出产生这组序列的函数,假设函数参数为 ,其表示为

即使得序列X发生概率最大的函数参数,要解决上式,最简单的考虑是将序列 的每个数据都视为独立的,比如建立一个神经网络。然后这种考虑会随着序列增长,而导致参数爆炸式增长。因此可以假设当前序列数据只与其前一数据值相关,即所谓的一阶马尔科夫链:

有一阶马尔科夫链,也会有二阶马尔科夫链(即当前数据值取决于其前两个数据值)

当前本文不对二阶马尔科夫链进行深入分析了,着重考虑一阶马尔科夫链,现在根据一阶马尔科夫链的假设,我们有:

因此要解一阶马尔科夫链,其关键在于求数据(以下称观测值)之间转换函数 ,如果假设转换函数

同序列中位置 (时间)无关,我们就能根据转换函数

而求出整个序列的概率:

然而,如果观测值x的状态非常多(特别极端的情况是连续数据),转换函数

会变成一个非常大的矩阵,如果x的状态有K个,那么转换函数

就会是一个K*(K-1)个参数,而且对于连续变量观测值更是困难。

为了降低马尔科夫链的转换函数的参数量,我们引入了一个包含较少状态的隐状态值,将观测值的马尔科夫链转换为隐状态的马尔科夫链(即为隐马尔科夫链HMM)

其包含了一个重要假设:当前观测值只由当前隐状态所决定。这么做的一个重要好处是,隐状态值的状态远小于观测值的状态,因此隐藏状态的转换函数

的参数更少。

此时我们要决定的问题是:

即在所有可能隐藏状态序列情况下,求使得序列 发生概率最大的函数参数 。

这里我们再总结下:

隐马尔科夫链HMM三个重要假设:

1. 当前观测值只由当前隐藏状态确定,而与其他隐藏状态或观测值无关(隐藏状态假设)

2. 当前隐藏状态由其前一个隐藏状态决定(一阶马尔科夫假设)

3. 隐藏状态之间的转换函数概率不随时间变化(转换函数稳定性假设)

隐马尔科夫链HMM所要解决的问题:

在所有可能隐藏状态序列情况下,求使得当前序列X产生概率最大的函数参数θ。

代码

http://blog.csdn.net/sinat_36005594/article/details/69568538

前几天用MATLAB实现了HMM的代码,这次用python写了一遍,依据仍然是李航博士的《统计学习方法》

由于第一次用python,所以代码可能会有许多缺陷,但是所有代码都用书中的例题进行了测试,结果正确。

这里想说一下python,在编写HMM过程中参看了之前写的MATLAB程序,发现他们有太多相似的地方,用到了numpy库,在python代码过程中最让我头疼的是数组角标,和MATLAB矩阵角标从1开始不同,numpy库数组角标都是从0开始,而且数组的维数也需要谨慎,一不小心就会出现too many indices for array的错误。程序中最后是维特比算法,在运行过程中出现了__main__:190: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future的警告,还没有去掉这个警告,查了一下说不影响结果,后面会去解决这个问题,下面贴出我的代码

#-*- coding: utf-8 -*-

"""Created on Thu Feb 16 19:28:39 2017

2017-4-2

ForwardBackwardAlg函数功能:实现前向算法

理论依据:李航《统计学习方法》

2017-4-5

修改了ForwardBackwardAlg函数名称为ForwardAlgo以及输出的alpha数组形式

完成了BackwardAlgo函数功能:后向算法

以及函数FBAlgoAppli:计算在观测序列和模型参数确定的情况下,

某一个隐含状态对应相应的观测状态的概率

2017-4-6

完成BaumWelchAlgo函数一次迭代

2017-4-7

实现维特比算法

@author: sgp"""

importnumpy as np#输入格式如下:#A = np.array([[.5,.2,.3],[.3,.5,.2],[.2,.3,.5]])#B = np.array([[.5,.5],[.4,.6],[.7,.3]])#Pi = np.array([[.2,.4,.4]])#O = np.array([[1,2,1]])

#应用ndarray在数组之间进行相互运算时,一定要确保数组维数相同!#比如:#In[93]:m = np.array([1,2,3,4])#In[94]:m#Out[94]: array([1, 2, 3, 4])#In[95]:m.shape#Out[95]: (4,)#这里表示的是一维数组#In[96]:m = np.array([[1,2,3,4]])#In[97]:m#Out[97]: array([[1, 2, 3, 4]])#In[98]:m.shape#Out[98]: (1, 4)#而这里表示的就是二维数组#注意In[93]和In[96]的区别,多一对中括号!!

#N = A.shape[0]为数组A的行数, H = O.shape[1]为数组O的列数#在下列各函数中,alpha数组和beta数组均为N*H二维数组,也就是横向坐标是时间,纵向是状态

defForwardAlgo(A,B,Pi,O):

N= A.shape[0]#数组A的行数

M = A.shape[1]#数组A的列数

H = O.shape[1]#数组O的列数

sum_alpha_1=np.zeros((M,N))

alpha=np.zeros((N,H))

r= np.zeros((1,N))

alpha_1= np.multiply(Pi[0,:], B[:,O[0,0]-1])

alpha[:,0]= np.array(alpha_1).reshape(1,N)#alpha_1是一维数组,在使用np.multiply的时候需要升级到二维数组。#错误是IndexError: too many indices for array

for h in range(1,H):for i inrange(N):for j inrange(M):

sum_alpha_1[i,j]= alpha[j,h-1] *A[j,i]

r= sum_alpha_1.sum(1).reshape(1,N)#同理,将数组升级为二维数组

alpha[i,h] = r[0,i] * B[i,O[0,h]-1]#print("alpha矩阵: \n %r" % alpha)

p = alpha.sum(0).reshape(1,H)

P= p[0,H-1]#print("观测概率: \n %r" % P)

#return alpha

returnalpha, PdefBackwardAlgo(A,B,Pi,O):

N= A.shape[0]#数组A的行数

M = A.shape[1]#数组A的列数

H = O.shape[1]#数组O的列数

#beta = np.zeros((N,H))

sum_beta = np.zeros((1,N))

beta=np.zeros((N,H))

beta[:,H-1] = 1p_beta= np.zeros((1,N))for h in range(H-1,0,-1):for i inrange(N):for j inrange(M):

sum_beta[0,j]= A[i,j] * B[j,O[0,h]-1] *beta[j,h]

beta[i,h-1] = sum_beta.sum(1)#print("beta矩阵: \n %r" % beta)

for i inrange(N):

p_beta[0,i]= Pi[0,i] * B[i,O[0,0]-1] *beta[i,0]

p= p_beta.sum(1).reshape(1,1)#print("观测概率: \n %r" % p[0,0])

returnbeta, p[0,0]defFBAlgoAppli(A,B,Pi,O,I):#计算在观测序列和模型参数确定的情况下,某一个隐含状态对应相应的观测状态的概率

#例题参考李航《统计学习方法》P189习题10.2

#输入格式:

#I为二维数组,存放所求概率P(it = qi,O|lambda)中it和qi的角标t和i,即P=[t,i]

alpha,p1 =ForwardAlgo(A,B,Pi,O)

beta,p2=BackwardAlgo(A,B,Pi,O)

p= alpha[I[0,1]-1,I[0,0]-1] * beta[I[0,1]-1,I[0,0]-1] /p1returnpdefGetGamma(A,B,Pi,O):

N= A.shape[0]#数组A的行数

H = O.shape[1]#数组O的列数

Gamma =np.zeros((N,H))

alpha,p1=ForwardAlgo(A,B,Pi,O)

beta,p2=BackwardAlgo(A,B,Pi,O)for h inrange(H):for i inrange(N):

Gamma[i,h]= alpha[i,h] * beta[i,h] /p1returnGammadefGetXi(A,B,Pi,O):

N= A.shape[0]#数组A的行数

M = A.shape[1]#数组A的列数

H = O.shape[1]#数组O的列数

Xi = np.zeros((H-1,N,M))

alpha,p1=ForwardAlgo(A,B,Pi,O)

beta,p2=BackwardAlgo(A,B,Pi,O)for h in range(H-1):for i inrange(N):for j inrange(M):

Xi[h,i,j]= alpha[i,h] * A[i,j] * B[j,O[0,h+1]-1] * beta[j,h+1] /p1#print("Xi矩阵: \n %r" % Xi)

returnXidefBaumWelchAlgo(A,B,Pi,O):

N= A.shape[0]#数组A的行数

M = A.shape[1]#数组A的列数

Y = B.shape[1]#数组B的列数

H = O.shape[1]#数组O的列数

c =0

Gamma=GetGamma(A,B,Pi,O)

Xi=GetXi(A,B,Pi,O)

Xi_1=Xi.sum(0)

a=np.zeros((N,M))

b=np.zeros((M,Y))

pi= np.zeros((1,N))

a_1= np.subtract(Gamma.sum(1),Gamma[:,H-1]).reshape(1,N)for i inrange(N):for j inrange(M):

a[i,j]= Xi_1[i,j] /a_1[0,i]#print(a)

for y inrange(Y):for j inrange(M):for h inrange(H):if O[0,h]-1 ==y:

c= c +Gamma[j,h]

gamma= Gamma.sum(1).reshape(1,N)

b[j,y]= c /gamma[0,j]

c=0#print(b)

for i inrange(N):

pi[0,i]=Gamma[i,0]#print(pi)

returna,b,pidef BaumWelchAlgo_n(A,B,Pi,O,n):#计算迭代次数为n的BaumWelch算法

for i inrange(n):

A,B,Pi=BaumWelchAlgo(A,B,Pi,O)returnA,B,Pidefviterbi(A,B,Pi,O):

N= A.shape[0]#数组A的行数

M = A.shape[1]#数组A的列数

H = O.shape[1]#数组O的列数

Delta =np.zeros((M,H))

Psi=np.zeros((M,H))

Delta_1= np.zeros((N,1))

I= np.zeros((1,H))for i inrange(N):

Delta[i,0]= Pi[0,i] * B[i,O[0,0]-1]for h in range(1,H):for j inrange(M):for i inrange(N):

Delta_1[i,0]= Delta[i,h-1] * A[i,j] * B[j,O[0,h]-1]

Delta[j,h]=np.amax(Delta_1)

Psi[j,h]= np.argmax(Delta_1)+1

print("Delta矩阵: \n %r" %Delta)print("Psi矩阵: \n %r" %Psi)

P_best= np.amax(Delta[:,H-1])

psi= np.argmax(Delta[:,H-1])

I[0,H-1] = psi + 1

for h in range(H-1,0,-1):

I[0,h-1] = Psi[I[0,h]-1,h]print("最优路径概率: \n %r" %P_best)print("最优路径: \n %r" % I)

python做马尔科夫模型预测法_Python实现HMM(隐马尔可夫模型)相关推荐

  1. python做马尔科夫模型预测法_python 日常笔记 hmmlearn 隐性马尔科夫模型案例分析...

    问题: 什么是马尔科夫模型?用来干什么? 大家可以参考这篇简书 python 实现 关于HMM有两个主要问题: 已知上述三个参数,和当前观测序列,求解隐藏状态的变化 所有参数未知,只有数据,如何获得三 ...

  2. python做马尔科夫模型预测法_python实现隐马尔科夫模型HMM

    #coding=utf8 ''''' Created on 2017-8-5 里面的代码许多地方可以精简,但为了百分百还原公式,就没有精简了. @author: adzhua ''' import n ...

  3. HMM隐马尔科夫模型(附维特比代码)

    背景知识:马尔科夫模型 1 马尔科夫的局限性 在一些情况下,我们并不能直接得到观测的结果,比如在天气系统中,我们不能直接得到天气的状态,但是我们有一堆蚂蚁,可以从蚂蚁的行为状态找到天气变化的关系规律. ...

  4. 机器学习之概率图模型(贝叶斯概率,隐马尔科夫模型)

    一.贝叶斯公式 在学习概率图模型之前先要了解贝叶斯公式: 由公式(1),(2)可得: 这便是贝叶斯公式,其中条件概率P(A/B)称为后验概率,概率P(A),P(B)称为先验概率,条件概率P(B/A), ...

  5. NLP基础 : HMM 隐马尔可夫模型

    Hidden Markov Model, HMM 隐马尔可夫模型,是一种描述隐性变量(状态)和显性变量(观测状态)之间关系的模型.该模型遵循两个假设,隐性状态i只取决于前一个隐性状态i-1,而与其他先 ...

  6. 李航《统计学习方法》之HMM隐马尔可夫模型

    李航<统计学习方法>之HMM隐马尔可夫模型 文章目录 前言 一.基本概念 1.语言描述: 2.符号表示 3.基本假设 4.例子 5.隐马尔可夫模型解决的三个基本问题 二.概率计算算法 1. ...

  7. HMM隐马尔科夫时间序列预测 Markov马尔科夫时间序列预测(Matlab)

    HMM隐马尔科夫时间序列预测 Markov马尔科夫时间序列预测(Matlab) 1.所有程序经过验证,保证可以运行 2.程序包括源码(主程序一个,子函数两个)和数据集: 3.程序适用于单变量时间序列预 ...

  8. hmm隐马尔可夫真的那么难吗?

    hmm隐马尔可夫真的那么难吗? 首先上代码 这里是github上的关于hmm的:链接 概率计算问题:前向-后向算法 学习问题:Baum-Welch算法(状态未知) 预测问题:Viterbi算法 htt ...

  9. 【机器学习基础】数学推导+纯Python实现机器学习算法24:HMM隐马尔可夫模型

    Python机器学习算法实现 Author:louwill Machine Learning Lab HMM(Hidden Markov Model)也就是隐马尔可夫模型,是一种由隐藏的马尔可夫链随机 ...

最新文章

  1. [转帖]Runtime, Engine, VM 的区别是什么?
  2. OpenCV cv :: UMat与DirectX9ex曲面的互操作性的实例(附完整代码)
  3. Linux下软件安装和卸载
  4. Python 实现网络爬虫小程序
  5. 谷歌Pixel 6系列手机发布会官宣定档 10月19日发布
  6. Open3d之表面重建
  7. 配置mac百度云同步盘
  8. 《SQL注入攻击与防御(第2版)》百度网盘链接
  9. QQ/Chrome浏览器一键去广告--去广告插件安装教程(广告终结者)
  10. 手机局域网关闭计算机的方法,用手机控制电脑关机 方法介绍【图文】
  11. Pytorch中Conv2d的使用
  12. t检验临界值表中的n是什么_t检验临界值分布表
  13. 【06月12日】指数估值排名
  14. Python|美国婴儿姓名分析
  15. linux关机卡屏,Ubuntu关机卡住无法关机的解决方法
  16. Hadoop安装与环境配置
  17. Bluetooth 蓝牙介绍(四):低功耗蓝牙BLE Mesh网络Ⅲ —— 广播 PDU
  18. android app英文 英文模式,英语场景主题会话与单词app
  19. 15 单因子利率模型蒙卡模拟
  20. 02 离散数学 课程安排

热门文章

  1. BackgroundWorker学习笔记
  2. EZGUI下的动态图片的处理
  3. ASP.NET中Session简单原理图
  4. mouseChildren= false
  5. 哨兵2号波段_Redis 哨兵使用以及在 Laravel 中的配置
  6. idea连接不了5.6mysql_IDEA无法连接mysql数据库的6种解决方法大全
  7. C语言指针实数组输入输出,C语言:回来两个数组中第一个元素的指针,并输出这个值...
  8. 在计算机网络应用发展过程中 被称为,计算机网络技术与应用第三章考试题
  9. cam350 不能打开光绘文件_CAM350使用教程-复制Gerber层
  10. redhat怎样修改语言_硕士博士个人陈述(PS)辅导及修改服务带你极速前进!