自然语言处理学习笔记(五)————切分算法

目录

1.切分算法

2.完全切分

3.正向最长匹配

4.逆向最长匹配

5.双向最长匹配

6.速度评测


1.切分算法

        词典确定后,句子可能含有很多词典中的词语,他们有可能互相重叠,如何切分需要一些规则。常用规则为:正向匹配算法、逆向匹配算法以及双向匹配算法。但他们都是基于完全切分过程。

2.完全切分

        完全切分指的是,找出一段文本中的所有单词。朴素的完全切分算法其实非常简单,只要遍历文本中的连续序列,查询该序列是否在词典中即可。定义词典为dic,文本为text,当前的处理位置为i,完全切分的python算法如下:

def fully_segment(text, dic):
    word_list = []
    for i in range(len(text)):                  # i 从 0 到text的最后一个字的下标遍历
        for j in range(i + 1, len(text) + 1):   # j 遍历[i + 1, len(text)]区间
            word = text[i:j]                    # 取出连续区间[i, j]对应的字符串
            if word in dic:                     # 如果在词典中,则认为是一个词
                word_list.append(word)
    return word_list


if __name__ == '__main__':
    dic = load_dictionary()

    print(fully_segment('商品和服务', dic))

        运行结果: 

        输出了所有可能的单词。由于词库中含有单字,所以结果中也出现了一些单字。 

3.正向最长匹配

        完全切分的结果比较没有意义,我们更需要那种有意义的词语序列,而不是所有出现在词典中的单词所构成的链表。 所以需要完善一下处理规则,考虑到越长的单词表达的意义越丰富,于是我们定义单词越长优先级越高。具体说来,就是在以某个下标为起点递增查词的过程中,优先输出更长的单词,这种规则被称为最长匹配算法。扫描顺序从前往后,则称为正向最长匹配,反之则为逆向最长匹配。

def forward_segment(text, dic):
    word_list = []
    i = 0
    while i < len(text):
        longest_word = text[i]                      # 当前扫描位置的单字
        for j in range(i + 1, len(text) + 1):       # 所有可能的结尾
            word = text[i:j]                        # 从当前位置到结尾的连续字符串
            if word in dic:                         # 在词典中
                if len(word) > len(longest_word):   # 并且更长
                    longest_word = word             # 则更优先输出
        word_list.append(longest_word)              # 输出最长词
        i += len(longest_word)                      # 正向扫描
    return word_list



if __name__ == '__main__':
    dic = load_dictionary()

    print(forward_segment('就读北京大学', dic))
    print(forward_segment('研究生命起源', dic))

结果:

['就读', '北京大学']
['研究生', '命', '起源'] 

第二句话就会产生误差了,我们是需要把“研究”提取出来,结果按照正向最长匹配算法就提取出了“研究生”,所以人们就想出了逆向最长匹配。 


4.逆向最长匹配

def backward_segment(text, dic):
    word_list = []
    i = len(text) - 1
    while i >= 0:                                   # 扫描位置作为终点
        longest_word = text[i]                      # 扫描位置的单字
        for j in range(0, i):                       # 遍历[0, i]区间作为待查询词语的起点
            word = text[j: i + 1]                   # 取出[j, i]区间作为待查询单词
            if word in dic:
                if len(word) > len(longest_word):   # 越长优先级越高
                    longest_word = word
                    break
        word_list.insert(0, longest_word)           # 逆向扫描,所以越先查出的单词在位置上越靠后
        i -= len(longest_word)
    return word_list
 
dic = load_dictionary()
print(backward_segment('研究生命起源', dic))
print(backward_segment('项目的研究', dic))

        输出:

['研究', '生命', '起源']

['项', '目的', '研究']

        第一句正确了,但下一句又出错了,可谓拆东墙补西墙。另一些人提出综合两种规则,期待它们取长补短,称为双向最长匹配。

5.双向最长匹配

        统计显示,正向匹配错误而逆向匹配正确的句子占9.24%。双向最长匹配规则集,流程如下:

(1)同时执行正向和逆向最长匹配,若两者的词数不同,则返回词数更少的那一个。

(2)否则,返回两者中单字更少的那一个。当单字数也相同时,优先返回逆向最长匹配的结果。

def count_single_char(word_list: list):  # 统计单字成词的个数
    return sum(1 for word in word_list if len(word) == 1)
 
 
