频道栏目
首页 > 网络 > 云计算 > 正文

结巴中文分词说明

2016-07-27 10:44:53           
收藏   我要投稿

结巴分词介绍

现在开源的中文分词工具,有IK、MMseg4j、THULAC、Ansj、Jieba、HanLP等,其中最近还在更新并维护的,也是目前分词效果比较优秀的要属于Ansj、Jieba、HanLP了。

之前我写过Ansj分词器的介绍说明博客,现在细谈一下Jieba分词的详细思路及其实现过程。

结巴分词主页

结巴分词的github主页地址是:https://github.com/fxsjy/jieba(python版),原作者fxsjy是用python写的,后来有网友写了其他编程语言的版本。

目前官方页面推荐的java版结巴分词地址是:https://github.com/huaban/jieba-analysis(java版),这个java版的结巴分词只有针对搜索引擎分词的功能,我在这个之上做了优化改进,并添加了词性标志功能后,已经pull request 给作者piaolingxue了。

我改进后的结巴分词的java版地址是:https://github.com/shibing624/xmnlp ,该项目还在完善中,欢迎大家fork。

结巴分词简介

特点

支持三种分词模式:

精确模式,试图将句子最精确地切开,适合文本分析;全模式,把句子中所有的可以成词的词语都扫描出来,速度非常快,但是不能解决歧义;搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。支持繁体分词支持自定义词典

算法

基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG) 采用了动态规划查找最大概率路径,找出基于词频的最大切分组合对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法

分词过程

基于Trie树结构实现词图扫描,生成成词情况的有向无环图

Tire树

这个需要先了解trie树的python实现,结巴分词自带了一个叫做dict.txt的词典,里面有2万多条词,包含了词条出现的次数和词性(这个词典是清华大学、中科院等基于2014年人民日报语料等资源训练,词性是国标汉语词性)。这个第一条的trie树结构的词图扫描,说的就是把这2万多条词语,放到一个trie树中,而trie树是有名的前缀树,也就是说一个词语的前面几个字一样,就表示他们具有相同的前缀,就可以使用trie树来存储,具有查找速度快的优势。

你可能会想到把dict.txt中所有的词汇全部删掉,然后再试试结巴能不能分词,结果会发现:结巴依然能够分词,不过分出来的词,大部分的长度为2。这个就是第三条,基于HMM来预测分词了。

DAG有向无环图

这个是后一句的“生成句子中汉字所有可能成词情况所构成的有向无环图”,意思是给定一个句子,要你分词,对这个句子进行生成有向无环图。切分词图是为了消除分词中的歧异,提高切分准确度,需要找出一句话所有可能的词,生成全切分词图。如果对有向无环图想有更深入理解请google。

作者是怎么切分的呢?

根据dict.txt生成trie树对待分词句子,根据dict.txt生成的trie树,生成DAG,实际上通俗的说,就是对待分词句子,根据给定的词典进行查词典操作,生成几种可能的句子切分 DAG是什么?记录了啥呢? jieba(python版)源码中记录的是句子中某个词的开始位置,从0到n-1(n为句子的长度),每个开始位置作为字典的键,value是个list,其中保存了可能的词语的结束位置(通过查字典得到词,开始位置+词语的长度得到结束位置)

举个栗子:

一个简单的DAG: {0:[1,2,3]}

表示0位置开始,在1,2,3位置都是词

就是说0~1,0~2,0~3这三个起始位置之间的字符,在dict.txt中是词语

采用了动态规划查找最大概率路径,找出基于词频的最大切分组合

动态规划

这个在一些大学课程中讲了的,忘记的同学请google,我的博客之前也介绍过动态规划问题。

查找最大概率路径

源码中讲字典在生成trie树的同时,也把每个词的出现次数转换为了频率。动态规划中:

先查找待分词句子中已经切分好的词语,对该词语查找该词语出现的频率(次数/总数),如果没有该词(既然是基于词典查找,应该是有的),就把词典中出现频率最小的那个词语的频率作为该词的频率,也就是说P(某词语)=FREQ.get(‘某词语’,min_freq),然后根据动态规划查找最大概率路径的方法,对句子从右往左反向计算最大概率(一些教科书上可能是从左往右,这里反向是因为汉语句子的重心经常落在后面,就是落在右边,因为通常情况下形容词太多,后面的才是主干,因此,从右往左计算,正确率要高于从左往右计算,这个类似于逆向最大匹配),P(NodeN)=1.0,P(NodeN-1)=P(NodeN)*Max(P(倒数第一个词))…依次类推,最后得到最大概率路径,得到最大概率的切分组合。

对于未登录词,采用了HMM模型,使用了Viterbi算法

未登录词

什么意思?其实就是词典 dict.txt 中没有记录的词。上面说了,把 dict.txt 中的所有词语都删除了,结巴分词一样可以分词,就是说的这个。

怎么做到的?

这个就基于jieba采用的HMM模型了,中文词汇按照BEMS四个状态来标记。

BEMS:

B是开始begin位置

E是end是结束位置

M是middle是中间位置

S是singgle,单独成词的位置

采用了状态为(B,E,M,S)这四种状态来标记中文词语,比如北京可以标注为 BE,即 北/B 京/E,表示“北”是开始位置,“京”是结束位置,“中华民族”可以标注为BMME,就是开始-中间-中间-结束。

概率表

经过对大量语料的训练,得到了finalseg目录下的三个概率表文件(来自结巴项目的issues):

prob_trans.py 位置转换概率,即B(开头),M(中间),E(结尾),S(独立成词)四种状态的转移概率

{‘B’: {‘E’: 0.8518218565181658, ‘M’: 0.14817814348183422},

‘E’: {‘B’: 0.5544853051164425, ‘S’: 0.44551469488355755},

‘M’: {‘E’: 0.7164487459986911, ‘M’: 0.2835512540013088},

‘S’: {‘B’: 0.48617017333894563, ‘S’: 0.5138298266610544}}

P(E|B) = 0.851, P(M|B) = 0.149,说明当我们处于一个词的开头时,下一个字是结尾的概率要远高于下一个字是中间字的概率,符合我们的直觉,因为二个字的词比多个字的词更常见。

prob_emit.py 位置到单字的发射概率,比如P(“和”|M)表示一个词的中间出现“和”这个字的概率

prob_start.py 词语以某种状态开头的概率,其实只有两种:要么是B,要么是S。这个就是起始向量,就是HMM系统的最初模型状态

实际上,BEMS之间的转换有点类似于二元模型,就是两个词之间的转移二元模型考虑一个单词后出现另外一个单词的概率,是N元模型中的一种。

举个栗子:

“中国”之后出现”北京”的概率大于“中国”之后出现“北海”的概率

也就是:中国北京 比 中国北海 出现的概率大些,更有可能是一个词语。

不过,作者这里应该不是用的二元分词模型的,这里的BEMS只提供了单个汉字之间的转换,发射概率,并没有提供粒度更大的,基于词语的发射和转移概率。给定一个待分词的句子,就是观察序列,对HMM(BEMS)四种状态的模型来说,就是为了找到一个最佳的BEMS序列,这个就需要使用viterbi算法来得到这个最佳的隐藏状态序列,具体的python版的viterbi算法请看维基百科的维特比算法。

通过概率表和viterbi算法,就可以得到一个概率最大的BEMS序列,按照B打头,E结尾的方式,对待分词的句子重新组合,就得到了分词结果。

举个栗子:

带分词的句子: “全世界都在学中国话”

BEMS序列: [S,B,E,S,S,S,B,E,S]

把连续的BE凑合到一起得到一个词,单独的S放单,就得到一个分词结果了:

得到全/S 世界/BE 都/S 在/S 学/S 中国/BE 话/S 从而将句子切分为词语。

以上,完成中文分词,对于上面的解释有任何术语不理解,请使用google。

相关TAG标签 中文
上一篇:IBM的蓝色蔓延式创新,用Bluemix“混搭”出个云生态
下一篇:JAVASE初级笔记
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站