学习了李航的《统计学习方法》中隐马尔可夫模型(Hidden Markov Model, HMM),这里把自己对HMM的理解进行总结(大部分是书本原文,O(∩_∩)O哈哈~,主要是想利用python将其实现一遍,这样印象深刻一点儿),并利用python将书本上的例子运行一遍。HMM是可用于标注问题的统计学习模型,描述由隐藏的马尔科夫链随机生成观测序列的过程,属于生成模型。HMM在语音识别、自然语言处理、生物信息、模式识别等领域都有着广泛的应用。

一、隐马尔可夫模型的定义

HMM由初始概率分布、状态转移概率分布A以及观测概率分布B三部分确定。HMM模型可以用三元符号表示,即:。A、B、称为HMM的三要素。

设Q是所有可能的状态的集合,V是所有可能的观测的集合。其中,N是可能的状态数,M是可能的观测数。这里观测状态v是可见的,状态q是不可见的。记I是长度为T的状态序列,O是对应的观测序列,。

  1、则可定义状态转移概率矩阵B如下:

其中是在时刻t处于状态 qi 的条件下在时刻t+1转移到状态 qj 的概率。

  2、观测概率矩阵B定义如下:

其中是在时刻t处于状态 qj 的条件下生成观测 vk 的概率。

  3、初始状态概率向量如下:

其中是时刻t=1处于状态qj的概率。

二、HMM的两个假设

  1、齐次马尔科夫性假设。即隐藏的马尔科夫链在任意时刻 t 的状态只与前一时刻的状态有关,与时刻 t 也无关。

。

  2、观测独立性假设。即任意时刻的观测只和该时刻的马尔科夫链的状态有关,与其他观测即状态无关。

。

例题:例子采用书本上的盒子和球模型。

  分析:这里一共四个盒子,则表示所有可能的状态有四种Q={盒子1,盒子2,盒子3,盒子4},N=4。球的颜色只有红白两种,即所有可能的观测为V={红,白},M=2。

  用python中的列表分别表示可能的状态集合Q和观测集合V,用字典存储初始概率分布、状态转移概率分布和观测概率分布。

# 所有可能的状态集合
states = ['盒子1', '盒子2', '盒子3', '盒子4']
# 所有可能的观测集合
observations = ['红球', '白球'] # 初始状态概率分布pi
Pi = {'盒子1':0.25, '盒子2':0.25, '盒子3':0.25, '盒子4':0.25}
# 状态转移概率A
A = {'盒子1':{'盒子1':0, '盒子2':1, '盒子3':0, '盒子4':0},
'盒子2':{'盒子1':0.4, '盒子2':0, '盒子3':0.6, '盒子4':0},
'盒子3':{'盒子1':0, '盒子2':0.4, '盒子3':0, '盒子4':0.6},
'盒子4':{'盒子1':0, '盒子2':0, '盒子3':0.5, '盒子4':0.5}
}
# 观测概率分布B
B = {'盒子1':{'红球':0.5, '白球':0.5},
'盒子2':{'红球':0.3, '白球':0.7},
'盒子3':{'红球':0.6, '白球':0.4},
'盒子4':{'红球':0.8, '白球':0.2}
}

  为了后面方便处理,这里引入python的numpy库将Pi、A和B转换为矩阵和向量形式。

import numpy as np
# 将初始状态概率转换成向量形式
Pi = np.array([Pi[x] for x in Pi])
print('初始状态pi:', Pi) # 将初始概率分布转换为矩阵形式
trans_A = np.array([A[x][y] for x in A for y in A[x]]) A = trans_A.reshape((len(A), -1))
print('状态转移概率分步A:', A) # 将观测概率分布转换成矩阵形式
trans_B = np.array([B[x][y] for x in B for y in B[x]])
B = trans_B.reshape((len(B), -1))
print('观测概率分布B:', B)

观测序列的生成过程

  根据隐马尔可夫模型定义,可以将一个长度为T的观测序列的生成过程描述如下:

  算法(观测序列的生成)

  输入:隐马尔可夫模型,观测序列长度

  输出:观测序列。

  (1)按照初始状态分布产生状态

  (2)令t=1

  (3)按照状态的观测概率分布生成

  (4)按照状态的状态转移概率分布产生状态

  令;如果则转步(3);否则,终止。

  分析:对于按照某个概率分布生成状态,这里采用python中的np.random.multinomial函数按照多项式分布,生成数据,然后再利用np.where得到满足条件的元素对应的下标。定义观测序列生成函数generation_observation。

