中文分词之HMM模型详解

文章转载自: http://yanyiwu.com/work/2014/04/07/hmm-segment-xiangjie.html

HMM(Hidden Markov Model): 隐式马尔科夫模型。

HMM模型可以应用在很多领域,所以它的模型参数描述一般都比较抽象,以下篇幅针对HMM的模型参数介绍直接使用它在中文分词中的实际含义来讲:

HMM的典型介绍就是这个模型是一个五元组:

  • StatusSet: 状态值集合
  • ObservedSet: 观察值集合
  • TransProbMatrix: 转移概率矩阵
  • EmitProbMatrix: 发射概率矩阵
  • InitStatus: 初始状态分布

HMM模型可以用来解决三种问题:

  1. 参数(StatusSet, TransProbMatrix, EmitRobMatrix, InitStatus)已知的情况下,求解观察值序列。(Forward-backward算法)
  2. 参数(ObservedSet, TransProbMatrix, EmitRobMatrix, InitStatus)已知的情况下,求解状态值序列。(viterbi算法)
  3. 参数(ObservedSet)已知的情况下,求解(TransProbMatrix, EmitRobMatrix, InitStatus)。(Baum-Welch算法)

其中,第三种问题最玄乎也最不常用,第二种问题最常用,【中文分词】,【语音识别】, 【新词发现】, 【词性标注】 都有它的一席之地。所以本文主要介绍第二种问题,即【viterbi算法求解状态值序列】的方法。

五元组参数在中文分词中的具体含义

接下来我们讲实的,不讲虚的,针对中文分词应用,直接给五元组参数赋予具体含义:

StatusSet & ObservedSet

状态值集合为(B, M, E, S): {B:begin, M:middle, E:end, S:single}。分别代表每个状态代表的是该字在词语中的位置,B代表该字是词语中的起始字,M代表是词语中的中间字,E代表是词语中的结束字,S则代表是单字成词。

观察值集合为就是所有汉字(东南西北你我他…),甚至包括标点符号所组成的集合。

状态值也就是我们要求的值,在HMM模型中文分词中,我们的输入是一个句子(也就是观察值序列),输出是这个句子中每个字的状态值。比如:

小明硕士毕业于中国科学院计算所

输出的状态序列为

BEBEBMEBEBMEBES

根据这个状态序列我们可以进行切词:

BE/BE/BME/BE/BME/BE/S

所以切词结果如下:

小明/硕士/毕业于/中国/科学院/计算/所

同时我们可以注意到:

B后面只可能接(M or E),不可能接(B or S)。而M后面也只可能接(M or E),不可能接(B, S)

没错,就是这么简单,现在输入输出都明确了,下文讲讲输入和输出之间的具体过程,里面究竟发生了什么不可告人的秘密,请看下文:

上文只介绍了五元组中的两元【StatusSet, ObservedSet】,下文介绍剩下的三元【InitStatus, TransProbMatrix, EmitProbMatrix】。

这五元的关系是通过一个叫Viterbi的算法串接起来,ObservedSet序列值是Viterbi的输入,而StatusSet序列值是Viterbi的输出,输入和输出之间Viterbi算法还需要借助三个模型参数,分别是InitStatus, TransProbMatrix, EmitProbMatrix,接下来一一讲解:

InitStatus

初始状态概率分布是最好理解的,可以示例如下:

#B
-0.26268660809250016
#E
-3.14e+100
#M
-3.14e+100
#S
-1.4652633398537678

示例数值是对概率值取对数之后的结果(可以让概率相乘的计算变成对数相加),其中-3.14e+100作为负无穷,也就是对应的概率值是0。下同。

也就是句子的第一个字属于{B,E,M,S}这四种状态的概率,如上可以看出,E和M的概率都是0,这和实际相符合,开头的第一个字只可能是词语的首字(B),或者是单字成词(S)。

TransProbMatrix

