前言

文章标题的两个概念也许对于许多同学们来说都相对比较陌生,都比较偏向于于理论方面的知识,但是这个算法非常的强大,在很多方面都会存在他的影子。2个概念,1个维特比算法,1个隐马尔可夫模型。你很难想象,输入法的设计也会用到其中的一些知识。

HMM-隐马尔可夫模型

隐马尔可夫模型如果真的要展开来讲,那短短的一篇文章当然无法阐述的清,所以我会以最简单的方式解释。隐马尔可夫模型简称HMM,根据百度百科中的描述,隐马尔可夫模型描述的是一个含有隐含未知参数的马尔可夫模型。模型的本质是从观察的参数中获取隐含的参数信息。一般的在马尔可夫模型中,前后之间的特征会存在部分的依赖影响。示例图如下:

隐马尔可夫模型在语音识别中有广泛的应用。其实在输入法中也有用到。举个例子,假设我输入wszs,分别代表4个字,所以观察特征就是w, s, z, s,那么我想挖掘出他所想表达的信息,也就是我想打出的字是什么,可能是"我是张三",又可能是“晚上再说”,这个就是可能的信息,最可能的信息,就会被放在输入选择越靠前的位置。在这里我们就会用到一个叫维特比的算法了。

Viterbi-维特比算法

维特比算法这个名字的产生是以著名科学家维特比命名的,维特比算法是数字通信中非常常用的一种算法。那么维特比算法到底是做什么的呢。简单的说,他是一种特殊的动态规划算法,也就是DP问题。但是这里可不是单纯的寻找最短路径这些问题,可能他是需要寻找各个条件因素下最大概率的一条路径,假设针对观察特征,会有多个隐含特征值的情况。比如下面这个是多种隐含变量的组合情况,形成了一个密集的篱笆网络。

于是问题就转变成了,如何在这么多的路径中找到最佳路径。如果这是输入法的例子,上面的每一列的值就是某个拼音下对应的可能的字。于是我们就很容易联想到可以用dp的思想去做,每次求得相邻变量之间求得后最佳的值,存在下一列的节点上,而不是组合这么多种情况去算。时间复杂度能降低不少。但是在马尔可夫模型中,你还要考虑一些别的因素。所以总的来说,维特比算法就是一种利用动态规划算法寻找最有可能产生观察序列的隐含信息序列,尤其是在类似于隐马尔可夫模型的应用中。

算法实例

下面给出一个实际例子,来说明一下维特比算法到底怎么用,如果你用过动态规划算法,相信一定能很迅速的理解我想表达的意思。下面这个例子讲的是海藻的观察特征与天气的关系,通过观测海藻的特征状态,退出当天天气的状况。当然当天天气的预测还可能受昨天的天气影响,所以这是一个很棒的隐马尔可夫模型问题。问题的描述是下面这段话:

假设连续观察3天的海藻湿度为(Dry,Damp,Soggy),求这三天最可能的天气情况。天气只有三类(Sunny,Cloudy,Rainy),而且海藻湿度和天气有一定的关系。问题具体描述,链接在此

ok,状态转移概率矩阵和混淆矩阵都已给出,详细代码以及相关数据,请点击链接:https://github.com/linyiqun/DataMiningAlgorithm/tree/master/Others/DataMining_Viterbi

直接给出代码解答,主算法类ViterbiTool.java:

package DataMining_Viterbi;import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** 维特比算法工具类* * @author lyq* */
public class ViterbiTool {// 状态转移概率矩阵文件地址private String stmFilePath;// 混淆矩阵文件地址private String confusionFilePath;// 初始状态概率private double[] initStatePro;// 观察到的状态序列public String[] observeStates;// 状态转移矩阵值private double[][] stMatrix;// 混淆矩阵值private double[][] confusionMatrix;// 各个条件下的潜在特征概率值private double[][] potentialValues;// 潜在特征private ArrayList<String> potentialAttrs;// 属性值列坐标映射图private HashMap<String, Integer> name2Index;// 列坐标属性值映射图private HashMap<Integer, String> index2name;public ViterbiTool(String stmFilePath, String confusionFilePath,double[] initStatePro, String[] observeStates) {this.stmFilePath = stmFilePath;this.confusionFilePath = confusionFilePath;this.initStatePro = initStatePro;this.observeStates = observeStates;initOperation();}/*** 初始化数据操作*/private void initOperation() {double[] temp;int index;ArrayList<String[]> smtDatas;ArrayList<String[]> cfDatas;smtDatas = readDataFile(stmFilePath);cfDatas = readDataFile(confusionFilePath);index = 0;this.stMatrix = new double[smtDatas.size()][];for (String[] array : smtDatas) {temp = new double[array.length];for (int i = 0; i < array.length; i++) {try {temp[i] = Double.parseDouble(array[i]);} catch (NumberFormatException e) {temp[i] = -1;}}// 将转换后的值赋给数组中this.stMatrix[index] = temp;index++;}index = 0;this.confusionMatrix = new double[cfDatas.size()][];for (String[] array : cfDatas) {temp = new double[array.length];for (int i = 0; i < array.length; i++) {try {temp[i] = Double.parseDouble(array[i]);} catch (NumberFormatException e) {temp[i] = -1;}}// 将转换后的值赋给数组中this.confusionMatrix[index] = temp;index++;}this.potentialAttrs = new ArrayList<>();// 添加潜在特征属性for (String s : smtDatas.get(0)) {this.potentialAttrs.add(s);}// 去除首列无效列potentialAttrs.remove(0);this.name2Index = new HashMap<>();this.index2name = new HashMap<>();// 添加名称下标映射关系for (int i = 1; i < smtDatas.get(0).length; i++) {this.name2Index.put(smtDatas.get(0)[i], i);// 添加下标到名称的映射this.index2name.put(i, smtDatas.get(0)[i]);}for (int i = 1; i < cfDatas.get(0).length; i++) {this.name2Index.put(cfDatas.get(0)[i], i);}}/*** 从文件中读取数据*/private ArrayList<String[]> readDataFile(String filePath) {File file = new File(filePath);ArrayList<String[]> dataArray = new ArrayList<String[]>();try {BufferedReader in = new BufferedReader(new FileReader(file));String str;String[] tempArray;while ((str = in.readLine()) != null) {tempArray = str.split(" ");dataArray.add(tempArray);}in.close();} catch (IOException e) {e.getStackTrace();}return dataArray;}/*** 根据观察特征计算隐藏的特征概率矩阵*/private void calPotencialProMatrix() {String curObserveState;// 观察特征和潜在特征的下标int osIndex;int psIndex;double temp;double maxPro;// 混淆矩阵概率值,就是相关影响的因素概率double confusionPro;this.potentialValues = new double[observeStates.length][potentialAttrs.size() + 1];for (int i = 0; i < this.observeStates.length; i++) {curObserveState = this.observeStates[i];osIndex = this.name2Index.get(curObserveState);maxPro = -1;// 因为是第一个观察特征,没有前面的影响,根据初始状态计算if (i == 0) {for (String attr : this.potentialAttrs) {psIndex = this.name2Index.get(attr);confusionPro = this.confusionMatrix[psIndex][osIndex];temp = this.initStatePro[psIndex - 1] * confusionPro;this.potentialValues[BaseNames.DAY1][psIndex] = temp;}} else {// 后面的潜在特征受前一个特征的影响,以及当前的混淆因素影响for (String toDayAttr : this.potentialAttrs) {psIndex = this.name2Index.get(toDayAttr);confusionPro = this.confusionMatrix[psIndex][osIndex];int index;maxPro = -1;// 通过昨天的概率计算今天此特征的最大概率for (String yAttr : this.potentialAttrs) {index = this.name2Index.get(yAttr);temp = this.potentialValues[i - 1][index]* this.stMatrix[index][psIndex];// 计算得到今天此潜在特征的最大概率if (temp > maxPro) {maxPro = temp;}}this.potentialValues[i][psIndex] = maxPro * confusionPro;}}}}/*** 根据同时期最大概率值输出潜在特征值*/private void outputResultAttr() {double maxPro;int maxIndex;ArrayList<String> psValues;psValues = new ArrayList<>();for (int i = 0; i < this.potentialValues.length; i++) {maxPro = -1;maxIndex = 0;for (int j = 0; j < potentialValues[i].length; j++) {if (this.potentialValues[i][j] > maxPro) {maxPro = potentialValues[i][j];maxIndex = j;}}// 取出最大概率下标对应的潜在特征psValues.add(this.index2name.get(maxIndex));}System.out.println("观察特征为:");for (String s : this.observeStates) {System.out.print(s + ", ");}System.out.println();System.out.println("潜在特征为:");for (String s : psValues) {System.out.print(s + ", ");}System.out.println();}/*** 根据观察属性,得到潜在属性信息*/public void calHMMObserve() {calPotencialProMatrix();outputResultAttr();}
}

测试结果输出:

观察特征为:
Dry, Damp, Soggy,
潜在特征为:
Sunny, Cloudy, Rainy, 

参考文献

百度百科-隐马尔可夫模型

百度百科-维特比

<<数学之美>>第二版-吴军

http://blog.csdn.net/jeiwt/article/details/8076739

