隐形马尔可夫链代码——python源代码,看完你就完全懂了

隐形马尔可夫链代码

隐形马尔可夫链在李航的统计学习方法里面已经介绍的很详细了(李航统计学习方法P193-P196),我这里就不献丑了,这篇文章主要是分享隐形马尔可夫链的代码。

隐形马尔可夫有三个问题:
1、概率计算问题:
给定模型 λ = ( 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),计算在模型 λ \lambda λ下观测序列 O O O出现的概率 P ( O ∣ λ ) P(O|\lambda) P(Oλ)

2、学习问题:
已知观测序列 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λ)最大,即用最大似然估计的方法估计参数。

3、预测问题
也成为解码。已知模型 λ = ( 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λ)最大的状态序列 I = ( i 1 , i 2 , . . . i T ) I=(i_1,i_2,...i_T) I=(i1,i2,...iT)

一、概率计算问题
该问题的计算方法有前向算法和后向算法,详情可见统计学习方法P198-P203。模型和代码一起看更容易消化呢。

class HMM1:
    def __init__(self):
        self.A=[[0,1,0,0],[0.4,0,0.6,0],[0,0.4,0,0.6],[0,0,0.5,0.5]]       ##转移概率
        self.B=[[0.5,0.5],[0.3,0.7],[0.6,0.4],[0.8,0.2]]                   ##观测概率
        self.W=[0.25,0.25,0.25,0.25]
        ##初始状态
    def cal_q(self,Q):
        """
        前向算法
        :param Q: 观测数据 1,0,1,0,1,0
        :return:
        """
        a=[[0 for i in range(len(self.B))] for j in range(len(Q))]
        for i in range(len(self.B)):
            a[0][i]=self.W[i]*self.B[i][Q[0]]
        for t in range(1,len(Q)):
            for i in range(len(self.B)):
                a[t][i]=0
                for j in range(len(self.B)):
                    a[t][i]+=a[t-1][j]*self.A[j][i]*self.B[i][Q[t]]
        return sum(a[-1])
    def cal_q2(self,Q):
        """
        后向算法
        :param Q: 观测数据 1,0,1,0,1,0
        :return:
        """
        b = [[0 for i in range(len(self.B))] for j in range(len(Q))]
        for i in range(len(self.B)):
            b[-1][i]=1
        for t in range(len(Q)-2,-1,-1):
            for i in range(len(self.B)):
                b[t][i]=0
                for j in range(len(self.B)):
                    b[t][i]+=b[t+1][j]*self.A[i][j]*self.B[j][Q[t+1]]
        q=0
        for i in range(len(self.B)):
            q+=b[0][i]*self.W[i]*self.B[i][Q[0]]
        return q
T=HMM1()
print(T.cal_q([0,1,1,0]))
print(T.cal_q2([0,1,1,0]))

二、学习问题
学习问题的算法有Baum-Welch算法,该算法采用的是EM算法。同样,模型推荐还是看书,李航的那本书将的是最清楚的,当然配合下面的代码会更加清晰。