转移概率是马尔科夫链很重要的一个知识点,大学里面学过概率论的人都知道,马尔科夫链最大的特点就是当前T=i时刻的状态Status(i),只和T=i时刻之前的n个状态有关。也就是:

{Status(i-1), Status(i-2), Status(i-3), ... Status(i - n)}

更进一步的说,HMM模型有三个基本假设(具体哪三个请看文末备注)作为模型的前提,其中有个【有限历史性假设】,也就是马尔科夫链的n=1。即Status(i)只和Status(i-1)相关,这个假设能大大简化问题。

回过头看TransProbMatrix,其实就是一个4x4(4就是状态值集合的大小)的二维矩阵,示例如下:

矩阵的横坐标和纵坐标顺序是BEMS x BEMS。(数值是概率求对数后的值,别忘了。)

-3.14e+100 -0.510825623765990 -0.916290731874155 -3.14e+100
-0.5897149736854513 -3.14e+100 -3.14e+100 -0.8085250474669937
-3.14e+100 -0.33344856811948514 -1.2603623820268226 -3.14e+100
-0.7211965654669841 -3.14e+100 -3.14e+100 -0.6658631448798212

比如TransProbMatrix[0][0]代表的含义就是从状态B转移到状态B的概率,由

TransProbMatrix[0][0] = -3.14e+100

可知,这个转移概率是0,这符合常理。由状态各自的含义可知,状态B的下一个状态只可能是ME,不可能是BS,所以不可能的转移对应的概率都是0,也就是对数值负无穷,在此记为-3.14e+100

由上TransProbMatrix矩阵可知,对于各个状态可能转移的下一状态,且转移概率对应如下:

#B
#E:-0.510825623765990,M:-0.916290731874155
#E
#B:-0.5897149736854513,S:-0.8085250474669937
#M
#E:-0.33344856811948514,M:-1.2603623820268226
#S
#B:-0.7211965654669841,S:-0.6658631448798212

EmitProbMatrix

这里的发射概率(EmitProb)其实也是一个条件概率而已,根据HMM模型三个基本假设(哪三个请看文末备注)里的【观察值独立性假设】,观察值只取决于当前状态值,也就是:

P(Observed[i], Status[j]) = P(Status[j]) * P(Observed[i]|Status[j])

其中P(Observed[i]|Status[j])这个值就是从EmitProbMatrix中获取。

EmitProbMatrix示例如下:

#B
耀:-10.460283,涉:-8.766406,谈:-8.039065,伊:-7.682602,洞:-8.668696,...
#E
耀:-9.266706,涉:-9.096474,谈:-8.435707,伊:-10.223786,洞:-8.366213,...
#M
耀:-8.47651,涉:-10.560093,谈:-8.345223,伊:-8.021847,洞:-9.547990,....
#S:-10.005820,涉:-10.523076,唎:-15.269250,禑:-17.215160,洞:-8.369527...

虽然EmitProbMatrix也称为矩阵,这个矩阵太稀疏了,实际工程中一般是将上面四行发射转移概率存储为4个Map,详见代码HMMSegment。

到此,已经介绍完HMM模型的五元参数,假设现在手头上已经有这些参数的具体概率值,并且已经加载进来,(也就是有该模型的字典了,详见HMMDict里面的hmm_model.utf8),那么我们只剩下Viterbi这个算法函数,这个模型就算可以开始使用了。所以接下来讲讲Viterbi算法。

HMM中文分词之Viterbi算法

输入样例:

小明硕士毕业于中国科学院计算所

Viterbi算法计算过程如下:

定义变量

二维数组 weight[4][15],4是状态数(0:B,1:E,2:M,3:S),15是输入句子的字数。比如 weight[0][2] 代表 状态B的条件下,出现'硕'这个字的可能性。

