维特比算法(viterbi)python实现
import numpy as np
state_transfer = np.array([[0.5, 0.2, 0.3], [0.3, 0.5, 0.2], [0.2, 0.3, 0.5]]) # 状态转移矩阵
observe_prob = np.array([[0.5, 0.5], [0.4, 0.6], [0.7, 0.3]]) # 观测概率矩阵
initial = np.array([0.2, 0.4, 0.4]) # 初始状态概率向量
observes = ['红', '白'] # 所有可能的观测集合
states = [0, 1, 2] # 所有可能的状态集合
observe_seq = ['红', '白', '红'] # 观测序列
def argmax(path_value, state_transfer, states, state, m): # 在t时刻状态为i的所有单个路径(i1,i2,...,it)中概率最大的路径第t-1个结点
max_index = -1
max_value = -1
for statej in states:
if path_value[m-1][statej] * state_transfer[statej][state] > max_value:
max_value = path_value[m-1][statej] * state_transfer[statej][state]
max_index = statej
return max_index
def argmax2(path_value_len):
max_index = -1
max_value = -1
for i in range(len(path_value_len)):
if path_value_len[i] > max_value:
max_value = path_value_len[i]
max_index = i
return max_index
def viterbi(state_transfer, states, observe_prob, initial, observe_seq):
path_value = np.zeros(shape=(3, 3)) # 存储在t时刻状态为i的所有单个路径(i1,i2,...it)中概率最大值(t=0,1,2, i=0,1,2)
path_node = np.zeros(shape=(3, 3), dtype=int) # 存储在t时刻状态为i的所有单个路径(i1,i2,...,it)中概率最大的路径第t-1个结点
for m in range(len(observe_seq)):
if m == 0: #初始化
for state in states:
path_value[m][state] = initial[state] * observe_prob[state][observes.index(observe_seq[m])] #在t时刻状态为i的所有单个路径(i1,i2,...it)中概率最大值(t=0,1,2, i=0,1,2)
path_node[m] = [-1, -1, -1]
else:
for state in states: # 递推
path_value[m][state] = max([path_value[m-1][statej] * state_transfer[statej][state] for statej in states]) \
* observe_prob[state][observes.index(observe_seq[m])] # 在t时刻状态为i的所有单个路径(i1,i2,...it)中概率最大值(t=0,1,2, i=0,1,2)
path_node[m][state] = argmax(path_value, state_transfer, states, state, m) # 在t时刻状态为i的所有单个路径(i1,i2,...,it)中概率最大的路径第t-1个结点
max_path_value = max(path_value[len(observe_seq)-1])
path = []
i_t = argmax2(path_value[len(observe_seq)-1]) #最优路径第t时刻状态
path.append(i_t)
for k in range(len(observe_seq)-1, -1, -1): # 最优路径回溯
i_t = path_node[k][i_t]
path.append(i_t)
print(list(reversed(path))[1:]) # 输出最优路径
print(max_path_value)
if __name__ == '__main__':
viterbi(state_transfer, states, observe_prob, initial, observe_seq)