def bidirectional_segment(text, dic):
    f = forward_segment(text, dic)
    b = backward_segment(text, dic)
    if len(f) < len(b):                                  # 词数更少优先级更高
        return f
    elif len(f) > len(b):
        return b
    else:
        if count_single_char(f) < count_single_char(b):  # 单字更少优先级更高
            return f
        else:
            return b                                     # 都相等时逆向匹配优先级更高
 
 
print(bidirectional_segment('研究生命起源', dic))
print(bidirectional_segment('项目的研究', dic))

结果:

['研究', '生命', '起源']
['项', '目的', '研究']

        比较之后发现,双向最长匹配在2、3、5这3种情况下选择出了最好的结果,但在4号句子上选择了错误的结果,使得最终正确率3/6反而小于逆向最长匹配的4/6。由此,规则系统的脆弱可见一斑。规则集的维护有时是拆东墙补西墙,有时是帮倒忙。

6.速度评测

词典分词的规则没有技术含量,消除歧义的效果不好。词典分词的核心价值不在于精度,而在于速度。

 总结:

  • Python的运行速度比Java慢,效率只有Java的一半不到
  • 正向匹配与逆向匹配的速度差不多,是双向的两倍。因为双向做了两倍的工作
  • Java实现的正向匹配比逆向匹配快

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/62811.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序的 weiui的使用以及引入

https://wechat-miniprogram.github.io/weui/docs/quickstart.html 网址 1.点进去&#xff0c;在app.json里面配置 在你需要的 页面的 json里面配置&#xff0c;按需引入 然后看文档&#xff0c;再在你的 wxml里面使用就好了

MYSQL06高级_为什么使用索引、优缺点、索引的设计、方案、聚簇索引、联合索引

文章目录 ①. 为什么使用索引②. 索引及其优缺点③. InnoDb - 索引的设计④. InnoDb中的索引方案⑤. 索引 - 聚簇索引⑥. 索引 - 二级索引 ①. 为什么使用索引 ①. 索引是存储引擎用于快速找到数据记录的一种数据结构,就好比去图书馆找书,或者新华字典里找字,相当于一个目录,可…

Vue2 第十七节 Vue中的Ajax

1.Vue脚手架配置代理 2.vue-resource 一.Vue脚手架配置代理 1.1 使用Ajax库 -- axios ① 安装 : npm i axios ② 引入: import axios from axios ③ 使用示例 1.2 解决开发环境Ajax跨域问题 跨域&#xff1a;违背了同源策略&#xff0c;同源策略规定协议名&#xff0…

ApplicationContent 和BeanFactory的关系

选中这个类&#xff0c; ctrl alt u 从springboot的启动类说起 我们知道这个启动类返回值呢是哟个configurableApplicationContent 类型 我们查看她的类图 从图中我们可以看出&#xff0c;configurableApplicationContent是见解的继承了BeanFactory接口&#xff0c;扩展了他…

2023爱分析·信创云市场厂商评估报告:中国电子云

01 研究范围定义 信创2.0时代开启&#xff0c;信创进程正在从局部到全面、从细分到所有领域延展。在这个过程中&#xff0c;传统的系统集成,也在逐步向信创化、数字化及智能化转变。随着信创产业的发展&#xff0c;企业需要更多的技术支持和服务&#xff0c;而传统的系统集成已…

C语言 函数指针详解

一、函数指针 1.1、概念 函数指针&#xff1a;首先它是一个指针&#xff0c;一个指向函数的指针&#xff0c;在内存空间中存放的是函数的地址&#xff1b; 示例&#xff1a; int Add(int x&#xff0c;int y) {return xy;} int main() {printf("%p\n",&Add);…

uniapp引入inconfont自定义导航栏

app,h5端引入 uniapp本身的全局设置中有个iconfontsrc属性 所以只需要 1.iconfont将需要的icon添加至项目 2.下载到本地解压后,将其中的ttf文件,放在static静态目录下 3.在page.json中对全局文件进行配置tabBar(导航图标) “iconfontSrc”: “static/font/iconfont.ttf”, …

SQLAlchemy快速使用

一、介绍 sqlalchemy是一个基于python实现的orm框架&#xff0c;跟web框架无关&#xff0c;独立的。 同步orm框架&#xff1a;django的orm&#xff08;3.0以后支持异步&#xff09;、sqlalchemy&#xff08;大而重&#xff09;、peewee&#xff08;小而轻、同步和异步&#xf…

Netty 粘包半包

什么是 TCP 粘包半包&#xff1f; 假设客户端分别发送了两个数据包 D1 和 D2 给服务端&#xff0c;由于服务端一次读取到的字节 数是不确定的&#xff0c;故可能存在以下 4 种情况。 &#xff08;1&#xff09;服务端分两次读取到了两个独立的数据包&#xff0c;分别…

