【算法学习】隐马尔可夫模型HMM(例题+代码)

隐马尔可夫模型HMM

介绍了模型的基本知识,和三个基本问题。其中对概率计算问题和预测(解码)问题进行了详细分析,并提供了python代码实现

公众号关注 52DATA ,获得更多数据分析知识,感谢支持—>

一、题目引入

假设有三个盒子,每个盒子里都装有红白两种颜色的球,盒子里的红白球数由下表1列出
在这里插入图片描述
根据上表1,可以知道每次球出自于哪个盒子的概率,如表2:
在这里插入图片描述
按照下面的方法抽球:开始,以(0.2,0.4,0.4)的概率随机选取 1 个盒子(假设已知,第一次在盒子1抽取球的概率为0.2,第一次在盒子2中抽取球的概率为0.4,第一次在盒子3中抽取球的概率为0.4),然后从这个盒子里随机抽出 1 个球,记录其颜色后,放回;然后,从当前盒子随机转移到下一个盒子(这个概率假设已知,如表3),继续抽球,放回…,但是这个过程不知道从哪个盒子里抽取的,只能看到球的颜色。

已知t时刻选择的盒子为a,下一刻选中盒子a,b,c的概率为:
在这里插入图片描述

假设抽三次,抽取的结果为红球、白球、 红球,则该过程的流程图如下图:
在这里插入图片描述
也就是我抽取完球之后,只能看到球的颜色,但我不知道球来自取哪里,于是上面的灰色叫为隐状态,下面叫为观测状态。上述过程就叫做隐马尔科夫模型(HMM)

二、隐马尔科夫的基本概念

1.隐状态集合Q和可观测状态集合V

Q是所有可能的状态的集合(隐状态集合)
Q={},N是可能的状态数
V是所有可能的观测的集合(可观测状态集合)
在这里插入图片描述,M是可能的观测数
注:集合里面的元素不能重复

2.状态序列I 和观测序列O

I 是长度为T 的状态序列,O 是对应的观测序列.
在这里插入图片描述

3.状态转移概率矩阵A

在这里插入图片描述

4.观测概率矩阵B

在这里插入图片描述

5.初始状态概率向量π

在这里插入图片描述

6.隐马尔科夫模型的三要素

隐马尔可夫模型由初始状态概率向量π、状态转移概率矩阵 A 和观测概率矩阵 B 决定.π和 A 决定状态序列,B 决定观测序列.因此,隐马尔可夫模型λ可以用三元符号表示,即λ=(A,B,π).A,B,π叫做隐马尔科夫模型的三要素。

7.隐马尔可夫模型的两个基本假设

(1)齐次马尔可夫性假设

即假设隐藏的马尔可夫链在任意时刻 t 的状态只依赖于其前一时刻的状态,与其他时刻的状态及观测无关,也与时刻 t 无关.
在这里插入图片描述
在这里插入图片描述

(2)观测独立性假设

即假设任意时刻的观测只依赖于该时刻的马尔可夫链的状态,与其他观测及状态无关.
在这里插入图片描述
在这里插入图片描述

三、将第一个问题用符号表示

隐藏状态集合Q={盒子1,盒子2,盒子3},N=3
观测状态集合V={红,白},M=2
在这里插入图片描述
假设总共摸了三次球,依次是红球,白球,红球,则
观测序列O={红,白,红}
但状态序列I 是不固定的,可能的取值有27种

1: 盒子1-->盒子1-->盒子1
2: 盒子1-->盒子1-->盒子2
3: 盒子1-->盒子1-->盒子3
......
25: 盒子3-->盒子3-->盒子1
26: 盒子3-->盒子3-->盒子2
27: 盒子3-->盒子3-->盒子3

四、隐马尔科夫的三个基本问题

在这里插入图片描述
在这里插入图片描述

(一)概率计算问题(例题+代码实现)

在这里插入图片描述

1.直接计算

在这里插入图片描述
公式看的太难了,以我们的例子来看,实际上就是穷举出所有情况出现的概率求和

