最近我在学习自然语言处理,相信大家都知道NLP的第一步就是学分词,但分词≠自然语言处理。现如今分词工具及如何使用网上一大堆。我想和大家分享的是结巴分词核心内容,一起探究分词的本质。

(1)、基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图

什么是DAG(有向无环图)?

例如,句子“去北京大学玩”对应的DAG为{0:[0], 1:[1,2,4], 2:[2], 3:[3,4], 4:[4], 5:[5]}。DAG中{0:[0]}就表示0位置对应的是词,就是说0~0,即“去”这个词在Dict(词典库,里面记录每个词的频次)中是词条。DAG中{1:[1,2,4]},就是表示从1位置开始,在1,2,4位置都是词,就是说1~1、1~2、1~4即“北”“北京”“北京大学”这三个也是词,出现在Dict中。句子“去北京大学玩”的DAG毕竟比较短可以一眼看出来,现在来了另外一个句子“经常有意见分歧”,如何得到它的DAG呢?这时候就得通过代码来实现了。

Dict= {"经常":0.1,"经":0.05,"有":0.1, "常":0.001,"有意见":0.1, "歧":0.001,"意见":0.2,"分歧":0.2,"见":0.05,"意":0.05,"见分歧":0.05,"分":0.1}

def DAG(sentence):

DAG = {} #DAG空字典,用来构建DAG有向无环图

N = len(sentence)

for k in range(N):

tmplist = []

i = k

frag = sentence[k]

while i < N:

if frag in Dict:

tmplist.append(i)

i += 1

frag = sentence[k:i + 1]

if not tmplist:

tmplist.append(k)

DAG[k] = tmplist

return DAG

print(DAG("经常有意见分歧"))

输出:

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

根据dict及其每个词出现的概率,可以得到所有可能出现路径(分词情况),如下图:

DAG的图表示

只要出现的词,就可以分,像“经常有”这个词没出现,就不能把它当做单独一个词分开了,通过运行代码,我们可以得到“经常有意见分歧”的DAG

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

,便于直观理解DAG,我们把问题转化成寻找路径的过程,就如上图表示,从开始到结束,比如我照最上面红线的路径走,可以得到[经常|有|意见|分歧]的分词情况,如果把它们每一步的概率值加起来就是该路径的得分S=0.1+0.1+0.2+0.2=0.6,同理我走其他的路径[经|常|有意见|分歧],它的得分就是S=0.05+.0.001+0.1+0.2=0.351。这就是我们的第一步,通过代码构建出一个sentence的DAG。

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

通过第一步,得到了DAG,同样也可以得到每条路径的得分S,从中找到得分最大的,也就是概率值最大的情况,就是我们要找的分词情况。如果用遍历所有路径的话,找到每个路径然后求出每个S,取出最大的S,当然可以得到我们想要的,但比较蛮力。我们可以试着用动态规划的思路,维特比算法,直接上图

维特比算法的顺序解法

给每个节点编号1~8,开始到结束,f(a)代表该节点的所有得分值,每一步单个的箭头都有其对应的概率值,c(a~b)代表的是a节点到b节点的值,如c(1~3)是“经常”的概率值,为什么有的节点如f(6)有三个值?那是因为6这个节点有三个箭头指向它,也就是说有多少个箭头指向该节点,该节点就有多少个得分值,如分f(3)有2个值、f(4)有一个值......。按1~8的顺序,计算出每个节点的所有得分值,计算后面节点的时候要用到前面节点得分值都取(max)最大的,以保证最后计算到f(8)时是全局的最大值,例如计算f(4)中f(3)取的就是0.1。算到最后,我们知道f(8)=f(6) +c(6~8) =0.4+0.2=0.6 (max),接着把f(6)展开,f(8)=f(4) +c(4~6) +c(6~8) ,同理,把所有的f()换成c(),f(8)=c(1~3) +c(3~4) +c(4~6) +c(6~8) 。直到等式右边没有f(),c(1~3)、c(3~4)、c(4~6)、c(6~8)分别代表啥各位看图去吧。

