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

在上图中, 边的起点为词的第一个字, 边的终点为词尾的下一个字. 边1表示"我"字单字成词, 边2表示"只是"可以作为一个单词.
每个边拥有一个权值, 表示该词出现的概率. 最简单的做法是采用词频作为权值, 也可以采用TF-IDF值作为权值提高对低频词的分词准确度.
N最短路径分词即在上述有向无环图中寻找N条权值和最大的路径, 路径上的边标志了最可能的分词结果.通常我们只寻找权值和最大的那一条路径.

根据上图的权值最大路径得到的分词结果为: "我/只是/做/了/一些/微小/的/工作"
实现词典
词典将根据输入的文本, 统计各单词的词频:
class WordDictModel:
def __init__(self):
self.word_dict = {}
self.data = None
self.stop_words = {}
def load_data(self, filename):
self.data = open(filename, "r", encoding="utf-8")
def update(self):
# build word_dict
for line in self.data:
words = line.split(" ")
for word in words:
if word in self.stop_words:
continue
if self.word_dict.get(word):
self.word_dict[word] += 1
else:
self.word_dict[word] = 1
update函数可以在原有词典的基础上, 根据新的输入更新词频.
原始文本输入:
...
罗辑 离开 墓碑 , 站 到 他 为 自己 挖掘 的 墓穴 旁 , 将 手枪 顶到 自己 的 心脏 位置 , 说 : “ 现在 , 我 将 让 自己 的 心脏 停止 跳动 , 与此同时 我 也 将 成为 两个 世界 有史以来 最大 的 罪犯 。 对于 所 犯下 的 罪行 , 我 对 两个 文明 表示 深深 的 歉意 , 但 不会 忏悔 , 因为 这是 唯一 的 选择 。 我 知道 智子 就 在 身边 , 但 你们 对 人类 的 呼唤 从不 理睬 , 无言 是 最大 的 轻蔑 , 我们 忍受 这种 轻蔑 已经 两个 世纪 了 , 现在 , 如果 你们 愿意 , 可以 继续 保持 沉默 , 我 只 给 你们 三十 秒钟 时间
...
产生词频词典:
{
...
"伏击战": 26,
"生态园林": 3,
"造谣诽谤": 3,
"下关市": 11,
"水彩颜料": 3,
"虎踞龙盘": 5,
...
}
顺便编写save和load方法:
def save(self, filename="words.txt", code="txt"):
fw = open(filename, 'w', encoding="utf-8")
data = {
"word_dict": self.word_dict
}
# encode and write
if 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()
def load(self, filename="words.txt", code="txt"):
fr = open(filename, 'r', encoding='utf-8')
# load model
model = {}
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:
continue
word_dict[tmp[0]] = int(tmp[1])
model = {"word_dict": word_dict}
# update word dict
word_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]
fr.close()
最短路径分词
分词器需要继承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] = tmp
return 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算法. 但其耗时太久, 大多数情况下使用贪心算法求得次优解就可以达到所需精度:
def predict(self, sentence):
Len = len(sentence)
route = [0] * Len
dag = 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). 考虑常见句子的长度, 造成的性能损失难以接受.
最后, 做一下测试:
dag_segger = DAGSegger()
dag_segger.stop_words = seg_stop_words
dag_segger.load(filename=data_path("words.txt"))
def test_seg():
cases = [
"给你们传授一点人生的经验",
"我来到北京清华大学",
"长春市长春节讲话",
"我们在野生动物园玩",
"我只是做了一些微小的工作",
"国庆节我在研究中文分词",
"比起生存还是死亡来忠诚与背叛可能更是一个问题"
]
for case in cases:
result = dag_segger.cut(case)
print(result)
测试结果:
['给', '你们', '传授', '一点', '人生', '的', '经验']
['我', '来到', '北京', '清华大学']
['长春', '市长', '春节', '讲话']
['我们', '在', '野生', '动物园', '玩']
['我', '只是', '做', '了', '一些', '微小', '的', '工作']
['国庆节', '我', '在', '研究', '中文', '分词']
['比起', '生存', '还是', '死亡', '来', '忠诚', '与', '背叛', '可能', '更是', '一个', '问题']
因依赖关系,若要运行代码请clone整个项目, 并运行python3 test.py。
N最短路径分词的更多相关文章
- 自然语言处理工具HanLP-N最短路径分词
本篇给大家分享baiziyu 写的HanLP 中的N-最短路径分词.以为下分享的原文,部分地方有稍作修改,内容仅供大家学习交流! 首先说明在HanLP对外提供的接口中没有使用N-最短路径分词器的,作者 ...
- Hanlp中N最短路径分词详细介绍
N-最短路径 是中科院分词工具NLPIR进行分词用到的一个重要算法,张华平.刘群老师在论文<基于N-最短路径方法的中文词语粗分模型>中做了比较详细的介绍.该算法算法基本思想很简单,就是给定 ...
- 11大Java开源中文分词器的使用方法和分词效果对比
本文的目标有两个: 1.学会使用11大Java开源中文分词器 2.对比分析11大Java开源中文分词器的分词效果 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那 ...
- Hanlp中使用纯JAVA实现CRF分词
Hanlp中使用纯JAVA实现CRF分词 与基于隐马尔可夫模型的最短路径分词.N-最短路径分词相比,基于条件随机场(CRF)的分词对未登录词有更好的支持.本文(HanLP)使用纯Java实现CRF模型 ...
- CRF分词的纯Java实现
与基于隐马尔可夫模型的最短路径分词.N-最短路径分词相比,基于随机条件场(CRF)的分词对未登录词有更好的支持.本文(HanLP)使用纯Java实现CRF模型的读取与维特比后向解码,内部特征函数采用 ...
- NLP舞动之中文分词浅析(一)
一.简介 针对现有中文分词在垂直领域应用时,存在准确率不高的问题,本文对其进行了简要分析,对中文分词面临的分词歧义及未登录词等难点进行了介绍,最后对当前中文分词实现的算法原理(基于词表. ...
- Python分词工具——pyhanlp
本文为本人学习pyhanlp的笔记,大多知识点来源于GitHubhttps://github.com/hankcs/HanLP/blob/master/README.md,文中的demo代码来源于该G ...
- HanLP-最短路径分词
今天介绍的内容是最短路径分词.最近换回了thinkpad x1,原因是mac的13.3寸的屏幕看代码实在是不方便,也可能是人老了吧,^_^.等把HanLP词法分析介绍结束后,还是会换回macbook ...
- 11大Java开源中文分词器的使用方法和分词效果对比,当前几个主要的Lucene中文分词器的比较
本文的目标有两个: 1.学会使用11大Java开源中文分词器 2.对比分析11大Java开源中文分词器的分词效果 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那 ...
随机推荐
- Python 多进程编程之multiprocessing--Process
Python 多进程编程之multiprocessing 1,Process 跨平台的进程创建模块(multiprocessing), 支持跨平台:windowx/linux 创建和启动 创 ...
- Alpha 冲刺 (10/10)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 测试整体软件 展示GitHub当 ...
- 手机端table表格bug
table表格在手机端有一个小小的bug,就是td有一个右边线,解决办法可已给tr加一个背景色就行,或者table都行,完美解决
- VS“新建网站”与“新建Asp.Net Web 应用程序”的区别
WebApplication(新建Asp.Net Web 应用程序)编程模型的优点:针对大型网站 1.编译速度网站编译速度快,使用了增量编译模式,仅仅只有文件被修改后,这部分才会被增量编译进去. 2. ...
- MySQL中校验规则(collation)的选取对实际数据筛选的影响
在mysql中存在着各种utf8编码格式,如下表:1)utf8_bin2)utf8_general_ci utf8_bin将字符串中的每一个字符用二进制数据存储,区分大小写.utf8_genera_c ...
- pyhon_day1 格式化输出
格式化输出 我们在写Python的在很多时候输出的内容需要规定格式的,这样就引入到了格式化输出 定义: 盗用下大咖的例子: ------------ info of alex ----------- ...
- HashMap TreeMap的区别
Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复就覆盖了),但允许值重复.Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快 ...
- iostat 命令详解
前言 话说搞运维的人没有两把"刷子",都不好意思上服务器操作.还好,我还不是搞运维的,我一直都自诩是开发人员,奈何现在的东家运维人员"水"的一比,还要我这个自诩 ...
- Dev修改gridview 背景色
private void gridView1_RowCellStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowCellStyleEventA ...
- 项目Alpha冲刺(团队1/10)
项目Alpha冲刺(团队1/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...