盒子1 --> 盒子1 --> 盒子1    0.2*0.5*0.5*0.5*0.5*0.5 
盒子1 --> 盒子1 --> 盒子2    0.2*0.5*0.5*0.5*0.2*0.4 
盒子1 --> 盒子1 --> 盒子3    0.2*0.5*0.5*0.5*0.3*0.7 
盒子1 --> 盒子2 --> 盒子1    0.2*0.5*0.2*0.6*0.3*0.5 
盒子1 --> 盒子2 --> 盒子2    0.2*0.5*0.2*0.6*0.5*0.4 
盒子1 --> 盒子2 --> 盒子3    0.2*0.5*0.2*0.6*0.2*0.7 
盒子1 --> 盒子3 --> 盒子1    0.2*0.5*0.3*0.3*0.2*0.5 
盒子1 --> 盒子3 --> 盒子2    0.2*0.5*0.3*0.3*0.3*0.4 
盒子1 --> 盒子3 --> 盒子3    0.2*0.5*0.3*0.3*0.5*0.7 
盒子2 --> 盒子1 --> 盒子1    0.4*0.4*0.3*0.5*0.5*0.5 
盒子2 --> 盒子1 --> 盒子2    0.4*0.4*0.3*0.5*0.2*0.4 
盒子2 --> 盒子1 --> 盒子3    0.4*0.4*0.3*0.5*0.3*0.7 
盒子2 --> 盒子2 --> 盒子1    0.4*0.4*0.5*0.6*0.3*0.5 
盒子2 --> 盒子2 --> 盒子2    0.4*0.4*0.5*0.6*0.5*0.4 
盒子2 --> 盒子2 --> 盒子3    0.4*0.4*0.5*0.6*0.2*0.7 
盒子2 --> 盒子3 --> 盒子1    0.4*0.4*0.2*0.3*0.2*0.5 
盒子2 --> 盒子3 --> 盒子2    0.4*0.4*0.2*0.3*0.3*0.4 
盒子2 --> 盒子3 --> 盒子3    0.4*0.4*0.2*0.3*0.5*0.7 
盒子3 --> 盒子1 --> 盒子1    0.4*0.7*0.2*0.5*0.5*0.5 
盒子3 --> 盒子1 --> 盒子2    0.4*0.7*0.2*0.5*0.2*0.4 
盒子3 --> 盒子1 --> 盒子3    0.4*0.7*0.2*0.5*0.3*0.7 
盒子3 --> 盒子2 --> 盒子1    0.4*0.7*0.3*0.6*0.3*0.5 
盒子3 --> 盒子2 --> 盒子2    0.4*0.7*0.3*0.6*0.5*0.4 
盒子3 --> 盒子2 --> 盒子3    0.4*0.7*0.3*0.6*0.2*0.7 
盒子3 --> 盒子3 --> 盒子1    0.4*0.7*0.5*0.3*0.2*0.5 
盒子3 --> 盒子3 --> 盒子2    0.4*0.7*0.5*0.3*0.3*0.4 
盒子3 --> 盒子3 --> 盒子3    0.4*0.7*0.5*0.3*0.5*0.7

以上式子求和P(O|λ)=0.130218

画两个流程图就能明白了
盒子1 --> 盒子1 --> 盒子1 :
在这里插入图片描述
盒子2 --> 盒子1 --> 盒子3:
在这里插入图片描述
但是直接求解太麻烦了,需要穷举出所有的情况,所以一般采用前向算法或后向算法

Python代码实现–直接求法

A=np.array([[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]])
B=np.array([[0.5,0.5],[0.4,0.6],[0.7,0.3]])
pai=np.array([0.2,0.4,0.4])

sum=0
for i in range(len(Q)):
    for j in range(len(Q)):
        for k in range(len(Q)):
            sum=sum+pai[i]*B[i][0]*A[i][j]*B[j][1]*A[j][k]*B[k][0]
            #print(Q[i],"-->",Q[j],"-->",Q[k],("%s*%s*%s*%s*%s*%s ")%(pai[i],B[i][0],A[i][j],B[j][1],A[j][k],B[k][0]),pai[i]*B[i][0]*A[i][j]*B[j][1]*A[j][k]*B[k][0])
            print(Q[i],"-->",Q[j],"-->",Q[k],"  ",("%s*%s*%s*%s*%s*%s ")%(pai[i],B[i][0],A[i][j],B[j][1],A[j][k],B[k][0]))


