优化编辑距离以测量文本相似度

news2025/1/12 6:16:09

一、说明

        编辑距离是一种文本相似度度量,用于测量 2 个单词之间的距离。它有许多方面应用,如文本自动完成和自动更正。

        对于这两种用例中的任何一种,系统都会将用户输入的单词与字典中的单词进行比较,以找到最接近的匹配项,然后提出建议。字典可能包含数千个单词,因此应用程序比较 2 个单词的响应可能需要几毫秒。

        编辑距离通常是通过准备一个大小矩阵(M+1)x(N+1)(其中 M 和 N 是 2 个单词的长度)并使用 2 个 for 循环遍历所述矩阵,在每次迭代中执行一些计算来计算的。这使得计算一个单词与数千个单词的字典之间的距离非常耗时。

        为了加快编辑距离的计算速度,本教程使用向量而不是矩阵进行计算,这样可以节省大量时间。我们将使用 Java 编写此实现的代码。

本教程涵盖的部分如下:

  • 为什么使用向量而不是矩阵?
  • 使用向量
  • Java实现

二、为什么使用向量而不是矩阵?

        首先,在使用向量之前,让我们快速总结一下矩阵的距离计算是如何进行的。

        对于 2 个单词,例如niceniace,将创建一个大小矩阵5x6,如下图所示。请注意,蓝色标签不是矩阵的一部分,只是为了清晰起见而添加的。您可以自由决定让给定的单词代表行或列。在此示例中,单词的字符nice代表行。

        请注意,矩阵中还有额外的行和列,它们与 2 个单词中的任何字符都不对应。它们放置在那里是为了帮助计算距离。

        矩阵的第一行和第一列由从每个字符开始0并递增的值初始化。1例如,第一行的值从 0 到 5。请注意,2 个单词之间的最终距离位于右下角,但要达到它,我们必须计算 2 个单词中所有子集之间的距离。字。

        根据初始化的矩阵,将计算 2 个单词的所有子集之间的距离。该过程首先将第一个单词中的第一个子集(仅包含 1 个字符)与第二个单词中的所有子集进行比较。然后将第一个单词的另一个子集(包含 2 个字符)与第二个单词的所有子集进行比较,依此类推。

        根据上图中的矩阵,该单词的第一个字符nicen。它将与第二个单词的所有子集进行比较niace——即使是具有零个字符的子集{_, n, ni, nia, niac, niace}

        让我们看看这两个子集之间的距离是如何计算的。(i,j)对于与 2 个字符A和之间的交集对应的位置处的给定单元格B,我们比较 3 个位置 ( i,j-1)、( i-1,j) 和 ( i-1,j-1) 处的值。如果 2 个字符相同,则位置 ( ) 处的值i,j等于上述 3 个位置中的最小值。否则,它将等于添加 后这 3 个位置处的最小值1

        这里需要注意一点。在计算矩阵第二行中的距离时,位置 ( i-1,j) 和 ( )处的单元格i-1,j-1只是索引。对于矩阵第二列中的距离,位置 ( i,j-1) 和 ( i-1,j-1) 处的单元格也只是索引。

        前面的讨论可以表示为 4 个值的矩阵,其中有 3 个已知值和 1 个缺失值,如下图所示。

        此类缺失值是通过根据以下方式比较 3 个值来计算的:

dist(X,Y) = min(a, b, c)      -   if X==Y
dist(X,Y) = min(a, b, c) + 1  -   if X!=Y

通过应用该方法,下图给出了矩阵第二行中的值。

        计算完第二行的距离后,将不再需要第一行的距离。对于第三行距离,我们仅使用第二行中的值,而不是第一行中的值。

        换句话说,我们只需要单行已知值来计算一行未知值的距离,不需要整个矩阵。在每行仅使用一次的情况下,使用矩阵计算距离可以保存所有行。

        为了解决这个问题,我们根本不会使用矩阵,而是使用向量。

