介绍

结巴分词是一个受大家喜爱的分词库,源码地址为github,今天我们就跟进源码,看一下结巴分词的原理

原理

def cut(self, sentence, cut_all=False, HMM=True):

'''The main function that segments an entire sentence that containsChinese characters into separated words.Parameter:- sentence: The str(unicode) to be segmented.- cut_all: Model type. True for full pattern, False for accurate pattern.- HMM: Whether to use the Hidden Markov Model.'''

使用结巴分词的时候,有三种模式,这三种模式的进入条件分别为:

if cut_all:

cut_block = self.__cut_all

elif HMM:

cut_block = self.__cut_DAG

else:

cut_block = self.__cut_DAG_NO_HMM

首先我们看一下这三种模式__cut_all:原句:我来到北京清华大学 结果:我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学

原句:他来到了网易杭研大厦 结果:他/ 来到/ 了/ 网易/ 杭/ 研/ 大厦

__cut_DAG:原句:我来到北京清华大学 结果:我/ 来到/ 北京/ 清华大学

原句:他来到了网易杭研大厦 结果:他/ 来到/ 了/ 网易/ 杭研/ 大厦

__cut_DAG_NO_HMM:原句:我来到北京清华大学 结果:我/ 来到/ 北京/ 清华大学

原句:他来到了网易杭研大厦 结果:他/ 来到/ 了/ 网易/ 杭/ 研/ 大厦

下面我们就来分析一下这三种模式:

这三种模式有一个共同点,第一步都是先构造DAG,也就是构造有向无环图。

源码如下:

def get_DAG(self, sentence):

self.check_initialized()

DAG = {}

N = len(sentence)

for k in xrange(N):

tmplist = []

i = k

frag = sentence[k]

while i < N and frag in self.FREQ:

if self.FREQ[frag]:

tmplist.append(i)

i += 1

frag = sentence[k:i + 1]

if not tmplist:

tmplist.append(k)

DAG[k] = tmplist

return DAG

如果sentence是'我来到北京清华大学‘,那么DAG为

{0: [0], 1: [1, 2], 2: [2], 3: [3, 4], 4: [4], 5: [5, 6, 8], 6: [6, 7], 7: [7, 8], 8: [8]}

直观上来看,DAG[5]=[5,6,8]的意思就是,以’清‘开头的话,分别以5、6、8结束时,可以是一个词语,即’清‘、’清华‘、’清华大学‘

get_DAG方法中,最重要的也就是self.FREQ了,它是怎么来的呢?

其实就是通过jieba目录下,dict.txt文件来产生的self.FREQ,方法如下:

dict.txt共有349046行,每一行格式为:

一 217830 m

一一 1670 m

一一二 11 m

一一例 3 m

一一分 8 m

一一列举 34 i

第一部分为词语,第二部分为该词出现的频率,第三部分为该词的词性。

以读取’一一列举‘为例子,首先执行self.FREQ['一一列举']=34,然后会检查’一‘、’一一‘、’一一列‘、’一一列举‘之前是否在self.FREQ中存储过,如果之前存储过,则跳过,否则执行self.FREQ['一']=0,self.FREQ['一一']=0,self.FREQ['一一列']=0

所以self.FREQ中不止存储了正常的词语和它出现的次数,同时也存储了所有词语的前缀,并将前缀出现的次数设置为0,以和正常词语区别开。

好了,现在DAG这部分我们介绍完了,然后我们分开来介绍一下这三种模式:

__cut_all

源码如下:

def __cut_all(self, sentence):

dag = self.get_DAG(sentence)

old_j = -1

for k, L in iteritems(dag):

if len(L) == 1 and k > old_j:

yield sentence[k:L[0] + 1]

old_j = L[0]

else:

for j in L:

if j > k:

yield sentence[k:j + 1]

old_j = j

这个具体的遍历方式我们就不细说了,大家自行看源码吧

__cut_DAG

def __cut_DAG(self, sentence):

DAG = self.get_DAG(sentence)

route = {}

self.calc(sentence, DAG, route)

......

首先我们先看一下self.calc方法

def calc(self, sentence, DAG, route):

N = len(sentence)

route[N] = (0, 0)

logtotal = log(self.total)

for idx in xrange(N - 1, -1, -1):

route[idx] = max((log(self.FREQ.get(sentence[idx:x + 1]) or 1) -

logtotal + route[x + 1][0], x) for x in DAG[idx])