print("P(O|λ)=",sum)

2.前向算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
python代码实现–前向算法

Q=["box1","box2","box3"]#状态集合
V=["红","白"] #观测集合
#O=["红","白","红"]  #观测序列
O=[0,1,0] #转为数字类型,0代表红,1代表白
A=np.array([[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]])
B=np.array([[0.5,0.5],[0.4,0.6],[0.7,0.3]])
pai=np.array([0.2,0.4,0.4])

#前向算法
for i in range(len(O)):
    if i==0:
        pai=pai*B.T[O[i]]  #初始状态概率
    else:
        pai=pai.dot(A)*B.T[O[i]]   #之后的状态概率迭代
print(pai.sum())

3.后向算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
python代码实现–后向算法

Q=["box1","box2","box3"]#状态集合
V=["红","白"] #观测集合
#O=["红","白","红"]  #观测序列
O=[0,1,0] #转为数字类型
A=np.array([[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]])
B=np.array([[0.5,0.5],[0.4,0.6],[0.7,0.3]])
pai=np.array([0.2,0.4,0.4])

#后向算法
for i in range(len(O),0):
    if i==len(O):
        pai1=np.array([1,1,1])  #t=3时刻
    else:
        pai1=A.dot(B.T[O[i]]*pai1)##之前的状态概率迭代
print((pai1*pai*B.T[0]).sum())#终止

(二)模型参数学习

学习问题
在这里插入图片描述
没有找到具体例子,若用到,再更新…

(三)预测(解码)问题(例题+代码实现)

在这里插入图片描述

1.穷举

找出所有可能出现的情况,选择概率最大的一组

直接附代码

Q=["box1","box2","box3"]#状态集合
V=["红","白"] #观测集合
#O=["红","白","红"]  #观测序列
O=[0,1,0] #转为数字类型
A=np.array([[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]])
B=np.array([[0.5,0.5],[0.4,0.6],[0.7,0.3]])
pai=np.array([0.2,0.4,0.4])

#暴力破解 穷举
sum=0
pathlist=[]#存路径
plist=[]#存概率
for i in range(len(Q)):
    for j in range(len(Q)):
        for k in range(len(Q)):
            pathlist.append((i,j,k))
            plist.append(pai[i]*B[i][0]*A[i][j]*B[j][1]*A[j][k]*B[k][0])
            print((i,j,k),("%s*%s*%s*%s*%s*%s =")%(pai[i],B[i][0],A[i][j],B[j][1],A[j][k],B[k][0]),pai[i]*B[i][0]*A[i][j]*B[j][1]*A[j][k]*B[k][0])
#看概率最大的路径 则是最优

maxp=max(plist) #计算列表最大值                
xb=plist.index(maxp)#取出最大值所对应的下标
print("最优路径为:",pathlist[xb])#输出最优解pathlist[xb]
print("最优路径对应概率为:",plist[xb])#输出最大概率p[xb]

输出
在这里插入图片描述

2.维特比viterbi算法

维特比算法实际是用动态规划解隐马尔可夫模型预测问题,即用动态规划(dynamic programming)求概率最大路径(最优路径).这时一条路径对应着一个状态序列.
定义两个变量:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Python代码实现

Q=["box1","box2","box3"]#状态集合

V=["红","白"] #观测集合

#O=["红","白","红"]  #观测序列
O=[0,1,0] #转为数字类型


A=np.array([[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]])
B=np.array([[0.5,0.5],[0.4,0.6],[0.7,0.3]])
pai=np.array([0.2,0.4,0.4])

#维特比viterbi算法

maxxb=[] #存φ,b-->δ
for i in range(len(O)):
    if i==0:
        b=pai*B.T[0]#t=1时刻概率
    else:
        maxxb.append(np.argmax(b*A.T,axis=1)) #返回最大值下标,axis=1每行最大,axis=0每列最大
        b=np.max(b*A.T,axis=1)*B.T[O[i]]   #迭代取最大值

#print(list(maxxb))        
path=[]#最优路径

