本文摘要 · 理论来源:【统计自然语言处理】第七章 自动分词
· 参考文章:https://www.cnblogs.com/Finley/p/6619187.html
· 代码目的:手写N-最短路径法进行中文分词
作者:CSDN 征途黯然.

  

本代码评分

  1、训练集、测试集使用The Second International Chinese Word Segmentation比赛中的PKU的数据集。数据集地址:http://sighan.cs.uchicago.edu/bakeoff2005/。

  2、本代码只是简单实现了N最短路径分词,消歧、未登录词暂未解决,评分如下:

精确率 0.7764031562984604
召回率 0.8847287850978248

  3、当初比赛部分评分结果如下:

N最短路径分词

  N最短路径算法是一种基于词典的分词算法. 每个句子将生成一个有向无环图, 每个字作为图的一个定点, 边代表可能的分词.

  在上图中, 边的起点为词的第一个字, 边的终点为词尾的下一个字. 边1表示"我"字单字成词, 边2表示"只是"可以作为一个单词.

  每个边拥有一个权值, 表示该词出现的概率. 最简单的做法是采用词频作为权值, 也可以采用TF-IDF值作为权值提高对低频词的分词准确度.

  N最短路径分词即在上述有向无环图中寻找N条权值和最大的路径, 路径上的边标志了最可能的分词结果.通常我们只寻找权值和最大的那一条路径.

  根据上图的权值最大路径得到的分词结果为: "我/只是/做/了/一些/微小/的/工作"

实现词典

  词典将根据输入的文本, 统计各单词的词频:

import json
import pickle# ##############
# main--词典
# 用来读取utf8格式文章库、json格式词典库、停用词;
# 可以转存为json形式的txt词典库;
# 初始化时默认调用load函数,读取dataset/unknown/words.txt
# ##############class WordDictModel:def __init__(self):self.word_dict = {}self.data = Noneself.stop_words = {}self.load()# 读取词库数据,词库为空格分隔的文章等。文件后缀应当为.utf8def load_data(self, filename):self.data = open(filename, "r", encoding="utf-8")# 更新新词库数据,把读取的词库转化成内部字典word_dictdef update(self):# build word_dictfor line in self.data:words = line.split(" ")for word in words:if word in self.stop_words:continueif self.word_dict.get(word):self.word_dict[word] += 1else:self.word_dict[word] = 1# 把内部词典里面的数据,转化成txt本文文档,格式为key-value键值对,相对于压缩def save(self, filename="words.txt", code="txt"):fw = open(filename, 'w', encoding="utf-8")data = {"word_dict": self.word_dict}# encode and writeif code == "json":txt = json.dumps(data)fw.write(txt)elif code == "pickle":pickle.dump(data, fw)if code == 'txt':for key in self.word_dict:tmp = "%s %d\n" % (key, self.word_dict[key])fw.write(tmp)fw.close()# 加载初始词库,是用save()方法保存的key-value形式的词库def load(self, filename="dataset/unknown/words.txt", code="txt"):fr = open(filename, 'r', encoding='utf-8')# load modelmodel = {}if code == "json":model = json.loads(fr.read())elif code == "pickle":model = pickle.load(fr)elif code == 'txt':word_dict = {}for line in fr:tmp = line.split(" ")if len(tmp) < 2:continueword_dict[tmp[0]] = int(tmp[1])model = {"word_dict": word_dict}fr.close()# update word dictword_dict = model["word_dict"]for key in word_dict:if self.word_dict.get(key):self.word_dict[key] += word_dict[key]else:self.word_dict[key] = word_dict[key]

  update函数可以在原有词典的基础上, 根据新的输入更新词频.

  原始文本输入:

...
罗辑 离开 墓碑 , 站 到 他 为 自己 挖掘 的 墓穴 旁 , 将 手枪 顶到 自己 的 心脏 位置 , 说 : “ 现在 , 我 将 让 自己 的 心脏 停止 跳动 , 与此同时 我 也 将 成为 两个 世界 有史以来 最大 的 罪犯 。 对于 所 犯下 的 罪行 , 我 对 两个 文明 表示 深深 的 歉意 , 但 不会 忏悔 , 因为 这是 唯一 的 选择 。 我 知道 智子 就 在 身边 , 但 你们 对 人类 的 呼唤 从不 理睬 , 无言 是 最大 的 轻蔑 , 我们 忍受 这种 轻蔑 已经 两个 世纪 了 , 现在 , 如果 你们 愿意 , 可以 继续 保持 沉默 , 我 只 给 你们 三十 秒钟 时间
...

  产生词频词典:

{
  ...
  "伏击战": 26,
  "生态园林": 3,
  "造谣诽谤": 3,
  "下关市": 11,
  "水彩颜料": 3,
  "虎踞龙盘": 5,
  ...
}

最短路径分词

  分词器需要继承WordDictModel, 并利用其词典. 遍历输入语句中所有子串, 并查询其词频构造有向无环图:

class DAGSegger(WordDictModel):# 构建有向无环图def build_dag(self, sentence):dag = {}for start in range(len(sentence)):unique = [start + 1]tmp = [(start + 1, 1)]for stop in range(start+1, len(sentence)+1):fragment = sentence[start:stop]# use tf_idf?num = self.word_dict.get(fragment, 0)if num > 0 and (stop not in unique):tmp.append((stop, num))unique.append(stop)dag[start] = tmpreturn dag

  产生的dag格式:

{
  0: [(1,1)],
  1: [(2,1), (3,738)],
  2: [(3,1)],
  3: [(4,1)],
  4: [(5,1)],
  5: [(6,1), (7,2309)],
  6: [(7,1)],
  7: [(8,1), (9,304)],
  8: [(9,1)],
  9: [(10,1)],
  10: [(11,1), (12,2605)],
  11: [(12,1)],
}

  字典中的值代表其键的后继顶点, 如1: [(2,1), (3,738)]表示顶点1到顶点2的权值为1, 到顶点3的权值为738

  最短路径最好使用Floyd或Dijsktra算法. 但其耗时太久, 大多数情况下使用贪心算法求得次优解就可以达到所需精度:

# 从N个路径中,挑选出最优路径def predict(self, sentence):Len = len(sentence)route = [0] * Lendag = self.build_dag(sentence)  # {i: (stop, num)}for i in range(0, Len):route[i] = max(dag[i], key=lambda x: x[1])[0]return route

  词典法分词本身就是一种不精确的方法, 最短路径的最优解和次优解在分词效果上相差并不大.

  但是, 求得最优解需要将时间复杂度由O(n2)提高到O(n3). 考虑常见句子的长度, 造成的性能损失难以接受.

  最后, 做一下测试:

# 测试def test(self):cases = ["小朋友,你是否有很多烦恼","别人在嘻嘻哈哈,你却在研究中文分词","我是周杰伦,我为自己歌唱","我只是做了一些微小的工作","中秋节我在看统计自然语言处理,我特别开心"]for case in cases:result = self.cut(case)# for word in result:#     print(word)print('/'.join(result))

  测试结果:

小朋友/,/你/是否/有/很多/烦恼
别人/在/嘻嘻哈哈/,/你/却/在/研究/中文/分词
我/是/周杰伦/,/我/为/自己/歌唱
我/只是/做/了/一些/微小/的/工作
中秋节/我/在/看/统计/自然/语言/处理/,/我/特别/开心

获取本项目的源代码

如果需要本组件的源代码,请扫描关注我的公众号,回复“中文分词”即可。

