package hmm; import java.util.HashMap; import java.util.Map; /** * 隐马尔可夫模型 * @author xuguanglv * */ public class Hmm { //初始概率向量 private static double[] pai = {0.333, 0.333, 0.333}; //状态转移矩阵 private static double[][] A = {{0.333, 0.333, 0.333}, {0.333, 0.333, 0.333}, {0.333, 0.333, 0.333}}; //混淆矩阵 private static double[][] B = {{0.5, 0.5}, {0.75, 0.25}, {0.25, 0.75}}; //隐藏状态索引 private static Map<Integer, String> hiddenStateIndex = new HashMap<Integer, String>(); static{ hiddenStateIndex.put(0, "S(0)"); hiddenStateIndex.put(1, "S(1)"); hiddenStateIndex.put(2, "S(2)"); } //观察状态索引 private static Map<String, Integer> observableStateIndex = new HashMap<String, Integer>(); static{ observableStateIndex.put("O(0)", 0); observableStateIndex.put("O(1)", 1); } //维特比算法 根据观察状态序列和已知的隐马尔可夫模型 返回最可能的隐藏状态序列 //delta[t][j]表示t时刻最可能生成O(0) O(1) ... O(t)的以状态j为结尾的隐藏状态序列出现的概率 public static String[] viterbi(String[] observedSequence){ String[] hiddenSequence = new String[observedSequence.length]; double[][] delta = new double[observedSequence.length][A.length]; //一个前驱数组 predecessor[t][j]表示以状态j为结尾的概率最大的隐藏状态序列中j的前一个状态 int[][] predecessor = new int[observedSequence.length][A.length]; //利用动态规划计算出delta数组 //初始化 for(int i = 0; i <= A.length - 1; i++){ int index = observableStateIndex.get(observedSequence[0]); delta[0][i] = pai[i] * B[i][index]; } for(int i = 0; i <= A.length - 1; i++){ predecessor[0][i] = -1; } for(int t = 1; t <= observedSequence.length - 1; t++){ for(int j = 0; j <= A.length - 1; j++){ double max = 0; for(int i = 0; i <= A.length - 1; i++){ if(delta[t - 1][i] * A[i][j] > max){ max = delta[t - 1][i] * A[i][j]; predecessor[t][j] = i; } } int index = observableStateIndex.get(observedSequence[t]); delta[t][j] = max * B[j][index]; } } //max就是生成整个观察状态序列的最可能的隐藏状态序列的概率 //lastHiddenIndex用来表示这最可能的隐藏状态序列的最后一个隐藏状态 double max = 0; int lastHiddenIndex = 0; for(int i = 0; i <= A.length - 1; i++){ if(delta[observedSequence.length - 1][i] > max){ max = delta[observedSequence.length - 1][i]; lastHiddenIndex = i; } } //回溯出最可能生成观察状态序列的隐藏状态序列的每一个隐藏状态 放入hiddenSequence hiddenSequence[observedSequence.length - 1] = hiddenStateIndex.get(lastHiddenIndex); int curHiddenIndex = lastHiddenIndex; for(int t = observedSequence.length - 1; t >= 1; t--){ hiddenSequence[t - 1] = hiddenStateIndex.get(predecessor[t][curHiddenIndex]); curHiddenIndex = predecessor[t][curHiddenIndex]; } return hiddenSequence; } public static void main(String[] args){ String[] observedSequence = {"O(0)", "O(0)", "O(0)", "O(0)", "O(1)", "O(0)", "O(1)", "O(1)", "O(1)", "O(1)"}; String[] hiddenSequence = viterbi(observedSequence); for(String hiddenState : hiddenSequence){ System.out.print(hiddenState + " "); } } }
隐马尔可夫模型之:维特比算法
接上一篇博客的内容,给出利用已知的隐马尔可夫模型和观察状态序列,输出最可能的隐藏状态序列的算法,该算法由著名信息学大师维特比提出,所以叫做维特比算法(viterbi algorithm),这其实是一个解码的过程。维特比算法依然利用动态规划,时间复杂度跟前向算法相同,最大的区别有两个:1.求和变为取最大值,即计算问题变为最优化问题 2.增加了回溯,利用一个前驱数组,记录了每条最优(也就是概率最大)的子隐藏状态序列的每个节点的前驱。java程序如下:
猜你喜欢
转载自xglv2013.iteye.com/blog/2307279
今日推荐
周排行