您的位置:首页 > 编程语言 > Java开发

通用维特比算法的Java实现

2016-07-24 14:31 411 查看


用Java实现的求解HMM的维特比算法,开源在Git上:https://github.com/hankcs/Viterbi。代码本身没什么新意,看到Git上没有好用的Viterbi的Java实现,所以补个缺。特点是简单好懂,一个方法搞定。调用简单,往compute方法里填充HMM的五元组就能得到最佳标注序列。

附赠一个对经典天气预测问题的求解,问题的描述和思路详见前文:

package com.hankcs.algorithm;

import static com.hankcs.algorithm.Main.Weather.*;

import static com.hankcs.algorithm.Main.Activity.*;

public class Main

{

static enum Weather

{

Rainy,

Sunny,

}

static enum Activity

{

walk,

shop,

clean,

}

static int[] states = new int[]{Rainy.ordinal(), Sunny.ordinal()};

static int[] observations = new int[]{walk.ordinal(), shop.ordinal(), clean.ordinal()};

static double[] start_probability = new double[]{0.6, 0.4};

static double[][] transititon_probability = new double[][]{

{0.7, 0.3},

{0.4, 0.6},

};

static double[][] emission_probability = new double[][]{

{0.1, 0.4, 0.5},

{0.6, 0.3, 0.1},

};

public static void main(String[] args)

{

int[] result = Viterbi.compute(observations, states, start_probability, transititon_probability,

emission_probability);

for (int r : result)

{

System.out.print(Weather.values()[r] + " ");

}

System.out.println();

}

}

输出:Sunny Rainy Rainy



顺便贴一个源码:

package com.hankcs.algorithm;

/**

* 维特比算法

* @author hankcs

*/

public class Viterbi

{

/**

* 求解HMM模型

* @param obs 观测序列

* @param states 隐状态

* @param start_p 初始概率(隐状态)

* @param trans_p 转移概率(隐状态)

* @param emit_p 发射概率 (隐状态表现为显状态的概率)

* @return 最可能的序列

*/

public static int[] compute(int[] obs, int[] states, double[] start_p, double[][] trans_p, double[][] emit_p)

{

double[][] V = new double[obs.length][states.length];

int[][] path = new int[states.length][obs.length];

for (int y : states)

{

V[0][y] = start_p[y] * emit_p[y][obs[0]];

path[y][0] = y;

}

for (int t = 1; t < obs.length; ++t)

{

int[][] newpath = new int[states.length][obs.length];

for (int y : states)

{

double prob = -1;

int state;

for (int y0 : states)

{

//我加的注释:V[t,隐状态Sj] = V[t-1,隐状态Si] * trans_p(隐状态Si->隐状态Sj)
* emit_p(obs[t] |

隐状态Si)

double nprob = V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]];

if (nprob > prob)

{

prob = nprob;

state = y0;

// 记录最大概率

V[t][y] = prob;

// 记录路径

System.arraycopy(path[state], 0, newpath[y], 0, t);

newpath[y][t] = y;

}

}

}

path = newpath;

}

double prob = -1;

int state = 0;

for (int y : states)

{

if (V[obs.length - 1][y] > prob)//我加的注释:最后一步v值决定最大可能隐状态序列

{

prob = V[obs.length - 1][y];

state = y;

}

}

return path[state];

}

}

对,你没看错,就这么点代码

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息