python实现隐马尔科夫模型HMM
作者:adzhua 发布时间:2023-05-05 13:33:57
标签:python,隐马尔科夫模型,HMM
一份完全按照李航<<统计学习方法>>介绍的HMM代码,供大家参考,具体内容如下
#coding=utf8
'''''
Created on 2017-8-5
里面的代码许多地方可以精简,但为了百分百还原公式,就没有精简了。
@author: adzhua
'''
import numpy as np
class HMM(object):
def __init__(self, A, B, pi):
'''''
A: 状态转移概率矩阵
B: 输出观察概率矩阵
pi: 初始化状态向量
'''
self.A = np.array(A)
self.B = np.array(B)
self.pi = np.array(pi)
self.N = self.A.shape[0] # 总共状态个数
self.M = self.B.shape[1] # 总共观察值个数
# 输出HMM的参数信息
def printHMM(self):
print ("==================================================")
print ("HMM content: N =",self.N,",M =",self.M)
for i in range(self.N):
if i==0:
print ("hmm.A ",self.A[i,:]," hmm.B ",self.B[i,:])
else:
print (" ",self.A[i,:]," ",self.B[i,:])
print ("hmm.pi",self.pi)
print ("==================================================")
# 前向算法
def forwar(self, T, O, alpha, prob):
'''''
T: 观察序列的长度
O: 观察序列
alpha: 运算中用到的临时数组
prob: 返回值所要求的概率
'''
# 初始化
for i in range(self.N):
alpha[0, i] = self.pi[i] * self.B[i, O[0]]
# 递归
for t in range(T-1):
for j in range(self.N):
sum = 0.0
for i in range(self.N):
sum += alpha[t, i] * self.A[i, j]
alpha[t+1, j] = sum * self.B[j, O[t+1]]
# 终止
sum = 0.0
for i in range(self.N):
sum += alpha[T-1, i]
prob[0] *= sum
# 带修正的前向算法
def forwardWithScale(self, T, O, alpha, scale, prob):
scale[0] = 0.0
# 初始化
for i in range(self.N):
alpha[0, i] = self.pi[i] * self.B[i, O[0]]
scale[0] += alpha[0, i]
for i in range(self.N):
alpha[0, i] /= scale[0]
# 递归
for t in range(T-1):
scale[t+1] = 0.0
for j in range(self.N):
sum = 0.0
for i in range(self.N):
sum += alpha[t, i] * self.A[i, j]
alpha[t+1, j] = sum * self.B[j, O[t+1]]
scale[t+1] += alpha[t+1, j]
for j in range(self.N):
alpha[t+1, j] /= scale[t+1]
# 终止
for t in range(T):
prob[0] += np.log(scale[t])
def back(self, T, O, beta, prob):
'''''
T: 观察序列的长度 len(O)
O: 观察序列
beta: 计算时用到的临时数组
prob: 返回值;所要求的概率
'''
# 初始化
for i in range(self.N):
beta[T-1, i] = 1.0
# 递归
for t in range(T-2, -1, -1): # 从T-2开始递减;即T-2, T-3, T-4, ..., 0
for i in range(self.N):
sum = 0.0
for j in range(self.N):
sum += self.A[i, j] * self.B[j, O[t+1]] * beta[t+1, j]
beta[t, i] = sum
# 终止
sum = 0.0
for i in range(self.N):
sum += self.pi[i]*self.B[i,O[0]]*beta[0,i]
prob[0] = sum
# 带修正的后向算法
def backwardWithScale(self, T, O, beta, scale):
'''''
T: 观察序列的长度 len(O)
O: 观察序列
beta: 计算时用到的临时数组
'''
# 初始化
for i in range(self.N):
beta[T-1, i] = 1.0
# 递归
for t in range(T-2, -1, -1):
for i in range(self.N):
sum = 0.0
for j in range(self.N):
sum += self.A[i, j] * self.B[j, O[t+1]] * beta[t+1, j]
beta[t, i] = sum / scale[t+1]
# viterbi算法
def viterbi(self, O):
'''''
O: 观察序列
'''
T = len(O)
# 初始化
delta = np.zeros((T, self.N), np.float)
phi = np.zeros((T, self.N), np.float)
I = np.zeros(T)
for i in range(self.N):
delta[0, i] = self.pi[i] * self.B[i, O[0]]
phi[0, i] = 0.0
# 递归
for t in range(1, T):
for i in range(self.N):
delta[t, i] = self.B[i, O[t]] * np.array([delta[t-1, j] * self.A[j, i] for j in range(self.N)] ).max()
phi = np.array([delta[t-1, j] * self.A[j, i] for j in range(self.N)]).argmax()
# 终止
prob = delta[T-1, :].max()
I[T-1] = delta[T-1, :].argmax()
for t in range(T-2, -1, -1):
I[t] = phi[I[t+1]]
return prob, I
# 计算gamma(计算A所需的分母;详情见李航的统计学习) : 时刻t时马尔可夫链处于状态Si的概率
def computeGamma(self, T, alpha, beta, gamma):
''''''''
for t in range(T):
for i in range(self.N):
sum = 0.0
for j in range(self.N):
sum += alpha[t, j] * beta[t, j]
gamma[t, i] = (alpha[t, i] * beta[t, i]) / sum
# 计算sai(i,j)(计算A所需的分子) 为给定训练序列O和模型lambda时
def computeXi(self, T, O, alpha, beta, Xi):
for t in range(T-1):
sum = 0.0
for i in range(self.N):
for j in range(self.N):
Xi[t, i, j] = alpha[t, i] * self.A[i, j] * self.B[j, O[t+1]] * beta[t+1, j]
sum += Xi[t, i, j]
for i in range(self.N):
for j in range(self.N):
Xi[t, i, j] /= sum
# 输入 L个观察序列O,初始模型:HMM={A,B,pi,N,M}
def BaumWelch(self, L, T, O, alpha, beta, gamma):
DELTA = 0.01 ; round = 0 ; flag = 1 ; probf = [0.0]
delta = 0.0; probprev = 0.0 ; ratio = 0.0 ; deltaprev = 10e-70
xi = np.zeros((T, self.N, self.N)) # 计算A的分子
pi = np.zeros((T), np.float) # 状态初始化概率
denominatorA = np.zeros((self.N), np.float) # 辅助计算A的分母的变量
denominatorB = np.zeros((self.N), np.float)
numeratorA = np.zeros((self.N, self.N), np.float) # 辅助计算A的分子的变量
numeratorB = np.zeros((self.N, self.M), np.float) # 针对输出观察概率矩阵
scale = np.zeros((T), np.float)
while True:
probf[0] =0
# E_step
for l in range(L):
self.forwardWithScale(T, O[l], alpha, scale, probf)
self.backwardWithScale(T, O[l], beta, scale)
self.computeGamma(T, alpha, beta, gamma) # (t, i)
self.computeXi(T, O[l], alpha, beta, xi) #(t, i, j)
for i in range(self.N):
pi[i] += gamma[0, i]
for t in range(T-1):
denominatorA[i] += gamma[t, i]
denominatorB[i] += gamma[t, i]
denominatorB[i] += gamma[T-1, i]
for j in range(self.N):
for t in range(T-1):
numeratorA[i, j] += xi[t, i, j]
for k in range(self.M): # M为观察状态取值个数
for t in range(T):
if O[l][t] == k:
numeratorB[i, k] += gamma[t, i]
# M_step。 计算pi, A, B
for i in range(self.N): # 这个for循环也可以放到for l in range(L)里面
self.pi[i] = 0.001 / self.N + 0.999 * pi[i] / L
for j in range(self.N):
self.A[i, j] = 0.001 / self.N + 0.999 * numeratorA[i, j] / denominatorA[i]
numeratorA[i, j] = 0.0
for k in range(self.M):
self.B[i, k] = 0.001 / self.N + 0.999 * numeratorB[i, k] / denominatorB[i]
numeratorB[i, k] = 0.0
#重置
pi[i] = denominatorA[i] = denominatorB[i] = 0.0
if flag == 1:
flag = 0
probprev = probf[0]
ratio = 1
continue
delta = probf[0] - probprev
ratio = delta / deltaprev
probprev = probf[0]
deltaprev = delta
round += 1
if ratio <= DELTA :
print('num iteration: ', round)
break
if __name__ == '__main__':
print ("python my HMM")
# 初始的状态概率矩阵pi;状态转移矩阵A;输出观察概率矩阵B; 观察序列
pi = [0.5,0.5]
A = [[0.8125,0.1875],[0.2,0.8]]
B = [[0.875,0.125],[0.25,0.75]]
O = [
[1,0,0,1,1,0,0,0,0],
[1,1,0,1,0,0,1,1,0],
[0,0,1,1,0,0,1,1,1]
]
L = len(O)
T = len(O[0]) # T等于最长序列的长度就好了
hmm = HMM(A, B, pi)
alpha = np.zeros((T,hmm.N),np.float)
beta = np.zeros((T,hmm.N),np.float)
gamma = np.zeros((T,hmm.N),np.float)
# 训练
hmm.BaumWelch(L,T,O,alpha,beta,gamma)
# 输出HMM参数信息
hmm.printHMM()
来源:https://blog.csdn.net/adzhua/article/details/76746895
0
投稿
猜你喜欢
- TensorFlow是一款优秀的深度学习框架,支持多种常见的操作系统,例如Windows10,Mac Os等等,同时也支持运行在NVIDIA
- django的表单系统,分2种基于django.forms.Form的所有表单类的父类基于django.forms.ModelForm,可以
- 0.摘要在Python中,尤其是数组当中,对于一些异常值往往需要进行特殊处理。为了防止异常值与正常数据混淆,影响最终计算结果,常用的方法是将
- 测试语法如下:powered by jb51.netexec GetRecordFromPage news,newsid,10,100000
- 字符编码我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题。因为计算机只能处理数字,如果要处理文本,就必须先把
- 有关pygal的安装,大家可以参阅《pip和pygal的安装实例教程》。直方图:直方图是一个特殊的条,它可以取3个数值:纵坐标高度,横坐标开
- 一个非常简单的将半角"转换为中文"的asp函数function new_str(str) 
- 导语说到童年爱玩的电脑游戏,你会想到什么?最国民的莫过于金山打字通,接着是扫雷、红心大战,而红极一时的单机游戏当属《大富翁》。嘻嘻 打字游戏
- 1.业务需求背景业务提供一张底层图片1以及需要在底层图片上添加的图片2,两张图片大小不一致,将小图2添加到底图1中,并在其他的空白部分添加个
- 本文实例讲述了Python使用matplotlib绘制三维参数曲线操作。分享给大家供大家参考,具体如下:一 代码import matplot
- 假设通过爬虫你获取到了北京2016年3,10月份每天白天的最高气温(分别位于列表a,b),那么此时如何寻找出气温随时间(天)变化的某种规律?
- 背景为了更好的发展自身的测试技能,应对测试行业以及互联网行业的迭代变化。自学python以及自动化测试。虽然在2017年已经开始接触了sel
- 前两天,编辑建议我去当当和卓越申请个用户,在网站上放上我的书的链接,这样还可以拿到一些反点儿,于是我兴冲冲地跑到几个网站上去看,却只在卓越(
- String(字符型)–%s integer(整形)–%d float(浮点型)–%f实例我们需要输出一个人的信息代码:#coding=ut
- 一、简介urlparse模块用户将url解析为6个组件,并以元组形式返回,返回的6个部分,分别是:scheme(协议)、netloc(网络位
- 关于python的ssh库操作需要引入一个远程控制的模块——paramiko,可用于对远程服务器进行
- 定义切片区别于数组,是引用类型, 不是值类型。数组是固定长度的,而切片长度是可变的,我的理解是:切片是对数组一个片段的引用。var s1 [
- 1. 为什么要查看梯度对于初学者来说网络经常不收敛,loss很奇怪(就是不收敛),所以怀疑是反向传播中梯度的问题(1)求导之后的数(的绝对值
- 我就废话不多说啦,大家还是直接看代码吧!import requests,randomfrom lxml import etreeimport
- 第一步、导入需要的包import osimport scipy.io as sioimport numpy as npimport torc