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

算法描述
正向最大匹配算法
先设定扫描的窗口大小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. Python网络爬虫_Scrapy框架_2.logging模块的使用

    logging模块提供日志服务 在scrapy框架中已经对其进行一些操作所以使用更为简单 在Scrapy框架中使用: 1.在setting.py文件中设置LOG_LEVEL(设置日志等级,只有高于等于 ...

  2. 14. java面向对象 - 基础

    一.面向对象主线 1. Java类及类的成员:属性.方法.构造器.代码块.内部类 2. 面向对象三大特征:封装.继承.多态.(抽象性) 3. 其他关键字:this.super.static.final ...

  3. hibernate-positional-parameter-does-not-exist-1-in-query

    经过bug的排查,问题出在,scsj字段的赋值上; 通过字符串在数据库端生成即可:

  4. java之Objects类

    Objects类概述 在JDK7添加了一个Objects工具类,它提供了一些方法来操作对象,它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空 ...

  5. JS Proxy(代理)

    前言 Proxy 也就是代理,可以帮助我们完成很多事情,例如对数据的处理,对构造函数的处理,对数据的验证,说白了,就是在我们访问对象前添加了一层拦截,可以过滤很多操作,而这些过滤,由你来定义. 想了解 ...

  6. Linux下shell脚本实现mongodb定时自动备份

    MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功 ...

  7. 3种不走寻常路的黑客攻击泄露&如何保护自己?

    数据泄露和黑客攻击现在已经成为我们日常生活中的常见部分,除非您是网络安全专业人员或您的个人数据受到威胁,否则您实际上并不关心是否存在新的漏洞. 正如美国联邦贸易委员会指出的那样,万豪酒店连锁店的超过5 ...

  8. 【Luogu P3994】高速公路

    Problem Background \(C\) 国拥有一张四通八达的高速公路网树,其中有 \(n\) 个城市,城市之间由一共 \(n-1\) 条高速公路连接.除了首都 \(1\) 号城市,每个城市都 ...

  9. [CrackMe]160个CrackMe之015

    吾爱破解专题汇总:[反汇编练习]160个CrackME索引目录1~160建议收藏备用 一.破解 该破解比较简单,其是一个静态密码  2G83G35Hs2 ,输入进去即可破解. 1)栈定位法找到用户代码 ...

  10. C++ float vs double

    精度 相比 float ,double 从其名字上已经展示出,它的精度是前者的两倍,他们的精度分别为: float: 7 位数字 double: 15 位数字 可通过如下的示例看出,在重复进行计算时, ...