三、使用向量

        要使用向量计算距离,第一步是创建该向量。向量长度将等于给定单词的长度+1nice如果选择第一个单词,则向量长度为4+1=5​​ 。该向量由零初始化,如下所示。

   nice该向量中的零将被所选单词中的所有子集与另一个单词中的第一个子集niace(即字符)之间的距离替换n。我们如何计算这样的距离?

        当使用矩阵时,需要比较 3 个值,如上一节所述。向量的情况是什么?仅在计算与第二个单词中的第一个子集的距离时,仅需要比较 2 个值。

        假设我们正在计算具有索引的元素的距离,i并且距离向量名为distanceVector,那么这 2 个值如下:

  1. 之前计算的距离:distanceVector[i-1]
  2. 前一个元素的索引:i-1

        返回的距离是这两个值中的最小值:

distanceVector[i] = min(distanceVector[i-1], i-1)

nice这是计算单词的所有子集与第二个单词的第一个子集之间的距离后的向量niace

在计算第一个单词的所有子集和第二个单词的第一个子集之间的距离之后,我们可以开始计算第一个单词中的所有子集和第二个单词中的其余子集之间的距离。距离将通过比较以下 3 个值来计算:

  1. 之前计算的距离:distanceVector[i-1]
  2. 之前计算的距离:distanceVector[i]
  3. 与第二个单词进行比较的元素的索引:j

请注意,i指的是从第一个单词开始的元素索引。

现在我们已经阐明了编辑距离在矩阵和向量中的工作原理,下一节将通过 Java 中的向量实现该距离。

四、Java实现

String除了初始化距离向量之外,要做的第一件事是创建 2 个保存 2 个单词的变量。下面是 Java 中的实现方法:

String token1 = "nice";
String token2 = "niace";
​
int[] distances = new int[token1.length() + 1];

        向量创建后,默认会初始化为零。下一步是使用for循环计算第一个单词niace 中的所有子集nice与第二个单词中的第一个子集之间的距离。

for (int t1 = 1; t1 <= token1.length(); t1++) {
    if (token1.charAt(t1 - 1) == token2.charAt(0)) {
        distances[t1] = calcMin(distances[t1 - 1], t1 - 1);
    } else {
        distances[t1] = calcMin(distances[t1 - 1], t1 - 1) + 1;
    }
}

int calcMin(int a, int b, int c) {
    if (a <= b && a <= c) {
        return a;
    } else if (b <= a && b <= c) {
        return b;
    } else {
        return c;
    }
}

        下一步也是最后一步是根据以下代码计算第一个单词中的所有子集与第二个单词中的其余子集之间的距离:

int dist = 0;
for (int t2 = 1; t2 < token2.length(); t2++) {
    dist = t2 + 1;
    for (int t1 = 1; t1 <= token1.length(); t1++) {
        int tempDist;
        if (token1.charAt(t1 - 1) == token2.charAt(t2)) {
            tempDist = calcMin(dist, distances[t1 - 1], distances[t1]);
        } else {
            tempDist = calcMin(dist, distances[t1 - 1], distances[t1]) + 1;
        }
        distances[t1 - 1] = dist;
        dist = tempDist;
    }
    distances[token1.length()] = dist;
}

int calcMin(int a, int b, int c) {
    if (a <= b && a <= c) {
        return a;
    } else if (b <= a && b <= c) {
        return b;
    } else {
        return c;
    }
}

        两个单词之间的最终距离被保存到变量dist和向量的最后一个元素中distances

        这是一个名为 的完整类LevenshteinDistance,其中名为 的方法levenshtein()保存了计算距离的代码。该方法接受 2 个单词作为参数并返回距离。在该main()方法内部,创建该方法的一个实例来计算 2 个单词nice和之间的距离niace

        前面代码的打印输出是:

The distance is 1

        这是使用两个不同单词计算距离的另一个示例:

System.out.println("The distance is " + levenshteinDistance.levenshtein("congratulations", "conmgeautlatins"));

结果如下:

The distance is 5

五 、结论

        本教程讨论了仅使用向量来计算编辑距离以返回单词之间的距离。经过优化,仅使用向量,它可以应用于移动设备上运行的应用程序,以便在用户键入搜索或其他文本输入时自动完成和更正单词。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关系型数据库Redis安装与写入数据

文章目录 安装和初步选择数据库创建键值对数据类型 安装和初步 安装 Redis是开源的跨平台非关系型数据库&#xff0c;特点是占用资源低、查询速度快。 首先&#xff0c;在Github上下载最新发布的Redis-xxxx.zip压缩文件&#xff0c;下载之后解压&#xff0c;并将解压后的路径…

1366 - Incorrect string value: ‘\xE5\xB9\xBF\xE5\x85\xB0...‘ for column编码错误

1366 - Incorrect string value: ‘\xE5\xB9\xBF\xE5\x85\xB0…’ for column ‘campus_name’ at row 1 > 查询时间: 0s 原因是数据库创建的时候使用的默认编码latin1&#xff0c;导致表和字段的编码格式都是这种编码&#xff0c;显然这种编码不支持中文。 自己修改了数据库…

论文阅读:PVT v2: Improved Baselines with Pyramid Vision Transformer

来源&#xff1a;PVTv1 和PVTv2 链接&#xff1a;https://arxiv.org/pdf/2102.12122.pdf 链接&#xff1a;https://arxiv.org/pdf/2106.13797.pdf PVTv2是在PVTv1基础上&#xff0c;所以先介绍PVTv1 Pyramid Vision Transformer: A Versatile Backbone for Dense Prediction…

ROS话题(Topic)通信:通信模型、Hello World与拓展

文章目录 一、话题通讯模型二、Topic Hello World2.1 创建并初始化功能包2.2 确定Topic名称及消息格式2.3 实现发布者与订阅者&#xff08;C版&#xff09;2.4 实现发布者与订阅者&#xff08;Python版&#xff09;2.5 关于Topic Hello World的注意 拓展1&#xff1a;devel下其…

Java中Enum枚举类型在项目中应用

1、什么是枚举类型&#xff1f; 1、枚举的本质就是穷举法&#xff0c;将可能会出现的情况&#xff0c;都列举出来&#xff0c;然后在列举的情况中调用。 2、枚举与class类似&#xff0c;也可以定义属性&#xff0c;构造方法&#xff0c;有getter和setter方法。 3、枚举类型对…

<MySQL> MySQL表数据的 CRUD 基础操作 —— 增(Create)、查(Retrieve)、改(Update)、删(Delete)

目录 一、CRUD 二、增加&#xff08;Create&#xff09; 2.1 新增插入数据 insert 2.2 操作演示 2.3 多行插入更高效 2.4 插入时间类型的数据 2.5 使用“库函数” 三、查询&#xff08;Retrieve&#xff09; 四、修改&#xff08;Update&#xff09; 4.1 修改数据 …

FTP、NFS、SAMBA系统服务一

一、rsync托管xinetd 1、为什么要进行服务托管 独立服务&#xff1a;独立启动脚本 ssh ftp nfs dns ... 依赖服务: 没有独立的启动脚本 rsync telnet 依赖xinetd服务&#xff08;独立服务&#xff09; 2、如何将rsync托管给xinetd服务去管理&#xff1f; 第一步&#xff1…

NSSCTF-Crypto入门题 练习记录贴 ‘‘一‘‘

