Python预测分词的实现


Posted in Python onJune 18, 2021

前言

在机器学习中,我们有了训练集的话,就开始预测。预测是指利用模型对句子进行推断的过程。在中文分词任务中也就是利用模型推断分词序列,同时也叫解码。

在HanLP库中,二元语法的解码由ViterbiSegment分词器提供。本篇将详细介绍ViterbiSegment的使用方式

 

加载模型

在前篇博文中,我们已经得到了训练的一元,二元语法模型。后续的处理肯定会基于这几个文件来处理。所以,我们首先要做的就是加载这些模型到程序中:

if __name__ == "__main__":
    MODEL_PATH = "123"
    HanLP.Config.CoreDictionaryPath = MODEL_PATH + ".txt"
    HanLP.Config.BiGramDictionaryPath = MODEL_PATH + ".ngram.txt"
    CoreDictionary = SafeJClass("com.hankcs.hanlp.dictionary.CoreDictionary")
    CoreBiGramTableDictionary = SafeJClass('com.hankcs.hanlp.dictionary.CoreBiGramTableDictionary')
    print(CoreDictionary.getTermFrequency("秦机"))
    print(CoreBiGramTableDictionary.getBiFrequency("秦机","的"))

运行之后,效果如下:

Python预测分词的实现

这里我们使用CoreDictionary.getTermFrequency()方法获取”秦机“的频次。使用CoreBiGramTableDictionary.getBiFrequency()方法获取“秦机 的”的二元语法频次。

 

构建词网

在前文中我们介绍了符号“末##末“,代表句子结尾,”始##始“代表句子开头。而词网指的是句子中所有一元语法构成的网状结构。比如MSR词典中的“秦机和科技”这个句子,是给定的一元词典。我们将句子中所有单词找出来。得到如下词网:

[始##始]
[秦机]
[]
[和,和科]
[科技]
[技]
[末##末]

对应的此图如下所示:

Python预测分词的实现

当然,这里博主只是举例说明词网的概念,“和科”并不是一个单词。

下面,我们来通过方法构建词网。具体代码如下:

def build_wordnet(sent, trie):
    JString = JClass('java.lang.String')
    Vertex = JClass('com.hankcs.hanlp.seg.common.Vertex')
    WordNet = JClass('com.hankcs.hanlp.seg.common.WordNet')
    searcher = trie.getSearcher(JString(sent), 0)
    wordnet = WordNet(sent)
    while searcher.next():
        wordnet.add(searcher.begin + 1,
                    Vertex(sent[searcher.begin:searcher.begin + searcher.length], searcher.value, searcher.index))
    # 原子分词,保证图连通
    vertexes = wordnet.getVertexes()
    i = 0
    while i < len(vertexes):
        if len(vertexes[i]) == 0:  # 空白行
            j = i + 1
            for j in range(i + 1, len(vertexes) - 1):  # 寻找第一个非空行 j
                if len(vertexes[j]):
                    break
            wordnet.add(i, Vertex.newPunctuationInstance(sent[i - 1: j - 1]))  # 填充[i, j)之间的空白行
            i = j
        else:
            i += len(vertexes[i][-1].realWord)

    return wordnet


if __name__ == "__main__":
    MODEL_PATH = "123"
    HanLP.Config.CoreDictionaryPath = MODEL_PATH + ".txt"
    HanLP.Config.BiGramDictionaryPath = MODEL_PATH + ".ngram.txt"
    CoreDictionary = SafeJClass("com.hankcs.hanlp.dictionary.CoreDictionary")
    CoreBiGramTableDictionary = SafeJClass('com.hankcs.hanlp.dictionary.CoreBiGramTableDictionary')
    print(build_wordnet("秦机和科技", CoreDictionary.trie))

运行之后,我们会得到与上图归纳差不多的内容:

Python预测分词的实现

 

维特比算法

如果现在我们赋予上述词图每条边以二元语法的概率作为距离,那么如何求解词图上的最短路径就是一个关键问题。

假设文本长度为n,则一共有2(n-1次方)种切分方式,因为每2个字符间都有2种选择:切或者不切,时间复杂度就为O(2(n-1次方))。显然不切实际,这里我们考虑使用维特比算法。

维特比算法原理:它分为前向和后向两个步骤。

  • 前向:由起点出发从前往后遍历节点,更新从起点到该节点的最下花费以及前驱指针
  • 后向:由终点出发从后往前回溯前驱指针,取得最短路径

维特比算法用python代码的实现如下:

def viterbi(wordnet):
    nodes = wordnet.getVertexes()
    # 前向遍历
    for i in range(0, len(nodes) - 1):
        for node in nodes[i]:
            for to in nodes[i + len(node.realWord)]:
                # 根据距离公式计算节点距离,并维护最短路径上的前驱指针from
                to.updateFrom(node)
    # 后向回溯
    # 最短路径
    path = []
    # 从终点回溯
    f = nodes[len(nodes) - 1].getFirst()
    while f:
        path.insert(0, f)
        # 按前驱指针from回溯
        f = f.getFrom()
    return [v.realWord for v in path]

 

实战

现在我们来做个测试,我们在msr_test_gold.utf8上训练模型,为秦机和科技常见词图,最后运行维特比算法。详细代码如下所示:

if __name__ == "__main__":
    MODEL_PATH = "123"
    corpus_path = r"E:\ProgramData\Anaconda3\Lib\site-packages\pyhanlp\static\data\test\icwb2-data\gold\msr_test_gold.utf8"
    train_model(corpus_path, MODEL_PATH)
    HanLP.Config.CoreDictionaryPath = MODEL_PATH + ".txt"
    HanLP.Config.BiGramDictionaryPath = MODEL_PATH + ".ngram.txt"
    CoreDictionary = SafeJClass("com.hankcs.hanlp.dictionary.CoreDictionary")
    CoreBiGramTableDictionary = SafeJClass('com.hankcs.hanlp.dictionary.CoreBiGramTableDictionary')
    ViterbiSegment = JClass('com.hankcs.hanlp.seg.Viterbi.ViterbiSegment')
    MODEL_PATH = "123"
    HanLP.Config.CoreDictionaryPath = MODEL_PATH + ".txt"
    HanLP.Config.BiGramDictionaryPath = MODEL_PATH + ".ngram.txt"
    sent = "秦机和科技"
    wordnet = build_wordnet(sent, CoreDictionary.trie)
    print(viterbi(wordnet))

Python预测分词的实现

有的人可能有疑问,因为二元模型里,本身就存在秦机 和
科技这个样本。这么做不是多此一举吗?那好,我们替换sent的文本内容为“北京和广州”,这个样本可不在模型中。运行之后,效果如下:

Python预测分词的实现

我们发现依然能正确的分词为[北京 和 广州],这就是二元语法模型的泛化能力。至此我们走通了语料标注,训练模型,预测分词结果的完整步骤。

到此这篇关于Python预测分词的实现的文章就介绍到这了,更多相关Python预测分词内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python调用java模块SmartXLS和jpype修改excel文件的方法
Apr 28 Python
Python基于smtplib实现异步发送邮件服务
May 28 Python
Python实现求两个csv文件交集的方法
Sep 06 Python
python中文乱码不着急,先看懂字节和字符
Dec 20 Python
Python File readlines() 使用方法
Mar 19 Python
python Django中models进行模糊查询的示例
Jul 18 Python
余弦相似性计算及python代码实现过程解析
Sep 18 Python
Keras自动下载的数据集/模型存放位置介绍
Jun 19 Python
python实现图像外边界跟踪操作
Jul 13 Python
Python基于tkinter canvas实现图片裁剪功能
Nov 05 Python
Pytorch 实现变量类型转换
May 17 Python
python基础之错误和异常处理
Oct 24 Python
学会Python数据可视化必须尝试这7个库
python tqdm用法及实例详解
Jun 16 #Python
python使用pymysql模块操作MySQL
分析Python感知线程状态的解决方案之Event与信号量
Jun 16 #Python
Python中else的三种使用场景
Jun 16 #Python
Python基础之条件语句详解
教你怎么用Python实现GIF动图的提取及合成
You might like
PHP数字格式化
2006/12/06 PHP
PHP循环结构实例讲解
2014/02/10 PHP
Linux(CentOS)下PHP扩展PDO编译安装的方法
2016/04/07 PHP
jQuery前台数据获取实现代码
2011/03/16 Javascript
JS Date函数整理方便使用
2013/10/23 Javascript
使用js简单实现了tree树菜单
2013/11/20 Javascript
jQuery中bind,live,delegate与one方法的用法及区别解析
2013/12/30 Javascript
js带点自动图片轮播幻灯片特效代码分享
2015/09/07 Javascript
js点击文本框弹出可选择的checkbox复选框
2016/02/03 Javascript
jQuery原理系列-常用Dom操作详解
2016/06/07 Javascript
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
2016/12/15 Javascript
bootstrap弹出层的多种触发方式
2017/05/10 Javascript
jQuery条件分页 代替离线查询(附代码)
2017/08/17 jQuery
json对象及数组键值的深度大小写转换问题详解
2018/03/30 Javascript
深入浅出理解JavaScript闭包的功能与用法
2018/08/01 Javascript
JS实现的input选择图片本地预览功能示例
2018/08/29 Javascript
解决iview多表头动态更改列元素发生的错误的方法
2018/11/02 Javascript
javascript原型链学习记录之继承实现方式分析
2019/05/01 Javascript
Vue如何获取数据列表展示
2019/12/11 Javascript
微信小程序自定义底部弹出框动画
2020/11/18 Javascript
简单介绍Python中的decode()方法的使用
2015/05/18 Python
python利用datetime模块计算时间差
2015/08/04 Python
python+pandas生成指定日期和重采样的方法
2018/04/11 Python
基于Django与ajax之间的json传输方法
2018/05/29 Python
python引入不同文件夹下的自定义模块方法
2018/10/27 Python
Python 确定多项式拟合/回归的阶数实例
2018/12/29 Python
北美主要的汽车零部件零售商:AutoShack.com
2019/02/23 全球购物
List、Map、Set三个接口,存取元素时,各有什么特点?
2015/09/27 面试题
责任心演讲稿
2014/05/14 职场文书
公司财务会计主管应聘求职信
2014/09/26 职场文书
2014年扫黄打非工作总结
2014/12/03 职场文书
市场总监岗位职责
2015/02/11 职场文书
初中军训感言
2015/08/01 职场文书
python中__slots__节约内存的具体做法
2021/07/04 Python
Go语言基础切片的创建及初始化示例详解
2021/11/17 Golang
PyCharm 配置SSH和SFTP连接远程服务器
2022/05/11 Python