二维数组 path[4][15],4是状态数(0:B,1:E,2:M,3:S),15是输入句子的字数。比如 path[0][2] 代表 weight[0][2]取到最大时,前一个字的状态,比如 path[0][2] = 1, 则代表 weight[0][2]取到最大时,前一个字(也就是)的状态是E。记录前一个字的状态是为了使用viterbi算法计算完整个 weight[4][15] 之后,能对输入句子从右向左地回溯回来,找出对应的状态序列。

使用InitStatus对weight二维数组进行初始化

已知InitStatus如下:

#B
-0.26268660809250016
#E
-3.14e+100
#M
-3.14e+100
#S
-1.4652633398537678

且由EmitProbMatrix可以得出

Status(B) -> Observed(小)  :  -5.79545
Status(E) -> Observed(小)  :  -7.36797
Status(M) -> Observed(小)  :  -5.09518
Status(S) -> Observed(小)  :  -6.2475

所以可以初始化 weight[i][0] 的值如下:

weight[0][0] = -0.26268660809250016 + -5.79545 = -6.05814
weight[1][0] = -3.14e+100 + -7.36797 = -3.14e+100
weight[2][0] = -3.14e+100 + -5.09518 = -3.14e+100
weight[3][0] = -1.4652633398537678 + -6.2475 = -7.71276

注意上式计算的时候是相加而不是相乘,因为之前取过对数的原因。

遍历句子计算整个weight二维数组

//遍历句子,下标i从1开始是因为刚才初始化的时候已经对0初始化结束了
for(size_t i = 1; i < 15; i++)
{// 遍历可能的状态for(size_t j = 0; j < 4; j++) {weight[j][i] = MIN_DOUBLE;path[j][i] = -1;//遍历前一个字可能的状态for(size_t k = 0; k < 4; k++){double tmp = weight[k][i-1] + _transProb[k][j] + _emitProb[j][sentence[i]];if(tmp > weight[j][i]) // 找出最大的weight[j][i]值{weight[j][i] = tmp;path[j][i] = k;}}}
}

如此遍历下来,weight[4][15]path[4][15] 就都计算完毕。

确定边界条件和路径回溯

边界条件如下:

对于每个句子,最后一个字的状态只可能是 E 或者 S,不可能是 M 或者 B。

所以在本文的例子中我们只需要比较 weight[1(E)][14]weight[3(S)][14] 的大小即可。

在本例中:

weight[1][14] = -102.492;
weight[3][14] = -101.632;

所以 S > E,也就是对于路径回溯的起点是 path[3][14]

回溯的路径是:

SEBEMBEBEMBEBEB

倒序一下就是:

BE/BE/BME/BE/BME/BE/S

所以切词结果就是:

小明/硕士/毕业于/中国/科学院/计算/所

到此,一个HMM模型中文分词算法过程就阐述完毕了。

也就是给定我们一个模型,我们对模型进行载入完毕之后,只要运行一遍Viterbi算法,就可以找出每个字对应的状态,根据状态也就可以对句子进行分词。

模型的训练问题

以上讲的前提是基于模型来进行切词,也就是假设我们手头上的HMM模型已经是被训练好了的(也就是InitStatus, TransProbMatrix, EmitProbMatrix这三个模型的关键参数都是已知的),没有涉及到这三个参数是如何得到的。这三个参数其实也是基于已分词完毕的语料进行统计计算,计算出相应的频率和条件概率就可以算出这三个参数。具体在此就不讲了。

备注

HMM模型的三个基本假设如下:

  • 有限历史性假设:
P(Status[i]|Status[i-1],Status[i-2],... Status[1]) = P(Status[i]|Status[i-1])
  • 齐次性假设(状态和当前时刻无关):
P(Status[i]|Status[i-1]) = P(Status[j]|Status[j-1])
  • 观察值独立性假设(观察值只取决于当前状态值):
P(Observed[i]|Status[i],Status[i-1],...,Status[1]) = P(Observed[i]|Status[i])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/284405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ArcGIS微课1000例】0035:地图面状符号设计教程