这里使用了一个技巧,也就是log(a) + log(b) = log(ab),从而巧妙的避过了乘法,也就避免了溢出的风险。

其实calc函数就是实现了vertibi算法,不了解vertibi算法的同学自行百度吧。

然后再贴上整个__cut_DAG的源码:

def __cut_DAG(self, sentence):

DAG = self.get_DAG(sentence)

route = {}

self.calc(sentence, DAG, route)

x = 0

buf = ''

N = len(sentence)

while x < N:

y = route[x][1] + 1

l_word = sentence[x:y]

if y - x == 1:

buf += l_word

else:

if buf:

if len(buf) == 1:

yield buf

buf = ''

else:

if not self.FREQ.get(buf):

recognized = finalseg.cut(buf)

for t in recognized:

yield t

else:

for elem in buf:

yield elem

buf = ''

yield l_word

x = y

if buf:

if len(buf) == 1:

yield buf

elif not self.FREQ.get(buf):

recognized = finalseg.cut(buf)

for t in recognized:

yield t

else:

for elem in buf:

yield elem

其中,重点关注这一部分

if not self.FREQ.get(buf):

recognized = finalseg.cut(buf)

for t in recognized:

yield t

什么时候会进入finalseg.cut(buf)呢?实际上,就是当遇到一些dict.txt中没出现的词的时候,才会进入这个函数:

在这个函数中,就是使用HMM的方法,对这些未识别成功的词进行标注,然后我们来介绍一下项目中相关的内容:

其中,prob_start.py存储的是HMM的起始状态相关的信息,文件中的数字都经过log处理过:

P={'B': -0.26268660809250016,

'E': -3.14e+100,

'M': -3.14e+100,

'S': -1.4652633398537678}

B代表begin,E代表end,M代表middle,S代表single。所以在开始时,HMM的状态只可能是S或者B,而E和M为负无穷

prob_trans.py存储的是状态转移矩阵:

P={'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}}

prob_emit.py中存储的是在该状态下出现该汉字的概率,例如p('刘'|S)=-0.916

P={'B': {'\u4e00': -3.6544978750449433,

'\u4e01': -8.125041941842026,

'\u4e03': -7.817392401429855,

'\u4e07': -6.3096425804013165,

'\u4e08': -8.866689067453933,

'\u4e09': -5.932085850549891,

'\u4e0a': -5.739552583325728,

'\u4e0b': -5.997089097239644,

'\u4e0d': -4.274262055936421,

'\u4e0e': -8.355569307500769,

......

通过这种方式,也就可以进行分词了。

‘我/ 来到/ 北京/ 清华大学’对应的状态应该为'SBEBEBMME'

__cut_DAG_NO_HMM

其实__cut_DAG_NO_HMM和__cut_DAG的区别就是:对vertibi未成功切分的部分,__cut_DAG_NO_HMM没有使用HMM进行分词。源码如下:

def __cut_DAG_NO_HMM(self, sentence):

DAG = self.get_DAG(sentence)

route = {}

self.calc(sentence, DAG, route)

x = 0

N = len(sentence)

buf = ''

while x < N:

y = route[x][1] + 1

l_word = sentence[x:y]

if re_eng.match(l_word) and len(l_word) == 1:

buf += l_word

x = y

else:

if buf:

yield buf

buf = ''

yield l_word

x = y

if buf:

yield buf

buf = ''每日答答-程序员问答分享平台-快人一步,解决程序员问题​1024dada.com

python分词原理_结巴分词原理相关推荐

  1. 结巴分词python安装_“结巴”分词:做最好的Python分词组件

    python 结巴分词学习 https://www.toutiao.com/a6643201326710784520/ 2019-01-06 10:14:00 结巴分词(自然语言处理之中文分词器) j ...

  2. python100例 分词-Python中文分词工具之结巴分词用法实例总结【经典案例】

    本文实例讲述了Python中文分词工具之结巴分词用法.分享给大家供大家参考,具体如下: 结巴分词工具的安装及基本用法,前面的文章<Python结巴中文分词工具使用过程中遇到的问题及解决方法> ...

  3. 结巴分词优点_中文分词概述及结巴分词原理

    词是中文表达语义的最小单位,中文分词是中文文本处理的一个基础步骤,分词的结果对中文信息处理至为关键. 本文先对中文分词方法进行概述,然后简单介绍结巴分词背后的原理. 1. 中文分词概述 中文分词根据实 ...

  4. 结巴分词 java 权重_结巴分词原理介绍

    转自一个很不错的博客,结合自己的理解,记录一下.作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 结巴分词的原理,结 ...

  5. python中文分词工具_结巴中文分词工具的安装使用 Python分词教程

    结巴分词 中文分词是中文文本处理的一个基础性工作,结巴分词利用进行中文分词.其基本实现原理有三点: 1.基于Trie树结构实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图(DAG) ...

  6. python结巴分词实例_python 结巴分词(jieba)详解

    "结巴"中文分词:做最好的 Python 中文分词组件 "Jieba" (Chinese for "to stutter") Chinese ...

  7. hmm 求隐藏序列_结巴分词3--基于汉字成词能力的HMM模型识别未登录词

    1 算法简介 在结巴分词2--基于前缀词典及动态规划实现分词 博文中,博主已经介绍了基于前缀词典和动态规划方法实现分词,但是如果没有前缀词典或者有些词不在前缀词典中,jieba分词一样可以分词,那么j ...

  8. 结巴分词 java 权重_结巴分词 (转载)

    转自一个很不错的博客,结合自己的理解,记录一下. 作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! https:// ...

  9. python结巴分词代码_python结巴分词SEO的应用详解

    本帖最后由 为人生而奋斗 于 2019-10-15 16:19 编辑 结巴分词在SEO中可以应用于分析/提取文章关键词.关键词归类.标题重写.文章伪原创等等方面,用处非常多. 具体结巴分词项目:htt ...

  10. mysql使用结巴语句_结巴分词 java 高性能实现,是 huaban jieba 速度的 2倍

    Segment Segment 是基于结巴分词词库实现的更加灵活,高性能的 java 分词实现. 创作目的 分词是做 NLP 相关工作,非常基础的一项功能. jieba-analysis 作为一款非常 ...

最新文章

  1. Pygame介绍以及下载
  2. Qt修炼手册4_信号与槽
  3. delphi TWebBrowser组件使用详解
  4. SAP CRM Fiori应用My Lead的常见问题和解答
  5. 笨办法学习@ConditionalOnProperty 烧脑配置记录
  6. 基于springboot的疫情网课教学平台
  7. c语言仿宋gb2312字体,仿宋gb2312字体官方下载|仿宋gb2312字体下载官方版 - 维维软件园...
  8. 读取cpu温度的api_获取传感器温度-cpu 温度篇
  9. 阿里巴巴淘宝网电子商务模式调查分析
  10. 概率论大作业C语言验证正态分布的数学期望和方差
  11. Hadoop报错Permissions incorrectly set for dir /tmp/hadoop-LeiHanhan/nm-local-dir/filecache, should be
  12. php中array_unshift,php中array_unshift()修改数组key注意事项分析
  13. 手机拍的照片计算机内存不足怎么办,手机内存不够用,照片应该怎么处理才能够少占用内存?...
  14. MathType安装和解决不能Crtl+V的问题
  15. 读了冯唐老师的成事心法
  16. LabVIEW基础-图形和图表
  17. 达内html5,达内html5培训:5网页设计让用户浏览下去
  18. 禅道集成极狐gitlab #JIHULAB101
  19. 极客大学产品经理训练营:数据分析与商业分析,商业分析到业务分析 第18课总结
  20. java开发网站学年论文,《Java程序设计》教学网站的设计【毕业论文】.doc

热门文章

  1. c语言同余法随机数,线性同余法取随机数
  2. 联想笔记本计算机在哪里找不到,联想笔记本电脑找不到WLAN怎么解决
  3. matlab基于瑞利信道,一种基于MATLAB的瑞利信道仿真方法研究
  4. 软件工程导论作业2.4
  5. tourex旅游系统 php,TourEx 旅游电商系统B2C_B2B2C v7.0升级V8.0 旅游源码系统无限制版源码工程源码...
  6. X.U.S.T的《自己搭建IIS找ASP程序漏洞》发表在《黑客X档案》,稿费捐给希望工程
  7. SocksCapV2+Socks2HTTP
  8. c++整人小程序(附源码)
  9. win10 安装sqlserver2000
  10. windows10安装adb/fastboot教程