隐马尔可夫模型之:维特比算法

接上一篇博客的内容,给出利用已知的隐马尔可夫模型和观察状态序列,输出最可能的隐藏状态序列的算法,该算法由著名信息学大师维特比提出,所以叫做维特比算法(viterbi algorithm),这其实是一个解码的过程。维特比算法依然利用动态规划,时间复杂度跟前向算法相同,最大的区别有两个:1.求和变为取最大值,即计算问题变为最优化问题 2.增加了回溯,利用一个前驱数组,记录了每条最优(也就是概率最大)的子隐藏状态序列的每个节点的前驱。java程序如下:

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 + " ");
}
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值