回到开始,假如用蛮力一个一个列出所有路径,不累死也得列的头晕,用动态规划的思想可以把一个大问题拆分到每一步的小问题,下一步的小问题只需要在之前的小问题上再进一步,动态规划的思想就像是小问题站巨人肩膀上,然后大问题莫名其妙就解决了。刚说的是从开始到结束的顺序解法,要是从8节点到1节点逆序解法怎么解?

维特比算法的逆序解法

发现没,最后最大都是0.6=f(1)=c(1~3) +c(3~4) +c(4~6) +c(6~8),而且直接都是看出来了,再一次说明了最大的路径就是这条路径。说了这么多,上代码

sentence ="经常有意见分歧"

N=len(sentence)

route={}

route[N] = (0, 0)

DAG={0: [0, 1], 1: [1], 2: [2, 4], 3: [3, 4], 4: [4, 6], 5: [5, 6], 6: [6]}

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

distance = (((Dict.get(sentence[idx:x + 1]) or 0) + route[x + 1][0], x) for x in DAG[idx])

route[idx] = max(distance)

# 列表推倒求最大概率对数路径

# route[idx] = max([ (概率值,词语末字位置) for x in DAG[idx] ])

# 以idx:(概率最大值,词语末字位置)键值对形式保存在route中)

# route[x+1][0] 表示 词路径[x+1,N-1]的最大概率值,

# [x+1][0]即表示取句子x+1位置对应元组(概率对数,词语末字位置)的概率对数

print(route)

输出结果:

{7: (0, 0), 6: (0.001, 6), 5: (0.2, 6), 4: (0.25, 4), 3: (0.4, 4), 2: (0.5, 2), 1: (0.501, 1), 0: (0.6, 1)}

这是一个自底向上的动态规划(逆序的解法),从sentence的最后一个字开始倒序遍历每个分词方式的得分。然后将得分最高的情况以(概率得分值,词语最后一个字的位置)这样的tuple保存在route中。看route的0: (0.6, 1)中的0.6,不就是我们求到的f(1)的max, 1: (0.501, 1)中的0.501不就是f(2)......后面大家对着看图找规律吧。最后小操作一波,就可以把我们要的分词结果打印出来了,结果和手推的是一样的c(1~3) +c(3~4) +c(4~6) +c(6~8)。

x = 0

segs = []

while x < N:

y = route[x][1] + 1

word = sentence[x:y]

segs.append(word)

x = y

print(segs)

#输出结果:['经常', '有', '意见', '分歧']

上面只是一些核心的思路,好多地方可以继续优化的,比如把概率值转换成-log(概率值),目的是为了防止下溢问题,只是我举例的概率值比较大,如果是一个超大的Dict,为了保证所有词的概率之和约等于1,那每个词对应的概率值会特别小。

(3)中文分词以后得攻克的难点

1、分词的规范,词的定义还不明确,没有一个公认的、权威的标准。

2、歧义词的切分。这也从侧面证实了中华文化博大精深。

3、未登录的新词。就是咱们的Dict里没有的词,对于3这个比2对分词的影响大多了,目前结巴分词对此采取的方法是:基于汉字成词能力的HMM模型,使用维特比算法。

参考:

1、贪心学院nlp

2、自然语言处理理论与实战 唐聃

