我最近一直在尝试研究隐马尔可夫模型和维特比算法。我找到了一个名为 hmmlearn ( http://hmmlearn.readthedocs.io/en/latest/tutorial.html ) 的库来帮助我生成两个状态的状态序列(具有高斯发射)。然后我想用维特比重新确定状态序列。我的代码有效,但预测了大约 5% 的错误状态(取决于高斯发射的均值和方差)。hmmlearn 库有一个 .predict 方法,它也使用 Viterbi 来确定状态序列。
我现在的问题是 hmmlearn 的 Viterbi 算法比我手写的要好得多(与我的 5% 相比,错误率低于 0.5%)。我在我的代码中找不到任何重大问题,所以我不确定为什么会这样。下面是我的代码,我首先生成状态和观察序列 Z 和 X,用 hmmlearn 预测 Z,最后用我自己的代码预测它:
# Import libraries
import numpy as np
import scipy.stats as st
from hmmlearn import hmm
# Generate a sequence
model = hmm.GaussianHMM(n_components = 2, covariance_type = "spherical")
model.startprob_ = pi
model.transmat_ = A
model.means_ = obs_means
model.covars_ = obs_covars
X, Z = model.sample(T)
## Predict the states from generated observations with the hmmlearn library
Z_pred = model.predict(X)
# Predict the state sequence with Viterbi by hand
B = np.concatenate((st.norm(mean_1,var_1).pdf(X), st.norm(mean_2,var_2).pdf(X)), axis = 1)
delta = np.zeros(shape = (T, 2))
psi = np.zeros(shape= (T, 2))
### Calculate starting values
for s in np.arange(2):
delta[0, s] = np.log(pi[s]) + np.log(B[0, s])
psi = np.zeros((T, 2))
### Take everything in log space since values get very low as t -> T
for t in range(1,T):
for s_post in range(0, 2):
delta[t, s_post] = np.max([delta[t - 1, :] + np.log(A[:, s_post])], axis = 1) + np.log(B[t, s_post])
psi[t, s_post] = np.argmax([delta[t - 1, :] + np.log(A[:, s_post])], axis = 1)
### Backtrack
states = np.zeros(T, dtype=np.int32)
states[T-1] = np.argmax(delta[T-1])
for t in range(T-2, -1, -1):
states[t] = psi[t+1, states[t+1]]
我不确定我的代码是否有大错误,或者 hmmlearn 是否只是使用了更精细的 Viterbi 算法。通过查看错误预测的状态,我注意到发射概率 B 的影响似乎太大了,因为它导致状态变化过于频繁,即使进入另一个状态的转换概率非常低。
我对python很陌生,所以请原谅我丑陋的编码。提前感谢您提供的任何提示!
编辑:正如您在代码中看到的那样,我很愚蠢并且使用方差而不是标准偏差来确定排放概率。修复此问题后,我得到与实现的 Viterbi 算法相同的结果。