地图符号是表示地图内容的基本手段,它由形状不同、大小不一、色彩有别的图形和文字组成。 地图符号是地图的语言,是一种图形语言。它与文字语言相比较,最大的特点是形象直观,一目了然。 本文讲解ArcGIS中面状符号设计方法。 文章目录 一、新建符号样式二、面状符号设计1. 斜…

MySQL夺命15问,你能坚持到第几问?

前言 MySQL在面试中经常被问到&#xff0c;本文总结了面试中的经典问题。 1. 数据库三大范式是什么&#xff1f; 第一范式&#xff1a;每个列都不可以再拆分。 第二范式&#xff1a;在第一范式的基础上&#xff0c;非主键列完全依赖于主键&#xff0c;而不能是依赖于主键的一部…

ios元素定位

原文地址http://www.cnblogs.com/meitian/p/7373460.html 第一种&#xff1a;通过Appium1.6的Inspector来查看 具体安装方式前面的随笔已经介绍了&#xff1a;http://www.cnblogs.com/meitian/p/7360017.html可以通过定位找到元素xpath或name个人不推荐用这个方法&#xff0c;实…

分治法——循环赛日程表

1、问题描述&#xff1a;有n2^k个远动员选手&#xff0c;设计比赛日程表实现&#xff1a;&#xff08;1&#xff09;每个选手必须与n-1个选手比赛&#xff08;2&#xff09;每个选手一天只比赛一场&#xff08;3&#xff09;比赛共进行n-1天输入&#xff1a;n人输出&#xff1a…

使用 LSM-Tree 思想基于.NET 6.0 C# 写个 KV 数据库(案例版)

文章有点长&#xff0c;耐心看完应该可以懂实际原理到底是啥子。这是一个KV数据库的C#实现&#xff0c;目前用.NET 6.0实现的&#xff0c;目前算是属于雏形&#xff0c;骨架都已经完备&#xff0c;毕竟刚完工不到一星期。当然&#xff0c;这个其实也算是NoSQL的雏形&#xff0c…

35.使用拦截器实现权限验证

转自&#xff1a;https://wenku.baidu.com/view/84fa86ae360cba1aa911da02.html 为了说明此问题&#xff0c;我们建立struts2auth项目&#xff0c;流程图如下&#xff1a; 简短说明&#xff1a;当我们访问main.jsp页面&#xff0c;并试图通过此页面中的链接地址&#xff1a;not…

如何保证缓存和数据库的一致性?

1. 问题分析 2. Cache-Aside 2.1 读缓存 2.2 写缓存 2.3 延迟双删 2.4 如何确保原子性 3. Read-Through/Write-Through 3.1 Read-Through 3.2 Write-Through 4. Write Behind 很多小伙伴在面试的时候&#xff0c;应该都遇到过类似的问题&#xff0c;如何确保缓存和数据库…

Pressed状态和clickable,duplicateParentState的关系

做Android开发的人都用过Selector,可以方便的实现View在不同状态下的背景。不过&#xff0c;相信大部分开发者遇到过和我一样的问题&#xff0c;本文会从源码角度&#xff0c;解释这些问题。 首先&#xff0c;这里简单描述一下&#xff0c;我遇到的问题&#xff1a; 界面上有个…

Hbase笔记4 java操作Hbase

暂无转载于:https://www.cnblogs.com/mrxiaohe/p/6512481.html

【招聘(南京)】 慧咨环球南京研发中心 .NET和Blazor 前端

主要的亮点快速增长的、产品导向型的全球性科技公司设计和开发市场领先的软件解决方案WLB — 工作生活相平衡澳洲排名前五的软件公司混合办公 — 3天在家办公&#xff0c;2天在办公室办公在C#和.NET开发&#xff0c;企业级系统研发&#xff0c;软件工程方面有长期的优秀实践和技…

用Python+Django在Eclipse环境下开发web网站【转】