MyBatis查询数据库之一(概念+创建项目+基础交互)

目录 1.MyBatis是什么&#xff1f; 2.为什么学习MyBatis&#xff1f; 3. 怎么学 MyBatis 4.第⼀个MyBatis查询 4.1 添加MyBatis框架支持 4.1.1老项目添加MyBatis 4.1.2 新项目添加MyBatis 4.2 配置连接字符串和MyBatis 4.2.1 配置连接字符串 4.2.2 配置 MyBatis 中的…

python爬虫之scrapy框架介绍

一、Scrapy框架简介 Scrapy 是一个开源的 Python 库和框架&#xff0c;用于从网站上提取数据。它为自从网站爬取数据而设计&#xff0c;也可以用于数据挖掘和信息处理。Scrapy 可以从互联网上自动爬取数据&#xff0c;并将其存储在本地或在 Internet 上进行处理。Scrapy 的目标…

谈谈基因编辑技术

目录 1.基因编辑的概念 2.基因编辑技术的发展 3.基因编辑技术给人类带来的福利 1.基因编辑的概念 基因编辑是指通过人为干预&#xff0c;对生物个体的基因组进行特定的修改。这种技术使得科学家能够直接改变生物体的遗传信息&#xff0c;包括添加、删除或修改特定基因的DNA序…

为什么你一定要学会写作?

不管是写文章还是做短视频&#xff0c;也就是现在的自媒体&#xff0c;都有一个很大的好处&#xff1a; 写作是把自己的同一段时间重复销售很多很多次的极少选择之一&#xff0c;也是相对来看最容易成为普通人起步的台阶之一。 你写一篇文章&#xff0c;可能花了半天时间&…

uniapp点击图片放大预览

阐述 有些时候我们在用uniapp显示图片时&#xff0c;有的不宜全部显示到屏幕上&#xff0c;uniapp提供了一个非常好用的api。 实现方式如下&#xff1a; <template><view class"content"><image class"logo" src"/static/images/a.…

移动开发最佳实践:为 Android 和 iOS 构建成功应用的策略

您可以将本文作为指南&#xff0c;确保您的应用程序符合可行的最重要标准。请注意&#xff0c;这份清单远非详尽无遗&#xff1b;您可以加以利用&#xff0c;并添加一些自己的见解。 了解您的目标受众 要制作一个成功的应用程序&#xff0c;你需要了解你是为谁制作的。从创建…

Scala编程语言入门教程

Scala教程 方便个人学习和查阅 学习目标 Scala介绍 简介 Scala创始人Martin Odersky马丁奥德斯基 再回到我们的scala语言&#xff0c;在Scala官网https://www.scala-lang.org/介绍了其六大特征。 Java和scala可以混编 类型推测(自动推测类型) 并发和分布式&#xff08;Ac…

OLED透明屏采购指南:如何选择适合您需求的高品质产品

引言&#xff1a;OLED透明屏作为一种创新的显示技术&#xff0c;正在迅速发展并广泛应用于各个领域。 然而&#xff0c;面对市场上琳琅满目的OLED透明屏产品&#xff0c;如何选择适合自己需求的高品质产品成为了采购者们的重要任务。 对此&#xff0c;尼伽将为您提供一份OLED…

mybatis-plus的update方法,到底会不会更新null值?看这一篇就够了

普通的设置值。需要传入一个Wrapper对象 默认情况下是不会更新null值的&#xff0c;也就是只更新设置值的字段 LambdaUpdateWrapper<OrderChildRoom> orderChildRoomUpdateWrapper new LambdaUpdateWrapper<>();orderChildRoomUpdateWrapper.set(OrderChildRoo…

基于SqlSugar的开发框架循序渐进介绍- 基于MongoDB的数据库操作整合

SqlSugar的开发框架本身主要是基于常规关系型数据库设计的框架&#xff0c;支持多种数据库类型的接入&#xff0c;如SqlServer、MySQL、Oracle、PostgreSQL、SQLite等数据库&#xff0c;非关系型数据库的MongoDB数据库也可以作为扩展整合到开发框架里面&#xff0c;通过基类的继…

SPI通信协议

简介 SPI有主、从两种模式&#xff0c;通常由一个主模块和一个或多个从模块组成&#xff08;SPI不支持多主机&#xff09;&#xff0c;主 模块选择一个从模块进行同步通信&#xff0c;从而完成数据的交换。提供时钟的为主设备&#xff08;Master&#xff09;&#xff0c;接 收时…