it=np.argmax(b,axis=0)#最优路径的“终点”
path.append(it)
for i in range(len(maxxb)):#最优路径回溯
    it=maxxb[len(maxxb)-i-1][it]
    path.append(it)

path.reverse()#把顺序调整一下,因为存的时候是倒着存储的   
print(path)
输出
[2, 2, 2]

![在这里插入图片描述](https://img-blog.csdnimg.cn/ec5ba9a65200419a84ccc1dfc1c78f04.png

公众号关注 52DATA ,获得更多数据分析知识,感谢支持—>

  • 15
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
HMM是一种常见的统计模型,用于描述随机生成的序列。Viterbi算法是一种在HMM中进行解码的动态规划算法,用于寻找最可能的隐藏状态序列。下面是HMM的MATLAB实现,包括Viterbi算法。 首先,我们需要定义一个HMM模型。我们假设这个模型有3个隐藏状态和2个可见状态。我们使用矩阵A表示隐藏状态之间的转移概率,矩阵B表示每个隐藏状态生成每个可见状态的概率,向量pi表示初始隐藏状态的概率分布。 ```matlab % 定义HMM模型参数 A = [0.5 0.2 0.3; 0.3 0.5 0.2; 0.2 0.3 0.5]; B = [0.5 0.5; 0.4 0.6; 0.7 0.3]; pi = [0.2 0.4 0.4]; ``` 接下来,我们需要生成一个可见序列。我们使用HMM模型中的随机过程生成一个长度为10的可见序列。 ```matlab % 生成可见序列 T = 10; q = zeros(1, T); o = zeros(1, T); q(1) = randsrc(1, 1, [1:3; pi]); o(1) = randsrc(1, 1, [1:2; B(q(1), :)]); for t = 2:T q(t) = randsrc(1, 1, [1:3; A(q(t-1), :)]); o(t) = randsrc(1, 1, [1:2; B(q(t), :)]); end ``` 接下来,我们使用Viterbi算法解码这个可见序列,得到最可能的隐藏状态序列。我们定义一个矩阵V表示每个时间步的最大概率,以及一个矩阵path表示每个时间步的最大概率对应的前一个状态。 ```matlab % Viterbi算法解码 V = zeros(3, T); path = zeros(3, T); V(:, 1) = pi' .* B(:, o(1)); for t = 2:T for j = 1:3 [V(j, t), path(j, t)] = max(V(:, t-1) .* A(:, j)); V(j, t) = V(j, t) * B(j, o(t)); end end ``` 最后,我们找到最可能的隐藏状态序列。我们首先找到最后一个时间步的最大概率对应的隐藏状态,然后从后往前依次寻找每个时间步的最大概率对应的隐藏状态,最终得到整个隐藏状态序列。 ```matlab % 找到最可能的隐藏状态序列 [~, q(T)] = max(V(:, T)); for t = T-1:-1:1 q(t) = path(q(t+1), t+1); end ``` 完整代码如下: ```matlab % 定义HMM模型参数 A = [0.5 0.2 0.3; 0.3 0.5 0.2; 0.2 0.3 0.5]; B = [0.5 0.5; 0.4 0.6; 0.7 0.3]; pi = [0.2 0.4 0.4]; % 生成可见序列 T = 10; q = zeros(1, T); o = zeros(1, T); q(1) = randsrc(1, 1, [1:3; pi]); o(1) = randsrc(1, 1, [1:2; B(q(1), :)]); for t = 2:T q(t) = randsrc(1, 1, [1:3; A(q(t-1), :)]); o(t) = randsrc(1, 1, [1:2; B(q(t), :)]); end % Viterbi算法解码 V = zeros(3, T); path = zeros(3, T); V(:, 1) = pi' .* B(:, o(1)); for t = 2:T for j = 1:3 [V(j, t), path(j, t)] = max(V(:, t-1) .* A(:, j)); V(j, t) = V(j, t) * B(j, o(t)); end end % 找到最可能的隐藏状态序列 [~, q(T)] = max(V(:, T)); for t = T-1:-1:1 q(t) = path(q(t+1), t+1); end ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yanyanxiaobaobei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值