import numpy as np
class Baum:
    def __init__(self,Q):
        self.l=len(Q)
        self.Q=Q
        self.n=len(set([i for j in Q for i in j]))  ##观测状态的个数
        self.m=4
        self.A=np.zeros((4,4))
        self.B=np.zeros((4,self.n))
        self.W=np.zeros(4)
        self.T=len(Q[0])
        self.initial()
    def initial(self):
        for i in range(4):
            for j in range(4):
                self.A[i,j]=0.25
        for i in range(4):
            for j in range(self.n):
                self.B[i,j]=1lf.n
        for i in range(4):
            self.W[i]=0.25

    def main(self):
        for iter in range(20):
            for l in range(len(self.Q)):
                gama,sigma=self.update(self.Q[l])
                for i in range(4):
                    for j in range(4):
                        self.A[i,j]=sum([sigma[t,i,j] for t in range(self.T-1)])/sum([gama[t,i] for t in range(self.T-1)])
                for i in range(4):
                    for j in range(self.n):
                        temp=0
                        for t in range(self.T):
                            if self.Q[l][t]==j:
                                temp+=gama[t,i]
                        self.B[i,j]=temp/sum([gama[t,i] for t in range(self.T)])
                for i in range(4):
                    self.W[i]=gama[0][i]
                
    def update(self,O):
        a = [[0 for i in range(len(self.B))] for j in range(len(O))]
        for i in range(len(self.B)):
            a[0][i]=self.W[i]*self.B[i][O[0]]

        for t in range(1,len(O)):
            for i in range(len(self.B)):
                a[t][i]=0
                for j in range(len(self.B)):
                    a[t][i]+=a[t-1][j]*self.A[j,i]*self.B[i,O[t]]

        b = [[0 for i in range(len(self.B))] for j in range(len(O))]
        for i in range(len(self.B)):
            b[-1][i]=1
        for t in range(len(O)-2,-1,-1):
            for i in range(len(self.B)):
                b[t][i]=0
                for j in range(len(self.B)):
                    b[t][i]+=b[t+1][j]*self.A[i,j]*self.B[j,O[t+1]]

        """
        gama t i 表示给定模型个观测数据的情况下在时刻t系统状态为i的概率
        """
        gama = np.zeros((self.T, 4))
        for t in range(self.T):
            for i in range(4):
                gama[t,i]=a[t][i]*b[t][i]/sum([a[t][k]*b[t][k] for k in range(4)])

        """
        sgma t i,j 表示给定模型个观测数据的情况下在时刻t系统状态为i,且t+1时刻状态为j的概率
        """
        sigma = np.zeros((self.T, 4, 4))
        for t in range(self.T-1):
            temp=0
            for i in range(4):
                for j in range(4):
                    temp+=a[t][i]*self.A[i,j]*self.B[i,O[t]]*b[t+1][j]
            for i in range(4):
                for j in range(4):
                    sigma[t,i,j]=a[t][i]*self.A[i,j]*self.B[i,O[t]]*b[t+1][j]/temp

        return gama,sigma

T=Baum([[0,1,1,0,2,3,0,1],[0,2,3,0,1,2,3,0],list(map(int,list("12300212")))])
T.main()

三、预测问题
预测问题采用的是维比特算法,该算法采用的是动态规划方法求最优路径。

import numpy as np
class 维比特算法:
    def __init__(self):
        self.A=[[0.5,0.2,0.3],[0.3,0.5,0.2],[0.2,0.3,0.5]]       ##转移概率
        self.B=[[0.5,0.5],[0.4,0.6],[0.7,0.3]]                   ##观测概率
        self.W=[0.2,0.4,0.4]
        self.O=[0,1,0]
        self.m=len(self.A) ## 状态的种数
        self.n=len(self.O) ## 观测的个数
        self.sigma=[[0 for _ in range(self.m)] for _ in range(self.n)]
        self.psi=[[0 for _ in range(self.m)] for _ in range(self.n)]


    def main(self):
        self.sigma[0][:]=[self.W[i]*self.B[i][self.O[0]] for i in range(self.m)]
        for i in range(1,self.n):
            for j in range(self.m):
                tem=[self.sigma[i-1][k]*self.A[k][j] for k in range(self.m)]
                tem_max=max(tem)
                self.sigma[i][j]=tem_max*self.B[j][self.O[i]]
                self.psi[i][j]=np.argmax(tem)

        res=[np.argmax(self.sigma[-1][:])]
        for i in range(self.n-1):
            res.insert(0,np.argmax(self.psi[res[-1]][:]))
        print(res)

T=维比特算法()
T.main()

想了解更多算法,数据分析,数据挖掘等方面的知识,欢迎关注ChallengeHub公众号,添加微信进入微信交流群,或者进入QQ交流群。关注公众号或者进群可以直接获得上面的代码,而且也有很多机器学习的资料可以获取。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值