【自然语言处理】N-最短路径法进行中文分词相关推荐

  1. 基于Tire树和最大概率法的中文分词功能的Java实现

    对于分词系统的实现来说,主要应集中在两方面的考虑上:一是对语料库的组织,二是分词策略的制订. 1.   Tire树 Tire树,即字典树,是通过字串的公共前缀来对字串进行统计.排序及存储的一种树形结构 ...

  2. 用python进行自然语言处理_Python NLP自然语言处理之使用jieba进行中文分词实践

    自然语言处理的首要任务是分词,将一段文本分割成独立的词语. 中文分词介绍 已经归纳的三种分词如下: 规则分词.统计分词.混合分词规则分词: 通过设立人工词库,按照一定方式进行切分匹配. 正向最大匹配法 ...

  3. 【自然语言处理与文本分析】中文分词的基本原理,如何进行词性标注 使用HMM算法提高准确率

    分词(中文) 本次内容 分词: N-Gram vs.中文分词 分词的难点 法则式分词 统计式分词 词性标注: 词性标注简介 词性标注的难点 词性的种类及意义 保留某些词性的词 分词: N-Gram v ...

  4. 自然语言处理系列十七》中文分词》分词工具实战》Python的Jieba分词

    注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书<分布式机器学习实战>(人工智能科学与技术丛书)[陈敬雷编著][清华大学出版社] 文章目录 自然语言处理系列十七 分词工 ...

  5. 比较好的中文分词方案汇总推荐

    https://www.toutiao.com/a6690352675990536718/ 2019-05-13 11:45:19 中文分词是中文文本处理的一个基础步骤,也是中文人机自然语言交互的基础 ...

  6. NLP-基础任务-中文分词算法(1)-基于词典: 机械分词(词典字符串匹配):前向最大匹配、后向最大匹配、双向最大匹配【OOV:基于现有词典,不能进行新词发现处理】

    分词与NLP关系:分词是中文自然语言处理的基础,没有中文分词,我们对语言很难量化,进而很能运用数学的知识去解决问题.对于拉丁语系是不需要分词的. 拉丁语系与亚系语言区别 拉丁语言系不需要分词,因为他们 ...

  7. 开源 Java 中文分词器 Ansj 作者孙健专访

    Ansj 是一个开源的 Java 中文分词工具,基于中科院的 ictclas 中文分词算法,比其他常用的开源分词工具(如mmseg4j)的分词准确率更高. 在线演示: http://ansj.sdap ...

  8. 转:从头开始编写基于隐含马尔可夫模型HMM的中文分词器

    http://blog.csdn.net/guixunlong/article/details/8925990 从头开始编写基于隐含马尔可夫模型HMM的中文分词器之一 - 资源篇 首先感谢52nlp的 ...

  9. 从头开始编写基于隐含马尔可夫模型HMM的中文分词器之一 - 资源篇

    首先感谢52nlp的系列博文(http://www.52nlp.cn/),提供了自然语言处理的系列学习文章,让我学习到了如何实现一个基于隐含马尔可夫模型HMM的中文分词器. 在编写一个中文分词器前,第 ...

最新文章

  1. ubutun:从共享文件夹拷贝文件尽量使用cp命令而不是CTRL+C/V
  2. CentOS5.6下配置rsync内网同步数据到外网
  3. C++ 顺序容器入门
  4. ubuntu 设置分辨率 亲测可用 转载的
  5. 计算机是怎么RUN起来的
  6. Vue3---安装Element-Plus组件库
  7. 2020年最新全国彩礼地图出炉,你那儿娶媳妇儿需要多少彩礼钱呢?数据分析来告诉你...
  8. linux网卡绑定和漂移,LINUX修改、增加IP的方法,一张网卡绑定多个IP/漂移IP【转】...
  9. centos7.5下yum安装mysql-5.6.43
  10. poj_1390 动态规划
  11. 番茄助手破解找到VA_X.dll的位置
  12. 实时音频编解码之十一Opus编码
  13. python环境下skimage处理高通道tif图片(10通道)
  14. matlab求多元函数微积分,中北大学高等数据MATLAB验证性实验7多元函数微积分学MATLAB实验报告格式...
  15. 互联网架构的演进方向
  16. 云ERP来的正是时候!
  17. 学习项目管理理论后的体会
  18. ...mapMutations的使用
  19. 1个球从100m落下,每次时,反跳原高度的一半,再落,再反弹,求第10次落地共经过多少m,第10次反弹多高。 谭浩强《c语言程序设计》第五章第十一题
  20. 打印机显示无法连接计算机,网络打印提示:Windows无法连接到打印机,请检查打印机名并重试...

热门文章

  1. react-router-dom v6 中的Routes
  2. 日志处理模块----logging
  3. Enrichment plot的另一种展示
  4. 苹果手机做文件服务器,iOS企业账号打包发布App到自己服务器上
  5. go channel 缓冲区最大限制_Java内卷系列之你不得不知的Go并发基础
  6. redis一般缓存什么样数据_门户数据展示_Redis缓存数据
  7. JGG | 肠道微生物研究助力穿山甲圈养保护
  8. USEARCH —— 最简单易学的扩增子分析流程(中国总代理)
  9. QIIME 2教程. 20实用程序Utilities(2020.11)
  10. SBB:增温掩盖不同形态氮素对青藏高原草地微生物群落的作用