隐 马尔科夫 维特比viterbi算法

算法讲解见 https://www.zhihu.com/question/20136144/answer/239971177 ,细节不过多赘述。
核心思想:
一种搜索算法,为避免穷举,使用概率优化:
一、使用前一状态与本次观察推断本次状态。
二、对于每一个时间t,保留概率最大的隐状态剪枝,用于后续计算。最终得到 T * state 形状的路径矩阵。
三、将最后一个时刻中 概率最大的隐状态 作为最后一个时刻的最优状态,上一时刻隐状态中 最可能致使该最优状态 的状态 为上一时刻的最优状态。依此法,从后往前依次取得每一个时刻的最优状态为推测结果。

python代码

import numpy as np
# 状态转移矩阵
trans_ = np.array([[0.7,0.3],
				   [0.4,0.6]])
# 观察矩阵
ob_ = 	 np.array([[0.5,0.4,0.1],
				   [0.1,0.3,0.6]])
# t0时刻 初始状态
state = np.array([0.6,0.4])

def next_state(state_):
	""" 计算t到t+1的状态转移
	要保留各行的值,所以使用内积计算"""
	state = np.zeros_like(trans_)
	for i in range(trans_.shape[1]):
		state[i] = state_
	state = state.T
	res = np.multiply(state,trans_)
	return res

def ob2state(last_statu,ob):
	"""使用 ob和上一状态 推测当前状态,保留行使用内积"""
	ob = ob_[:,ob]
	state = np.multiply(last_statu,ob)
	return state

def viterbi(obs):
	"""从观察结果中推断每一时刻最可能的状态"""
	global state
	# 记录路径, 形状 T* state
	table = np.zeros((len(obs)-1,state.shape[0]),dtype=int)
	# 第一状态计算
	state = ob2state(state,obs[0])
	table[0] = state
	# 后续状态计算
	for i,ob in enumerate(obs[1:]):
		state = next_state(state)
		state = ob2state(state,ob)
		# 将概率最大的路径保存到table中
		table[i] = np.argmax(state,axis=0)
		# 剪枝,保留最大概率用于后续计算
		state = np.max(state,axis=0)
		# print(state)

	# 回溯
	res = []
	# 最后一个状态 取概率最大值
	state = np.argmax(state)
	res.insert(0,state)
	# 依次从后往前回溯
	i = table.shape[0] - 1
	while i>=0:
		state = table[i,state]
		res.insert(0,state)
		i -= 1
	return res

if __name__ == '__main__':
	obs = [0,1,2] # 每一时刻的观察结果
	print(viterbi(obs))
	

你可能感兴趣的:(算法,马尔科夫,维特比,viterbi)