一、创建一个项目如果这是你第一次使用Django&#xff0c;那么你必须进行一些初始设置。也就是通过自动生成代码来建立一个Django项目--一个Django项目的设置集&#xff0c;包含了数据库配置、Django详细选项设置和应用 特性配置&#xff0c;具体操作步骤如下所示。 1.新建Djan…

[转]数据结构KMP算法配图详解(超详细)

KMP算法配图详解 前言 KMP算法是我们数据结构串中最难也是最重要的算法。难是因为KMP算法的代码很优美简洁干练&#xff0c;但里面包含着非常深的思维。真正理解代码的人可以说对KMP算法的了解已经相当深入了。而且这个算法的不少东西的确不容易讲懂&#xff0c;很多正规的书本…

BGP-MED-2

BGP-MED-2如图&#xff1a;当AS100去往AS300的60、10的网络时&#xff0c;60走R3&#xff0c;10走R1!使用MED属性影响选路&#xff01; R2的配置 bgp 200peer 1.1.1.1 as-number 100 peer 1.1.1.1 ebgp-max-hop 255 peer 1.1.1.1 connect-interface LoopBack0peer 4.4.4.4 as-n…

WPF 实现 Gitee 气泡菜单(一)

WPF 实现 Gitee 气泡菜单&#xff08;一&#xff09;气泡菜单&#xff08;一&#xff09;作者&#xff1a;WPFDevelopersOrg原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40&#xff1b;Visual Studio 2022;项目使用 MIT 开…

[转]LVS负载均衡(LVS简介、三种工作模式、十种调度算法)

一、LVS简介 LVS&#xff08;Linux Virtual Server&#xff09;即Linux虚拟服务器&#xff0c;是由章文嵩博士主导的开源负载均衡项目&#xff0c;目前LVS已经被集成到Linux内核模块中。该项目在Linux内核中实现了基于IP的数据请求负载均衡调度方案&#xff0c;其体系结构如图1…

一张图看懂微软Power BI系列组件

一、Power BI简介 Power BI是微软最新的商业智能&#xff08;BI&#xff09;概念&#xff0c;它包含了一系列的组件和工具。话不多说&#xff0c;直接上图吧&#xff1a; Power BI的核心理念就是让我们用户不需要强大的技术背景&#xff0c;只需要掌握Excel这样简单的工具就能快…

互联网项目总结

2019独角兽企业重金招聘Python工程师标准>>> 从去年年底开始专门被分配到互联网小组做项目&#xff0c;一直想做个总结&#xff0c;但是苦于太贪玩。好吧&#xff0c;借着小组技术交流来一发。这里只对自己新学习的技术或者一些小技巧做简要概述&#xff0c;不做深究…

【ArcGIS微课1000例】0036:分式标注案例教程

【拓展阅读】:【ArcGIS Pro微课1000例】0015:ArcGIS Pro中属性字段分式标注案例教程 文章目录 1. 符号化2. 分式标注1. 符号化 右键数据图层→符号系统,打开符号系统对话框,住符号系统选择【唯一值】,字段1选择NAME。 唯一值标注效果: 2. 分式标注 双击打开图层属性,切…

【转】 ConstraintLayout 完全解析 快来优化你的布局吧

转自&#xff1a; http://blog.csdn.net/lmj623565791/article/details/78011599 本文出自张鸿洋的博客 一、概述 ConstraintLayout出现有一段时间了&#xff0c;不过一直没有特别去关注&#xff0c;也多多少少看了一些文字介绍&#xff0c;多数都是对使用可视化布局拖拽&#…

IoTDB 的C# 客户端发布 0.13.0.7

IoTDB C# Client 0.13.0.7 已经发布&#xff0c; 此版本更新的内容为笔者为Apache-IoTDB-Client-CSharp实现了Ado.Net的兼容层&#xff0c;降低了对IoTDB的使用门槛。于此同时&#xff0c; IoTSharp也开始支持了IoTDB的数据入库&#xff0c;随着晚些时候IoTSharp 2.7 版本的发布…