维特比算法在隐马尔可夫模型中的应用相关推荐

  1. viterbi维特比算法和隐马尔可夫模型(HMM)

    阅读目录 隐马尔可夫模型(HMM) 回到目录 隐马尔可夫模型(HMM) 原文地址:http://www.cnblogs.com/jacklu/p/7753471.html 本文结合了王晓刚老师的ENG ...

  2. 隐马尔可夫模型中的Viterbi算法zz

    隐马尔可夫模型中的Viterbi算法zz 这篇文章简单描述一下Viterbi算法--一年之前我听过它的名字,直到两周之前才花了一点时间研究了个皮毛,在这里做个简单检讨.先用一句话来简单描述一下:给出一 ...

  3. 【Python自然语言处理】隐马尔可夫模型中维特比(Viterbi)算法解决商务选择问题实战(附源码 超详细必看)

    需要源码请点赞关注收藏后评论区留言私信~~~ 一.统计分词 统计分词基本逻辑是把每个词语看做由单字组成,利用统计学原理计算连接字在不同文本中出现的次数,以此判断相连字属于特定词语的概率. 二.隐马尔可 ...

  4. 【机器学习算法】隐马尔可夫模型HMM(一)

    目录 一.马尔可夫模型 1. 马尔可夫性 2. 马尔可夫链 3. 马尔可夫链案例 二.隐马尔可夫模型HMM 1. named entity recognition(命名实体识别)问题概述 2. 什么是 ...

  5. 机器学习算法之隐马尔可夫模型

    马尔可夫性质及马尔可夫链 马尔可夫性质 设  是一个随机过程,E为其状态空间,若对于任意的  任意的  ,随机变量X(t) 在已知变量  之下的条件分布函数只与  有关,而与  无关,即条件分布函数满 ...

  6. 机器学习算法之——隐马尔可夫模型(Hidden Markov Models,HMM) 代码实现

    @Author:Runsen 隐形马尔可夫模型,英文是 Hidden Markov Models,就是简称 HMM. 既是马尔可夫模型,就一定存在马尔可夫链,该马尔可夫链服从马尔可夫性质:即无记忆性. ...

  7. 【大道至简】机器学习算法之隐马尔科夫模型(Hidden Markov Model, HMM)详解(3)---学习问题:Baum-Welch算法推导及Python代码实现

    ☕️ 本文系列文章汇总: (1)HMM开篇:基本概念和几个要素 (2)HMM计算问题:前后向算法 (3)HMM学习问题:Baum-Welch算法 (4) HMM预测问题:维特比算法 ☕️ 本文来自专栏 ...

  8. 10_隐马尔科夫模型HMM2_统计学习方法

    文章目录 四.学习算法 1.监督学习方法 2.非监督学习方法(Baum-Welch算法) 五.预测算法 1.近似算法 2.维特比算法 (1)最优路径特性 (2)两个变量 (3)维特比算法流程 隐马尔科 ...

  9. (九)统计学习方法 | 隐马尔可夫模型

    文章目录 1.隐马尔可夫模型 1.1 简介与定义 1.2 观测序列的生成 2. 隐马尔可夫模型的3个基本问题 2.1 概率计算方法 2.1.1 直接计算法 2.1.2 前向算法 2.1.3 后向算法 ...

最新文章

  1. 动画库 Lottie 的使用
  2. Redis事件管理(三)
  3. Flink从入门到精通100篇(十四)-Flink开发IDEA环境搭建与测试
  4. 模拟noj——打扑克
  5. python中代理模式分为几种类型_代理模式
  6. linkedblockingqueue 后 take 不消化_消化不良的成因及护理
  7. 科大讯飞输入法解锁高效语音输入
  8. 实现微信小程序版本管理
  9. access统计班级人数_使用ACCESS查询统计分数段人数
  10. pentaho mysql_pentaho bi server 配置MySQL数据库
  11. 网卡在linux系统下的驱动怎么安装,RedHat Linux系统如何安装无线网卡驱动
  12. 六级听力技巧与备考策略
  13. 划重点!划重点!2022面试必刷461道大厂架构面试真题汇总+面经+简历模板
  14. 我有一壶酒,足以慰风尘
  15. Github清除历史记录的方法
  16. C语言 命令行 execl函数
  17. Python 扫雷游戏 完整源代码+图片素材
  18. logback prudent, SiftingAppender, layout, encoder的使用
  19. 中标麒麟 7 操作系统下安装达梦数据库
  20. 新浪微博终于完成多数ui

热门文章

  1. 嵌入式开发专业术语概念汇总
  2. CCS如何调整字体大小
  3. 关于Java对接读卡器遇到的坑Process finished with exit code -1073740940 (0xC0000374)
  4. 【转载】租房被骗,选择忍让,成就黑中介的猖狂
  5. 密码学 BugKu 这不是摩斯密码
  6. ZBrush中的三种对称类型的完美运用
  7. 用VB.NET写的一个简易的RSS阅读器
  8. React 父子组件的生命周期关系(16.4版本及以后)
  9. Github上的开源工具帮助你实现“十一”回家的愿望
  10. javascript判断常用浏览器版本和类型兼容处理