# 定义生成观测序列的函数
def generation_observation(pi, A, B, T):
def random_res(probs):
"""
1.np.random.multinomial:
按照多项式分布,生成数据
>>> np.random.multinomial(20, [1/6.]*6, size=2)
array([[3, 4, 3, 3, 4, 3],
[2, 4, 3, 4, 0, 7]])
For the first run, we threw 3 times 1, 4 times 2, etc.
For the second, we threw 2 times 1, 4 times 2, etc.
2.np.where:
>>> x = np.arange(9.).reshape(3, 3)
>>> np.where( x > 5 )
(array([2, 2, 2]), array([0, 1, 2]))
"""
return np.where(np.random.multinomial(1,probs) == 1)[0][0] observation_data = np.zeros(T, dtype=int) # 初始化生成的观测序列
observation_states = np.zeros(T, dtype=int) # 观测序列对应的状态
observation_states[0] = random_res(pi) # 根据初始状态分布产生状态1
observation_data[0] = random_res(B[observation_states[0]]) # 由状态1生成对应的观测值
for i in range(1, T):
observation_states[i] = random_res(A[observation_states[i-1]]) # 由前一个状态转变到下一个状态
observation_data[i] = random_res(B[observation_states[i]])
return observation_data, observation_states observation_data, observation_states = generation_observation(Pi, A, B, 10)
print(observation_data, observation_states) print('观测序列:', [observations[i] for i in observation_data])
print('状态序列:', [states[i] for i in observation_states])

三、隐马尔可夫模型的3个基本问題

   1、概率计算问题。给定模型和观测序列,计算在模型下观测序列O出现的概率。

  2、学习问题。己知观测序列,估计模型参数,使得在该模型下观测序列概率最大。即用极大似然估计的方法估计参数。

  3、预测问题,也称为解码(decoding)问题。已知模型和观测序列,求对给定观测序列条件概率最大的状态序列。即给定观测序列,求最有可能的对应的状态序列。

  问题1 概率计算问题

  如果直接采用直接计算法的话,需要列举所有长度为T的状态序列 I,然后求出 I 与观测序列O的联合概率,最后再对所有可能的状态序列求和,得到序列O在HMM模型下生成的概率。这样时间复杂度是O(TNT)阶的,这种算法观测序列长度很长的话计算量太大,所以采用前向、后向算法计算概率。

  (1)前向算法

  首先定义(前向概率)给定隐马尔可夫模型,定义到时刻t为止的观测序列为且状态为的概率为前向概率,记作

  输入:隐马尔可夫模型,观测序列;

  输出:观测序列概率。

  (1)初值

  (2)递推对

  (3)终止

  由于到了时间T,一共有N种状态发转移到最后那个观测,所以最终的结果要将这些概率加起来。而每次递推都是在前一次的基础上做的,所以只需累加O(T)次,所以总体复杂度是O(N2T)。

  分析:前向概率矩阵alpha是N*T维的,可以先用零初始化,之后再按照前向算法一步一步对其值进行替换。定义前向算法方法forward_compute。再利用例题10.2对其进行验证。

def forward_compute(pi, A, B, o_seq):
T = len(o_seq)
N = A.shape[0]
alpha = np.zeros((N, T)) # 初始化alpha矩阵 N*T维
# print(alpha)
# print(B[:, o_seq[0]])
alpha[:, 0] = pi*B[:, o_seq[0]] # step1 初值
for t in range(1, T):
alpha[:, t] = alpha[:, t-1].dot(A) * B[:, o_seq[t]] # step2 递推
# print(alpha)
return np.sum(alpha[:, T-1]), alpha # step3 终止 对时刻T的alpha求和
# 测试 例题10.2
A = np.array([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]])
Pi = np.array([0.2, 0.4, 0.4])
B = np.array([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]])
o_seq = [0, 1, 0] # 红、白、红 prob, alpha = forward_compute(Pi, A, B, o_seq)
print('观测概率为:', prob)
print('alpha:', alpha)

  (2)后向算法

  定义后向概率为给定隐马尔可夫模型,定义在时刻t状态为的条件下,从t+1到T的部分观测序列为的概率为后向概率,记作

可以用递推的方法求得后向概率及观测序列概率。

  算法(观测序列概率的后向算法)

  输入:隐马尔可夫模型,观测序列:

  输出:观测序列概率

  (1)初值

根据定义,从T+1到T的部分观测序列其实不存在,所以硬性规定这个值是1。

  (2)递推。对

aij表示状态i转移到j的概率,bj表示发射Ot+1,表示j后面的序列对应的后向概率。

  (3)终止

最后的求和是因为,在第一个时间点上有N种后向概率都能输出从2到T的观测序列,所以乘上输出O1的概率后求和得到最终结果。

  分析:前向概率矩阵beta也是N*T维的,可以先用零初始化,之后再按照前向算法一步一步对其值进行替换。定义前向算法方法backward_compute。再利用例题10.2对其进行验证。

def backword_compute(pi, A, B, o_seq):
T = len(o_seq)
beta = np.zeros((A.shape[0], T)) # 初始化beta矩阵 beta[:, T-1] = np.ones(A.shape[0]) # step1 初值
for t in range(T-2, -1, -1):
beta[:, t] = np.sum(A*B[:, o_seq[t+1]]*beta[:, t+1], axis=1) # step2 递推 res_prop = np.sum(pi*B[:, o_seq[0]]*beta[:,0], axis=0) # 求观测序列概率
  # print(beta)
return res_prop, beta
# 测试 例题10.2
A = np.array([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]])
Pi = np.array([0.2, 0.4, 0.4])
B = np.array([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]])
o_seq = [0, 1, 0] # 红、白、红
prob, beta = backword_compute(Pi, A, B, o_seq)
print('观测概率:', prob)
print('beta:', beta)

