本次实验内容是基于词典的双向匹配算法的中文分词算法的实现。使用正向和反向最大匹配算法对给定句子进行分词,对得到的结果进行比较,从而决定正确的分词方法。

算法描述
正向最大匹配算法
先设定扫描的窗口大小maxLen(最好是字典最长的单词长度),从左向右取待切分汉语句的maxLen个字符作为匹配字段。查找词典并进行匹配。若匹配成功,则将这个匹配字段作为一个词切分出来,并将窗口向右移动这个单词的长度。若匹配不成功,则将这个匹配字段的最后一个字去掉,剩下的字符串作为新的匹配字段,进行再次匹配,重复以上过程,直到切分出所有词为止。

反向最大匹配算法
该算法是正向的逆向算法,区别是窗口是从后向左扫描,若匹配不成功,则去掉第一个字符,重复上述的匹配步骤。

双向最大匹配算法
双向最大匹配法是将正向最大匹配法得到的分词结果和逆向最大匹配法的到的结果进行比较,从而决定正确的分词方法。定义的匹配规则如下:

如果正反向匹配算法得到的结果相同,我们则认为分词正确,返回任意一个结果即可。
如果正反向匹配算法得到的结果不同,则考虑单字词、非字典词、总词数数量的数量,三者的数量越少,认为分词的效果越好。我们设定一个惩罚分数(score_fmm / score_bmm = 0),例如:正向匹配中单字词数量多于反向匹配,则正向匹配的分值score_fmm += 1。其他两个条件相同。可以根据实际的分词效果调整惩罚分数的大小,但由于没有正确分词的数据,因此惩罚分数都设为1。最后比较惩罚分数,返回较小的匹配结果。

详例描述
以“对外经济技术合作与交流不断扩大。”为例,详细描述算法如下:
窗口大小设为4,句子长度为16,分词列表words = []。

首先是正向匹配。sub_str = ‘对外经济’与词典进行匹配,匹配失败,窗口大小减一。
sub_str = ‘对外经’与词典进行匹配,匹配失败,窗口大小减一。
sub_str = ‘对外’与词典进行匹配,匹配成功,窗口大小恢复为4,向右移动之前匹配词的长度,此时sub_str = ‘经济技术’,将其添加至列表words中。重复上述步骤。
当匹配到最后一个词时,算法停止。
正向匹配结果如下:[‘对外’, ‘经济’, ‘技术’, ‘合作’, ‘与’, ‘交流’, ‘不断’, ‘扩大’, ‘。’]
反向匹配如法炮制,结果如下:[‘对外’, ‘经济’, ‘技术’, ‘合作’, ‘与’, ‘交流’, ‘不断’, ‘扩大’, ‘。’]
正向与反向匹配结果相同,返回任意一个。

代码:

加载字典

def read_dict(path):
words_dict = []
with open(path, 'r') as r:
line = r.readlines()
# print(line)
for i in line:
word = i.split(',')
words_dict.append(word[0])
return words_dict window_size = 4

正向匹配算法

def fmm(source, words_dict):
len_source = len(source) # 原句长度
index = 0
words = [] # 分词后句子每个词的列表 while index < len_source: # 如果下标未超过句子长度
match = False
for i in range(window_size, 0, -1):
sub_str = source[index: index+i]
if sub_str in words_dict:
match = True
words.append(sub_str)
index += i
break
if not match:
words.append(source[index])
index += 1
return words

反向匹配算法

def bmm(source, word_dict):
len_source = len(source) # 原句长度
index = len_source
words = [] # 分词后句子每个词的列表 while index > 0:
match = False
for i in range(window_size, 0, -1):
sub_str = source[index-i: index]
if sub_str in words_dict:
match = True
words.append(sub_str)
index -= i
break
if not match:
words.append(source[index-1])
index -= 1
words.reverse() # 得到的列表倒序
return words

双向匹配算法

def bi_mm(source, word_dict):
forward = fmm(source, words_dict)
backward = bmm(source, words_dict)
# 正反向分词结果
print("FMM: ", forward)
print("BMM: ", backward)
# 单字词个数
f_single_word = 0
b_single_word = 0
# 总词数
tot_fmm = len(forward)
tot_bmm = len(backward)
# 非字典词数
oov_fmm = 0
oov_bmm = 0
# 罚分,罚分值越低越好
score_fmm = 0
score_bmm = 0
# 如果正向和反向结果一样,返回任意一个
if forward == backward:
return backward
# print(backward)
else: # 分词结果不同,返回单字数、非字典词、总词数少的那一个
for each in forward:
if len(each) == 1:
f_single_word += 1
for each in backward:
if len(each) == 1:
b_single_word += 1
for each in forward:
if each not in words_dict:
oov_fmm += 1
for each in backward:
if each not in backward:
oov_bmm += 1
# 可以根据实际情况调整惩罚分值
# 这里都罚分都为1分
# 非字典词越少越好
if oov_fmm > oov_bmm:
score_bmm += 1
elif oov_fmm < oov_bmm:
score_fmm += 1
# 总词数越少越好
if tot_fmm > tot_bmm:
score_bmm += 1
elif tot_fmm < tot_bmm:
score_fmm += 1
# 单字词越少越好
if f_single_word > b_single_word:
score_bmm += 1
elif f_single_word < b_single_word:
score_fmm += 1 # 返回罚分少的那个
if score_fmm < score_bmm:
return forward
else:
return backward

主函数,测试了分词的时间,包括加载词典的时间

