大佬博文地址[https://blog.csdn.net/slx_share/article/details/80237566]
1. 基础
1.1 python知识点
-
itertools.accumulate 返回一个迭代序列的累加值序列(没有func的情况下)[详细描述](http://www.mamicode.com/info-detail-2201554.html)
-
获取np的arraylist中满足某项条件的索引
行索引添加链接描述
np.where(state==2)[0]
3.enumerate
for j, d in enumerate(delta)
这个代码的好处在于,可以在for循环中同时获得索引和值
4. @ 运算符
可代替矩阵运算符
import numpy as np
A=np.array(range(4)).reshape([2,2])
al=np.array([4,5]).reshape([1,2])
al =al @ A
print(al)
# al的结果[[10,19]]
以上代码的运算结果是[[10,19]]
1.2 思想
观测序列的生成,采用随机的方式的给出,主要逻辑在下面的这个函数里
def _locate(self, prob_arr):
# 给定概率向量,返回状态
# 使用accumulate(prob_arr)必然就有一个返回值
seed = np.random.rand(1)
for state, cdf in enumerate(accumulate(prob_arr)):
if seed <= cdf:
return state
return
2. 代码分析
2.1.
def predict(hmm, obs):
# 采用Viterbi算法预测状态序列
N = len(obs)
nodes_graph = np.zeros((hmm.n_state, N), dtype=int) # 存储时刻t且状态为i时, 前一个时刻t-1的状态,用于构建最终的状态序列
# 矩阵运算,很节省计算资源
delta = hmm.S * hmm.B[:, obs[0]] # 存储到t时刻,且此刻状态为i的最大概率
nodes_graph[:, 0] = range(hmm.n_state)
for t in range(1, N):
new_delta = []
for i in range(hmm.n_state):
temp = [hmm.A[j, i] * d for j, d in enumerate(delta)] # 当前状态为i时, 选取最优的前一时刻状态
max_d = max(temp)
new_delta.append(max_d * hmm.B[i, obs[t]])
nodes_graph[i, t] = temp.index(max_d)
delta = new_delta
# current_state = np.argmax(nodes_graph[:, -1])
current_state=np.argmax(delta)
path = []
t = N
while t > 0:
path.append(current_state)
current_state = nodes_graph[current_state, t - 1]
t -= 1
return list(reversed(path))
这是关于书中维比特算法的算法实现,此博主的代码亮点在于:
1.delta = hmm.S * hmm.B[:, obs[0]]
利用这个向量的运算,使程序在一次计算中获取了 i=1 : n 的初始化数据,
2. 当然如果在后面的迭代操作中,需要寻找
temp = [hmm.A[j, i] * d for j, d in enumerate(delta)]
的最大值,否则,我们仍然可以使用向量的运算简化计算
3. 在我的个人见解里,我觉得第21行,原博主写的代码存在错误,故将其注释,换成自己的代码