维特比算法 python_维特比算法 实现中文分词 python实现相关推荐

  1. 维特比算法 python_维特比算法理解与实现(Python)

    前言 写这篇文章就是想以通俗易懂的方式解析维特比算法,最后给出Python代码的实现.下面的公式和原理均出自<统计学习方法>. 算法的原理 算法的原理1.PNG 算法的原理2.PNG 上面 ...

  2. 哈希算法python_哈希算法(Python代码实现)

    1.常见的数据查找算法: 众所周知,顺序查找是最简单的查找方式,但要将所有数据遍历一遍所以效率相对较低,对大数据量的査找问题显然不行.二分查找的查找效率虽然非常高但是数据必须有序,而对数据排序通常需要 ...

  3. 逻辑回归算法python_逻辑回归算法原理和例子

    本课程讲解现在工业界和学术界流行的机器学习算法的相关知识,以及如何用python去实现这些算法.算法的讲解包括supervised learning(有监督式学习)和unsupervised lear ...

  4. 蚂蚁算法python_蚁群算法python编程实现

    前言 这篇文章主要介绍了Python编程实现蚁群算法详解,涉及蚂蚁算法的简介,主要原理及公式,以及Python中的实现代码,具有一定参考价值,需要的朋友可以了解下. 蚁群算法简介 蚁群算法(ant c ...

  5. 人工蜂群算法python_人工蜂群算法简介与程序分析

    目前人工蜂群算法主要分为基于婚配行为与基于釆蜜行为两大类,本文研究的是基于釆蜜行为的人工蜂群算法. 蜜蜂采蜜 自然界中的蜜蜂总能在任何环境下以极高的效率找到优质蜜源,且能适应环境的改变.蜜蜂群的采蜜系 ...

  6. 自动寻路算法python_关于Dijkstra算法和其他的一些图算法(Johnson, Floyd-Warshall, A*)解决最短路径问题的方法的Python实现。...

    这篇文章其实主要想说的是如何解决最短路径的问题. 其实最短路径问题,我们在生活中都在不知不觉的使用.比如我们在上网的时候,互联网传输采用了各种各样的数据包路由方法.这些路由算法都在幕后工作. 还有一些 ...

  7. 人工鱼群算法python_蚁群算法、免疫优化算法、鱼群算法 Python 库

    github地址guofei9987/scikit-opt​github.com 安装 $pip install scikit-opt 蚁群算法(ACA, Ant Colony Algorithm) ...

  8. 花朵授粉算法python_花授粉算法的研究及应用

    摘要: 植物花授粉算法是根据自然界中植物花朵授粉行为机理进行模拟而设计的一种新型启发式优化算法,算法的局部搜索和全局搜索过程分别模拟自花授粉和异花授粉行为,并通过随机扰动来均衡算法局部搜索和全局搜索过 ...

  9. 维特比算法 python_维特比算法实现分词

    维特比算法原理可以参考以下文章,讲解的非常详细,那么接下来将讲解维特比算法如何应用到分词算法中,并如何用python代码实现.如何通俗地讲解 viterbi 算法?​www.zhihu.com 一.过 ...

最新文章

  1. 用CocoaPods做iOS程序的依赖管理
  2. 各互联网公司面试题整理
  3. AnimatorController即动画控制器创建的BUG
  4. Lottery Gym - 102822L
  5. (三十一)web 开发基础项目
  6. idea package自动生成_IDEA自动生成pojo实体类模板
  7. HDU1265 Floating Point Presentation【水题】
  8. ICE专题:编译环境构建
  9. 关于console.log() 打印得引用类型得数据得相关问题
  10. 【代码保留】IP地址排序(字符串分隔补齐)
  11. Tomcat内存溢出,解决方法
  12. 经典单片机课程设计题目大全【大学教授珍藏资料】
  13. OpenCV身份证离线识别技术实战(一)
  14. hover和active的区别
  15. 前端安全须知(淘宝)
  16. Vue 的身份证 手机号码 电话号码 邮箱等校验
  17. 真实机下 ubuntu 18.04 安装anaconda+cuDNN+pytorch以及其版本选择(亲测非常实用)
  18. Python 判断三位水仙花数
  19. 应聘简历/邮件怎样写
  20. 为什么软件测试工程师跳槽,越跳越值钱。嘎嘎涨薪

热门文章

  1. C++不允许使用不完整的类型说明
  2. CSDN中markdown编辑器如何实现首行缩进
  3. Android 用于视频回放显示时间刻度的一个自定义View
  4. 灰色产业链带来的合法正当的行业收入
  5. unity快速开发问答游戏(二)
  6. PPT光效属于计算机几级,PPT高大上的秘密,只有一个字:光!
  7. OC7141 PWM 调光的线性降压 LED恒流驱动IC
  8. Windows Socket套接字(四)-Windows套接字错误代码
  9. 【Guacamole中文文档】二、用户指南 —— 4.代理Guacamole
  10. guacamole1.4.0安装记录