隐马尔可夫模型(HMM)学习笔记一的更多相关文章

  1. 隐马尔科夫模型HMM学习最佳范例

    谷歌路过这个专门介绍HMM及其相关算法的主页:http://rrurl.cn/vAgKhh 里面图文并茂动感十足,写得通俗易懂,可以说是介绍HMM很好的范例了.一个名为52nlp的博主(google ...

  2. 用hmmlearn学习隐马尔科夫模型HMM

    在之前的HMM系列中,我们对隐马尔科夫模型HMM的原理以及三个问题的求解方法做了总结.本文我们就从实践的角度用Python的hmmlearn库来学习HMM的使用.关于hmmlearn的更多资料在官方文 ...

  3. 基于隐马尔科夫模型(HMM)的地图匹配(Map-Matching)算法

    文章目录 1. 1. 摘要 2. 2. Map-Matching(MM)问题 3. 3. 隐马尔科夫模型(HMM) 3.1. 3.1. HMM简述 3.2. 3.2. 基于HMM的Map-Matchi ...

  4. 隐马尔科夫模型(HMM)的概念

    定义隐马尔科夫模型可以用一个三元组(π,A,B)来定义:π 表示初始状态概率的向量A =(aij)(隐藏状态的)转移矩阵 P(Xit|Xj(t-1)) t-1时刻是j而t时刻是i的概率B =(bij) ...

  5. 隐马尔科夫模型HMM(一)HMM模型

    隐马尔科夫模型HMM(一)HMM模型基础 隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率 隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数(TODO) 隐马尔科夫模型HMM(四)维特比 ...

  6. HMM:隐马尔可夫模型HMM

    http://blog.csdn.net/pipisorry/article/details/50722178 隐马尔可夫模型 隐马尔可夫模型(Hidden Markov Model,HMM)是统计模 ...

  7. 隐马尔可夫模型HMM与维特比Veterbi算法(二)

    隐马尔可夫模型HMM与维特比Veterbi算法(二) 主要内容: 前向算法(Forward Algorithm) 穷举搜索( Exhaustive search for solution) 使用递归降 ...

  8. 隐马尔可夫模型HMM与维特比Veterbi算法(一)

    隐马尔可夫模型HMM与维特比Veterbi算法(一) 主要内容: 1.一个简单的例子 2.生成模式(Generating Patterns) 3.隐藏模式(Hidden Patterns) 4.隐马尔 ...

  9. 隐马尔可夫模型HMM

    隐马尔可夫模型HMM的探究 1 HMM基本概念1.1 定义1.2 观测序列生成过程1.3 HMM的三个问题2 概率计算算法2.1 直接计算算法2.2 前向算法forward algorithm2.3 ...

  10. 隐马尔科夫模型HMM

    崔晓源 翻译 我们通常都习惯寻找一个事物在一段时间里的变化规律.在很多领域我们都希望找到这个规律,比如计算机中的指令顺序,句子中的词顺序和语音中的词顺序等等.一个最适用的例子就是天气的预测. 首先,本 ...

随机推荐

  1. WEB前端开发规范文档[转]

    为新项目写的一份规范文档, 分享给大家. 我想前端开发过程中, 无论是团队开发, 还是单兵做站, 有一份开发文档做规范, 对开发工作都是很有益的. 本文档由本人编写, 部分意见来源于网络, 以此感谢, ...

  2. PAT甲1005 Spell it right【字符串】

    1005 Spell It Right (20 分) Given a non-negative integer N, your task is to compute the sum of all th ...

  3. poj2528 Mayor's posters【线段树】

    The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign h ...

  4. ResourceManager High Availability

    Introduction This guide provides an overview of High Availability of YARN’s ResourceManager, and det ...

  5. cordova-ios 升级到4.4.0 无法真机跑iOS8 报错: dyld`dyld_fatal_error: -> 0x120085088 <+0>: brk #0x3

    项目进入测试阶段,马上要上线了,同事拿了自己的iOS8系统5s跑真机,无缘无故报错,之前跑她的手机完全没有问题的.Xcode 8.x中最低部署版本是iOS8.0,按理说完全能够跑真机的. 但是报了一个 ...

  6. the internal array pointer

    The foreach construct provides an easy way to iterate over arrays. foreach works only on arrays and ...

  7. Linux下的反调试技术

    Linux下的反调试技术 2014年01月30日 ⁄ 综合 ⁄ 共 2669字 ⁄ 字号 小 中 大 ⁄ 评论关闭 转自  http://wangcong.org/blog/archives/310 ...

  8. flask数据库操作

    Python 数据库框架 大多数的数据库引擎都有对应的 Python 包,包括开源包和商业包.Flask 并不限制你使用何种类型的数据库包,因此可以根据自己的喜好选择使用 MySQL.Postgres ...

  9. contenttypes - django组件

    一.contenttypes介绍 它的作用:可以通过两个字段让表和N张表创建FK关系 二.ContentType.GenericForeignKey.GenericRelation 表结构: from ...

  10. 在Java中谈尾递归--尾递归和垃圾回收的比较

    我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...