zoukankan      html  css  js  c++  java
  • HMM代码实现

    按照网上的代码,自己敲了一下,改了一点点,理解加深了一下。

    还有训练HMM的EM算法没看懂,下次接着看;

    参考连接:http://www.cnblogs.com/hanahimi/p/4011765.html

      1 # -*- coding: utf-8 -*-
      2 
      3 '''
      4 function: 根据网上的代码,学习实现 HMM,前向计算概率,后向预测状态序列,学习算法参数
      5 date: 2017.8.9
      6 '''
      7 
      8 import numpy as np
      9 
     10 class HMM(object):
     11     """docstring Ann, Bnm, piln HMM"""
     12     def __init__(self, Ann, Bnm, piln):
     13         self.A = Ann
     14         self.B = Bnm
     15         self.pi = piln
     16         self.N = self.A.shape[0]  #状态的种类个数
     17         self.M = self.B.shape[1]  #观测序列的长度
     18 
     19     #打印hmm的信息
     20     def printHmm(self):
     21         print("=======================================")
     22         print('hmm content N = ', self.N, ' M = ', self.M)
     23         for i in range(self.N):
     24             if i == 0:
     25                 print('hmm.A ', self.A[i,:],'hmm.B', self.B[i,:])
     26             else:
     27                 print('      ', self.A[i,:], '    ', self.B[i,:])
     28         print('hmm.pi', self.pi)
     29         print('========================================')
     30 
     31     '''
     32     function: 维特比算法
     33     input: A,B,pi,O
     34     output: P(o|lambda) 最大的时候,状态的路径序列
     35     '''
     36     def viterbi(self, O):
     37         T = len(O) #观察序列的长度
     38         
     39         #初始化,这里从0~T-1
     40         #delta t行 n列,代表有t个时间点,每个时间点可能有n种状态
     41         delta = np.zeros((T, self.N), np.float) #二维数组记录计算的所有概率,包括了最有的点
     42         phi = np.zeros((T, self.N), np.int) #记录概率最大路径的前一个状态
     43         I = np.zeros(T, np.int) #这里如果不显示表明类型为 np.int,就是float?
     44         for i in range(self.N):
     45             delta[0,i] = self.pi[i] * self.B[i,O[0]] #t = 0时刻,各个状态的起始概率
     46             phi[0,i] = 0 #t=0时刻前缀状态都是0
     47 
     48         #递推
     49         for t in range(1,T): #从 1 开始
     50             for i in range(self.N):
     51                 delta[t,i] = self.B[i,O[t]] * np.array([delta[t-1,j]*self.A[j,i] 
     52                     for j in range(self.N)]).max()
     53                 phi[t,i] = np.array([delta[t-1, j]*self.A[j,i] for j in range(self.N)]).argmax()
     54         #结束
     55         prob = delta[T-1,:].max() #T-1时刻是最后时刻,哪个状态在最后时刻概率最大就是最优路径的起始点
     56         I[T-1] = phi[T-1,:].argmax() #最优路径的起点状态编号
     57         #状态序列获取
     58         for t in range(T-2, -1, -1): #从 T-1 到 -1(不包括-1),间隔是-1,即递减
     59             I[t] = phi[t+1, I[t+1]]
     60         return I, prob
     61 
     62     '''
     63     function: 前向算法计算擦观察序列 O 出现的概率
     64     input: A,B,pi,O
     65     output: prob
     66     '''
     67     def forward(self, O):
     68         T = len(O)
     69         alpha = np.zeros((T, self.N), np.float) #暂存计算的所有概率,按照时间点向前推进
     70         #初始化
     71         for i in range(self.N):
     72             alpha[0,i] = self.pi[i] * self.B[i, O[0]]
     73         
     74         #迭代计算
     75         for t in range(T-1):
     76             for i in range(self.N): #这里B[i,O[t]]也可以放在for的外面乘
     77                 alpha[t+1,i] = np.array([alpha[t, j]*self.A[j,i]*self.B[i,O[t+1]] for 
     78                     j in range(self.N)]).sum()
     79 
     80         #终止
     81         prob = np.array([alpha[T-1, j] for j in range(self.N)]).sum()
     82         return prob
     83 
     84     '''
     85     function: 后向算法,计算观测序列出现的概率
     86 
     87     '''
     88     def backword(self, O):
     89         T = len(O)
     90         beta = np.zeros((T, self.N), np.float) #暂存计算的概率
     91 
     92         #初始化
     93         for i in range(self.N):
     94             beta[T-1, i] = 1  #从后向前
     95         #迭代计算
     96         for t in range(T-2, -1, -1):
     97             for i in range(self.N):
     98                 beta[t,i] = np.array([[A[j,i] * B[j,O[t+1]] * beta[t+1,j]] for 
     99                     j in range(self.N)]).sum()
    100 
    101         prob = np.array([self.pi[j] * self.B[i,O[1]] * beta[1,j] for j in range(self.N)]).sum()
    102 
    103         return prob
    104 
    105 
    106 
    107 if __name__ == 'main':
    108 
    109     print('python my HMM')
    110 
    111     #HMM模型的参数
    112     A = [[0.8125,0.1875],[0.2,0.8]]
    113     B = [[0.875,0.125], [0.25,0.75]] #每一行的和是 1
    114     pi = [0.5,0.5]
    115     hmm = HMM(A,B,pi) #构建HMM
    116 
    117     print(hmm)
    118 
    119 print('python my HMM')
    120 
    121 #HMM模型的参数
    122 A = np.mat([[0.8125,0.1875],[0.2,0.8]])
    123 B = np.mat([[0.875,0.125], [0.25,0.75]]) #每一行的和是 1
    124 pi = [0.5,0.5]
    125 O = [[1,0,0,1,1,0,0,0,0],
    126     [1,1,0,1,0,0,1,1,0],
    127     [0,0,1,1,0,0,1,1,1]]
    128 
    129 hmm = HMM(A,B,pi) #构建HMM
    130 
    131 #计算前向概率,产生特定观测序列O的概率
    132 prob = hmm.forward(O[0])
    133 print('前向算法产生 O 序列的概率是: ' + str(prob))
    134 
    135 #后向算法计算观测序列的概率
    136 prob = hmm.backword(O[0])
    137 print('后向算法概率是: ' + str(prob))
    138 #计算隐含概率,维特比算法
    139 path, prob2 = hmm.viterbi(O[0])
    140 print('产生 O 序列最大概率路径是: ' + str(path))
    141 print('概率是: ' + str(prob2))
    142 
    143 hmm.printHmm()
  • 相关阅读:
    HDU 5528 Count a * b 欧拉函数
    HDU 5534 Partial Tree 完全背包
    HDU 5536 Chip Factory Trie
    HDU 5510 Bazinga KMP
    HDU 4821 String 字符串哈希
    HDU 4814 Golden Radio Base 模拟
    LA 6538 Dinner Coming Soon DP
    HDU 4781 Assignment For Princess 构造
    LA 7056 Colorful Toy Polya定理
    LA 6540 Fibonacci Tree
  • 原文地址:https://www.cnblogs.com/robin2ML/p/7340033.html
Copyright © 2011-2022 走看看