NLP-基础任务-中文分词算法(1)-基于词典: 机械分词(词典字符串匹配):前向最大匹配、后向最大匹配、双向最大匹配【OOV:基于现有词典,不能进行新词发现处理】
分词与NLP关系:分词是中文自然语言处理的基础,没有中文分词,我们对语言很难量化,进而很能运用数学的知识去解决问题。对于拉丁语系是不需要分词的。
拉丁语系与亚系语言区别
- 拉丁语言系不需要分词,因为他们的词语之间有空格分割,可以根据空格就可以把单词分开。比如英语、法语等。
- 亚系语言中间没有空格,比如中文、韩文及日文等。因此需要
分词。
什么是中文分词:中文分词(Chinese Word Segmentation) 指的是将一个汉字序 列切分成一个一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。
任何分词算法都是基于已有词典库来对一句话进行分词。
一、前向最大匹配算法
正向最大匹配法,对于输入的一段文本从左至右、以贪心的方式切分出当前位置上长度最大的词。正向最大匹配法是基于词典的分词方法,其分词原理是:单词的颗粒度越大,所能表示的含义越确切。
该算法主要分两个步骤:
- 一般从一个字符串的开始位置,选择一个最大长度的词长的片段,如果序列不足最大词长,则选择全部序列。
- 首先看该片段是否在词典中,如果是,则算为一个分出来的词,如果不是,则从右边开始,减少一个字符,然后看短一点的这个片段是否在词典中,依次循环,逐到只剩下一个字。
- 序列变为第2步骤截取分词后,剩下的部分序列
例子:“南京市长江大桥”
词典:[“南京”,“市长”,“大桥”,“长江”,“江”,“市”]
前向最大匹配的前向意思是说,从前往后匹配。最大意思是说,我们匹配的词的长度越大越好,也就是这句话中分出来的词的数量越少越好。
这里,我们假设这个最大长度max_len = 5:
第一轮搜索:
①"南京市长江
大桥" ,词典中没有南京市长江
这个词,匹配失败
②"南京市长
江大桥" , 词典中没有南京市长
这个词,匹配失败
③"南京市
长江大桥" , 词典中没有南京市
这个词,匹配失败
④"南京
市长江大桥" , 词典中有南京
这个词,匹配成功,去除
句子变为:“市长江大桥”
第二轮搜索:
①"市长江大桥
" ,词典中没有市长江大桥
这个词,匹配失败
②"市长江大
桥" ,词典中没有市长江大
这个词,匹配失败
③"市长江
大桥" , 词典中没有市长江
这个词,匹配失败
④"市长
江大桥" ,词典中有市长
这个词,匹配成功,去除
句子变为:“江大桥”
第三轮搜索(句子长度已不足5,将max_len改为3):
①"江大桥
" ,词典中没有江大桥
这个词,匹配失败
②"江大
桥" ,词典中没有江大
这个词,匹配失败
③"江
大桥" ,词典中有江
这个词,匹配成功,去除
句子变为:“大桥”
第四轮搜索:
①"大桥" ,词典中有大桥
这个词,匹配成功,去除
句子变为:"",说明已经处理完毕
最终结果:“南京 / 市长 / 江 / 大桥”
这个结果虽然勉强可以接受,可以认为它说的意思是,南京的市长名字叫江大桥,但是明显跟我们想要表达的或者想要理解的意思不一样,这就有了分词的歧义问题。
如果我们的词典里有南京市这个词,那么结果就是"南京市/长江/大桥"。
dictionaries = ["南京", "市长", "大桥", "长江", "江", "市"]# 前向最大匹配
def forward_max_matching(text, max_len=5):result = []text_ = textindex = max_lenwhile len(text_) > 0:if index == 0:print("分词失败,词典中没有这个词")return []if text_[:index] in dictionaries:result.append(text_[:index])text_ = text_[index:]index = 5else:index = index - 1return "".join(word + "/" for word in result)
#!/usr/bin/python
# -*- coding: UTF-8 -*-#实现正向匹配算法中的切词方法
def cut_words(raw_sentence,words_dic):#统计词典中最长的词max_length = max(len(word) for word in words_dic)sentence = raw_sentence.strip()#统计序列长度words_length = len(sentence)#存储切分好的词语cut_word_list = []while words_length > 0:max_cut_length = min(max_length, words_length)subSentence = sentence[0 : max_cut_length]while max_cut_length > 0:if subSentence in words_dic:cut_word_list.append(subSentence)breakelif max_cut_length == 1:cut_word_list.append(subSentence)breakelse:max_cut_length = max_cut_length -1subSentence = subSentence[0:max_cut_length]sentence = sentence[max_cut_length:]words_length = words_length - max_cut_length#words = "/".join(cut_word_list)return cut_word_list
二、后向最大匹配算法
后向最大匹配的后向意思是说,从后往前匹配。最大意思同样是说,我们匹配的词的长度越大越好。
例子:“南京市长江大桥”
词典:[“南京”,“市长”,“大桥”,“长江”,“江”,“市”]
这里,我们同样假设这个最大长度max_len = 5:
第一轮搜索:
①"南京市长江大桥
" 词典中没有市长江大桥
这个词,匹配失败
②"南京市长江大桥
" 词典中没有长江大桥
这个词,匹配失败
③"南京市长江大桥
" 词典中没有江大桥
这个词,匹配失败
④"南京市长江大桥
" 词典中有大桥
这个词,匹配成功,去除
句子变为:“南京市长江”
第二轮搜索:
①"南京市长江
" 词典中没有南京市长江
这个词,匹配失败
②"南京市长江
" 词典中没有京市长江
这个词,匹配失败
③"南京市长江
" 词典中没有市长江
这个词,匹配失败
④"南京市长江
" 词典中有长江
这个词,匹配成功,去除
句子变为:“南京市”
第三轮搜索(句子长度已不足5,将max_len改为3):
①"南京市
" 词典中没有南京市
这个词,匹配失败
②"南京市
" 词典中没有京市
这个词,匹配失败
③"南京市
" 词典中有市
这个词,匹配成功,去除
句子变为:“南京”
第四轮搜索:
①"南京
" 词典中有南京
这个词,匹配成功,去除
句子变为:"",说明已经处理完毕
最终结果:“南京 / 市 / 长江 / 大桥”
相同的话,相同的词典,分出来的效果却不一样,导致了歧义问题。
- 前向最大匹配与后向最大匹配 90%的几率分出来的结果一样。
- 统计结果表明,单纯使用后向最大匹配算法的错误率略低于正向最大匹配算法。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#Author bruce#实现逆向最大匹配算法中的切词方法
def cut_words(raw_sentence,words_dic):#统计词典中词的最长长度max_length = max(len(word) for word in words_dic)sentence = raw_sentence.strip()#统计序列长度words_length = len(sentence)#存储切分出来的词语cut_word_list = []#判断是否需要继续切词while words_length > 0:max_cut_length = min(max_length, words_length)subSentence = sentence[-max_cut_length:]while max_cut_length > 0:if subSentence in words_dic:cut_word_list.append(subSentence)breakelif max_cut_length == 1:cut_word_list.append(subSentence)breakelse:max_cut_length = max_cut_length -1subSentence = subSentence[-max_cut_length:]sentence = sentence[0:-max_cut_length]words_length = words_length -max_cut_lengthcut_word_list.reverse()#words = "/".join(cut_word_list)return cut_word_list
# -*- coding: utf-8 -*-
dictionaries = ["南京", "市长", "大桥", "长江", "江", "市"]# 前向最大匹配
def forward_max_matching(text, max_len=5):result = []text_ = textindex = max_lenwhile len(text_) > 0:if index == 0:print("分词失败,词典中没有这个词")return []if text_[:index] in dictionaries:result.append(text_[:index])text_ = text_[index:]index = 5else:index = index - 1return "".join(word + "/" for word in result)# 后向最大匹配
def backward_max_matching(text, max_len=5):result = []text_ = textindex = max_lenwhile len(text_) > 0:if index == 0:print("分词失败,词典中没有这个词")return []# print(text_[-index:])if text_[-index:] in dictionaries:result.insert(0, text_[-index:])# result.append(text_[-index:])text_ = text_[:-index]index = 5else:index = index - 1return "".join(word + "/" for word in result)if __name__ == '__main__':content = "南京市长江大桥"forward_result = forward_max_matching(content)print("forward_result:", forward_result)backward_result = backward_max_matching(content)print("backward_result:", backward_result)
打印结果:
forward_result: 南京/市长/江/大桥/
backward_result: 南京/市/长江/大桥/
三、双向最大匹配算法
双向最大匹配法是将正向最大匹配法得到的分词结果和逆向最大匹配法的到的结果进行比较,从而决定正确的分词方法。
据SunM.S. 和 Benjamin K.T.(1995)的研究表明:
- 中文中90.0%左右的句子, 正向最大匹配法和逆向最大匹配法完全重合且正确,
- 只有大概9.0%的句子两种切分方法得到的结果不一样,但其中必有一个是正确的(歧义检测成功),
- 只有不到1.0%的句子,或者正向最大匹配法和逆向最大匹配法的切分虽重合却是错的,或者正向最大匹配法和逆向最大匹配法切分不同但两个都不对(歧义检测失败)。
这正是双向最大匹配法在实用中文信息处理系统中得以广泛使用的原因所在。
启发式规则:
- 如果正反向分词结果词数不同,则取分词数量较少的那个。
- 如果分词结果词数相同:
- 分词结果相同,就说明没有歧义,可返回任意一个。
- 分词结果不同,返回其中单字较少的那个。
#!/usr/bin/python
# -*- coding: UTF-8 -*-import FMM
import BMM#使用双向最大匹配算法实现中文分词
words_dic = []def init():"""读取词典文件载入词典:return:"""with open("dic/dic.txt","r", encoding="utf8") as dic_input:for word in dic_input:words_dic.append(word.strip())#实现双向匹配算法中的切词方法
def cut_words(raw_sentence,words_dic):bmm_word_list = BMM.cut_words(raw_sentence,words_dic)fmm_word_list = FMM.cut_words(raw_sentence,words_dic)bmm_word_list_size = len(bmm_word_list)fmm_word_list_size = len(fmm_word_list)if bmm_word_list_size != fmm_word_list_size:if bmm_word_list_size < fmm_word_list_size:return bmm_word_listelse:return fmm_word_listelse:FSingle = 0BSingle = 0isSame = Truefor i in range(len(fmm_word_list)):if fmm_word_list[i] not in bmm_word_list:isSame = Falseif len(fmm_word_list[i]) == 1:FSingle = FSingle + 1if len(bmm_word_list[i]) == 1:BSingle = BSingle + 1if isSame:return fmm_word_listelif BSingle > FSingle:return fmm_word_listelse:return bmm_word_listdef main():"""于用户交互接口:return:"""init()while True:print("请输入您要分词的序列")input_str = input()if not input_str:breakresult = cut_words(input_str,words_dic)print("分词结果")print(result)if __name__ == "__main__":main()
参考资料:
NLP-基础任务-中文分词算法(1)-基于词典: 机械分词(词典字符串匹配):前向最大匹配、后向最大匹配、双向最大匹配【OOV:基于现有词典,不能进行新词发现处理】相关推荐
- php 分词搜索算法,分词算法(利用百度搜索分词算法布局关键词,告别堆砌)...
曾经在学习SEO撰写TDK的时候,老师给我们举了一个例子:月饼批发_提供2014月饼批发团购价格-XX月饼批发厂家.当时还不明白标题里包含了百度中文分析算法技术.在源源不断的学习中,才后知后觉这就是传 ...
- nlp基础—8.隐马尔科夫模型(HMM)分词实现
文章目录 引言 HMM分词实现 理论部分传送门: nlp基础-7.隐马尔可夫模型(HMM算法) 数据代码链接见:https://gitee.com/lj857335332/hmm-for-word-s ...
- 入门科普:一文看懂NLP和中文分词算法(附代码举例)
导读:在人类社会中,语言扮演着重要的角色,语言是人类区别于其他动物的根本标志,没有语言,人类的思维无从谈起,沟通交流更是无源之水. 所谓"自然"乃是寓意自然进化形成,是为了区分一些 ...
- 基于感知器的中文分词算法
http://heshenghuan.github.io/2015/12/21/%E5%9F%BA%E4%BA%8E%E6%84%9F%E7%9F%A5%E5%99%A8%E7%9A%84%E4%B8 ...
- 中文分词算法—— 基于词典的方法
1.基于词典的方法(字符串匹配,机械分词方法) 定义:按照一定策略将待分析的汉字串与一个"大机器词典"中的词条进行匹配,若在词典中找到某个字符串,则匹配成功. 按照扫描方向的不同: ...
- 中文分词算法python代码_中文分词算法之最大正向匹配算法(Python版)
最大匹配算法是自然语言处理中的中文匹配算法中最基础的算法,分为正向和逆向,原理都是一样的. 正向最大匹配算法,故名思意,从左向右扫描寻找词的最大匹配. 首先我们可以规定一个词的最大长度,每次扫描的时候 ...
- 正向最大匹配算法 python代码_中文分词算法之最大正向匹配算法(Python版)
最大匹配算法是自然语言处理中的中文匹配算法中最基础的算法,分为正向和逆向,原理都是一样的. 正向最大匹配算法,故名思意,从左向右扫描寻找词的最大匹配. 首先我们可以规定一个词的最大长度,每次扫描的时候 ...
- python最大分词_中文分词算法之最大正向匹配算法(Python版)
最大匹配算法是自然语言处理中的中文匹配算法中最基础的算法,分为正向和逆向,原理都是一样的. 正向最大匹配算法,故名思意,从左向右扫描寻找词的最大匹配. 首先我们可以规定一个词的最大长度,每次扫描的时候 ...
- PHP基于字典的中英文数字混合分词算法RMM简易实现
<?phpclass Seg {//字典private $dict = [];//加载字典function set_dict($vDict){//词典大写,方便比对foreach ($vDict ...
- 11大Java开源中文分词器的使用方法和分词效果对比,当前几个主要的Lucene中文分词器的比较...
本文的目标有两个: 1.学会使用11大Java开源中文分词器 2.对比分析11大Java开源中文分词器的分词效果 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那 ...
最新文章
- 初学python还是swift-零基础如何选择编程语言 小白的我研究了3个月得出一个结论...
- Android之使用ACTION_USAGE_ACCESS_SETTINGS权限检测手机多少天没有未使用其它APP
- iOS5 UI 设计新手段 Storyboard
- 主持人李咏在美国去世 妻子哈文:永失我爱
- foxmail邮件怎样打印日历
- 名片管理系统python详解_Python综合应用名片管理系统案例详解
- 数据库内存泄漏——A SQLiteConnection object for database '/data/data/.../databases/....db' was leaked!...
- 如何在idea中调试spring bean
- mysql 主备心跳监测配置_mysql主备配置
- 360全景拼接 opencv_广州海珠区专业改全景,丰田塞纳改3D全景,360全景行车记录仪的功能...
- Fineui 添加打印控件
- 新唐N76E003AT20PIN对PIN完美替代STM8S003F3P6
- 程序员的你不可不知的数据库northwind
- 出生年分数 15作者 陈越单位 浙江大学
- 100个英语超精简口语短句
- IDEA 2018.3版本Spring Boot 热部署
- 百度小程序SEO指南
- 关于定位一直在香港的解决方式
- html做网页 窗口最小化后,40种网页常用小技巧
- Android输入法架构学习总结