文章目录 前言001[鹤城杯 2021]easy_crypto002[强网拟态 2021]拟态签到题003[SWPUCTF 2021 新生赛]crypto8004[SWPUCTF 2021 新生赛]crypto7005[SWPUCTF 2021 新生赛]crypto6006[SWPUCTF 2021 新生赛]ez_caesar007[SWPUCTF 2021 新生赛]crypto10008[鹤城杯 2021]A_CRYPTO009[SW…

SAM + YOLO 智能抠图

在计算机视觉领域&#xff0c;对象检测和实例分割是使机器能够理解视觉数据并与之交互的关键任务。 准确识别和隔离图像中的物体的能力具有许多实际应用&#xff0c;从自动驾驶车辆到医学成像。 在这篇博文中&#xff0c;我们将探索如何在 Roboflow 和 Ultralytics YOLOv8 的帮…

Linux C 时间编程

时间编程 Linux中时间相关命令时间编程time  获取当前的时间gmtime  获取当前日期时间localtime  获取本地时间日期asctime  规格时间结构体为字符串 Linux中时间相关命令 1&#xff09;date&#xff1a;打印当前的系统时间。 2&#xff09;date -s 20231111&#xff…

C#,数值计算——函数计算,Eulsum的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class Eulsum { private double[] wksp { get; set; } private int n { get; set; } private int ncv { get; set; } public bool cnvgd { get; set; } pri…

openEuler编译安装nmon性能监控工具及可视化分析工具

ln 介绍 nmon&#xff08;short for Nigel’s Monitor&#xff09;是一个性能分析工具&#xff0c;由蓝色巨人IBM开发&#xff0c;最早用于自家操作系统UNIX&#xff0c;AIX &#xff08;Advanced Interactive eXecutive&#xff09;。现在也能用在Linux上。它可以显示系统的…

跨域:利用JSONP、WebSocket实现跨域访问

跨域基础知识点&#xff1a;跨域知识点 iframe实现跨域的四种方式&#xff1a;http://t.csdnimg.cn/emgFr 注&#xff1a;本篇中使用到的虚拟主机也是上面iframe中配置的 目录 JSONP跨域 JSONP介绍 跨域实验&#xff1a; WebSocket跨域 websocket介绍 跨域实验 JSONP跨域…

JavaWeb Day09 Mybatis-基础操作02-XML映射文件动态SQL

目录 Mybatis动态SQL介绍​编辑 一、案例 ①Mapper层 ②测试类 ③EmpMapper.xml ④结果​ 二、标签 &#xff08;一&#xff09;if where标签 ​①EmpMapper.xml ②案例 ③总结 &#xff08;二&#xff09;foreach标签 ①SQL语句 ②Mapper层 ③EmpMapper.xml ④…

基于GPTs个性化定制SCI论文专业翻译器

1. 什么是GPTs GPTs是OpenAI在2023年11月6日开发者大会上发布的重要功能更新&#xff0c;允许用户根据特定需求定制自己的ChatGPT模型。 Introducing GPTs 官方介绍页面https://openai.com/blog/introducing-gpts 在原有自定义ChatGPT的流程中&#xff0c;首先需要自己编制p…

HuggingFace模型头的自定义

在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 在本文中我们将介绍如何使HuggingFace的模型适应你的任务&#xff0c;在Pytorch中建立自定义模型头并将其连接到HF模型的主体&#…

2023数据安全战场回顾:迅软科技助您稳固阵线

随着各行业的数字化转型不断深入&#xff0c;数据安全逐步进入法制化的强监管时代。然而&#xff0c;由于人为攻击、技术漏洞和监管缺位等原因&#xff0c;各种数据泄露事件频繁发生&#xff0c;企业数据安全威胁日益严峻。 以下是我对2023年第三季度安全事件的总结&#xff0c…

Maven Profile组设置

application.properties中xxxx

JS实现数据结构与算法

队列 1、普通队列 利用数组push和shif 就可以简单实现 2、利用链表的方式实现队列 class MyQueue {constructor(){this.head nullthis.tail nullthis.length 0}add(value){let node {value}if(this.length 0){this.head nodethis.tail node}else{this.tail.next no…

hosts文件地址

Hosts是一个没有扩展名的系统文件&#xff0c;可以用记事本等工具打开&#xff0c;其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”&#xff0c;当用户在浏览器中输入一个需要登录的网址时&#xff0c;系统会首先自动从Hosts文件中寻找对应的IP地址&…