if __name__ == '__main__':
start = time.time()
words_dict = read_dict('chineseDic.txt')
# print(bmm("我正在上自然语言处理课。", words_dict))
# print("result: ", result)
print("BiMM: ", bi_mm("对外经济技术合作与交流不断扩大。", words_dict))
end = time.time()
print("running time: " + str(end - start) + "s")

  

分词 | 双向匹配中文分词算法python实现的更多相关文章

  1. Elasticsearch(10) --- 内置分词器、中文分词器

    Elasticsearch(10) --- 内置分词器.中文分词器 这篇博客主要讲:分词器概念.ES内置分词器.ES中文分词器. 一.分词器概念 1.Analysis 和 Analyzer Analy ...

  2. 中文分词接口api,采用结巴分词PHP版中文分词接口

    中文分词,分词就是将连续的字序列按照一定的规范重新组合成词序列的过程.我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字.句和段能通过明显的分界符来简单划界,唯独词没有一个形式上 ...

  3. 关于yaha中文分词(将中文分词后,结合TfidfVectorizer变成向量)

    https://github.com/jannson/yaha # -*- coding: utf-8 -*- """ Created on Wed Aug 10 08: ...

  4. python中文分词:结巴分词

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

  5. [python] 使用Jieba工具中文分词及文本聚类概念

    声明:由于担心CSDN博客丢失,在博客园简单对其进行备份,以后两个地方都会写文章的~感谢CSDN和博客园提供的平台.        前面讲述了很多关于Python爬取本体Ontology.消息盒Inf ...

  6. python 中文分词:结巴分词

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

  7. 自制基于HMM的python中文分词器

    不像英文那样单词之间有空格作为天然的分界线, 中文词语之间没有明显界限.必须采用一些方法将中文语句划分为单词序列才能进一步处理, 这一划分步骤即是所谓的中文分词. 主流中文分词方法包括基于规则的分词, ...

  8. NLP自然语言处理 jieba中文分词,关键词提取,词性标注,并行分词,起止位置,文本挖掘,NLP WordEmbedding的概念和实现

    1. NLP 走近自然语言处理 概念 Natural Language Processing/Understanding,自然语言处理/理解 日常对话.办公写作.上网浏览 希望机器能像人一样去理解,以 ...

  9. 深度学习实战篇-基于RNN的中文分词探索

    深度学习实战篇-基于RNN的中文分词探索 近年来,深度学习在人工智能的多个领域取得了显著成绩.微软使用的152层深度神经网络在ImageNet的比赛上斩获多项第一,同时在图像识别中超过了人类的识别水平 ...

随机推荐

  1. 删除文件linux

    bool LxDeleteFile(const char* src){ int32_t iRe = remove(src); ) return true; else return false; }

  2. 【洛谷5492】[PKUWC2018] 随机算法(状压DP)

    点此看题面 大致题意: 用随机算法求一张图的最大独立集:每次随机一个排列,从前到后枚举排列中的点,如果当前点加入点集中依然是独立集,就将当前点加入点集中,最终得到的点集就是最大独立集.求这个随机算法的 ...

  3. Python深拷贝与浅拷贝区别

    可变类型 如list.dict等类型,改变容器内的值,容器地址不变. 不可变类型 如元组.字符串,原则上不可改变值.如果要改变对象的值,是将对象指向的地址改变了 浅拷贝 对于可变对象来说,开辟新的内存 ...

  4. linux命令--基本权限命令

    一.权限介绍 使用ls命令查看时,发现长格式显示的第一列就是文件的权限 权限位一共有 10 位,这 10 位权限位的含义如下图所示. 第 1 位代表文件类型.Linux 不像 Windows 使用扩展 ...

  5. 函数式接口 & lambda表达式 & 方法引用

    拉呱: 终于,学习jdk8的新特性了,初体验带给我的感觉真爽,代码精简的不行,可读性也很好,而且,spring5也是把jdk8的融入到血液里,总之一句话吧,说的打趣一点,学的时候自己难受,学完了写出来 ...

  6. React躬行记(12)——Redux中间件

    Redux的中间件(Middleware)遵循了即插即用的设计思想,出现在Action到达Reducer之前(如图10所示)的位置.中间件是一个固定模式的独立函数,当把多个中间件像管道那样串联在一起时 ...

  7. 案例:使用dbms_xplan.display_cursor无法获取执行计划

    案例:使用dbms_xplan.display_cursor无法获取执行计划 环境:RHEL 6.5 + Oracle 11.2.0.4 在一次测试中发现使用dbms_xplan.display_cu ...

  8. Hbase如何批量删除指定数据

    有时我们需要批量删除一些hbase中符合某些条件的数据,本文提供一种简单的shell命令的方式批量删除hbase里的数据.思路就是,建立hive与hbase的关联表,通过hive sql查询出符合条件 ...

  9. SpringCloud(二):服务的注册与发现(Eureka)

    一.什么是服务注册与发现Spring Cloud Eureka 模块提供的功能是被动式的服务发现. 服务注册:每个用户去聊天室服务器上注册. 服务发现:这样他的好友们就能看到你,你同时也将获取好友的上 ...

  10. 解决html导出pdf中文乱码问题的正确姿势

    简介 本文使用jspdf 1.5.3版.GitHub地址:https://github.com/MrRio/jsPDF jspdf是歪果仁开发的,因此在一开始就没想过支持非英文以外的文字,这就导致了非 ...