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

一、说明

        编辑距离是一种文本相似度度量,用于测量 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.hqwc.cn/news/168977.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Round 908 (Div. 2)题解

目录 A. Secret Sport 题目分析: B. Two Out of Three 题目分析: C. Anonymous Informant 题目分析: A. Secret Sport 题目分析: A,B一共打n场比赛&#xff0c;输入一个字符串由A和‘B’组成代表A赢或者B赢&#xff08;无平局&#xff09;&#xff0c;因为题目说明这个人…

FPGA与STM32_FSMC总线通信实验

FPGA与STM32_FSMC总线通信实验 内部存储器IP核的参数设置创建IP核FPGA代码STM32标准库的程序 STM32F407 上自带 FSMC 控制器&#xff0c;通过 FSMC 总线的地址复用模式实现STM32 与 FPGA 之间的通信&#xff0c;FPGA 内部建立 RAM 块&#xff0c;FPGA 桥接 STM32 和 RAM 块&…

图论13-最小生成树-Kruskal算法+Prim算法

文章目录 1 最小生成树2 最小生成树Kruskal算法的实现2.1 算法思想2.2 算法实现2.2.1 如果图不联通&#xff0c;直接返回空&#xff0c;该图没有mst2.2.2 获得图中的所有边&#xff0c;并且进行排序2.2.2.1 Edge类要实现Comparable接口&#xff0c;并重写compareTo方法 2.2.3 取…

网络运维Day10

文章目录 SHELL基础查看有哪些解释器使用usermod修改用户解释器BASH基本特性 shell脚本的设计与运行编写问世脚本脚本格式规范执行shell脚本方法一方法二实验 变量自定义变量环境变量位置变量案例 预定义变量 变量的扩展运用多种引号的区别双引号的应用单引号的应用反撇号或$()…

HTML使用lable将文字与控件进行关联以获取焦点

先养养眼再往下看 注释很详细&#xff0c;直接上代码 <form action""><!-- 第一种方法:用id的方式绑定账户(文字)和输入框 --><label for"zhanghu">账户</label><input "text" id"zhanghu" name"ac…

一步一步详细介绍如何使用 OpenCV 制作低成本立体相机

在这篇文章中,我们将学习如何创建定制的低成本立体相机(使用一对网络摄像头)并使用 OpenCV 捕获 3D 视频。我们提供 Python 和 C++ 代码。文末并附完整的免费代码下载链接 我们都喜欢观看上面所示的 3D 电影和视频。您需要如图 1 所示的红青色 3D 眼镜才能体验 3D 效果。它是…

时间序列预测实战(九)PyTorch实现LSTM-ARIMA融合移动平均进行长期预测

一、本文介绍 本文带来的是利用传统时间序列预测模型ARIMA(注意&#xff1a;ARIMA模型不属于机器学习)和利用PyTorch实现深度学习模型LSTM进行融合进行预测&#xff0c;主要思想是->先利用ARIMA先和移动平均结合处理数据的线性部分&#xff08;例如趋势和季节性&#xff09…

C语言求解猴子分桃问题

题目&#xff1a; 海滩上有一堆桃子&#xff0c;五只猴子来分。第一只猴子把这堆桃子凭据分为五份&#xff0c;多了 一个&#xff0c;这只猴子把多的一个扔入海中&#xff0c;拿走了一份。第二只猴子把剩下的桃子又平均分 成五份&#xff0c;又多了一个&#xff0c;它同样把多…

HCIA-DHCP+DHCP中继

DHCPDHCP中继 实验拓扑配置步骤第一步 配置Eth-Trunk聚合链路&二层VLAN第二步 配置IP地址第三步 配置DHCPDHCP中继 配置验证查看PC1 PC2是否正确的获得了IP地址 实验拓扑 配置步骤 第一步 配置Eth-Trunk聚合链路&二层VLAN SW1 sysname SW1 # undo info-center enabl…

男科医院服务预约小程序的作用是什么

医院的需求度从来都很高&#xff0c;随着技术发展&#xff0c;不少科目随之衍生出新的医院的&#xff0c;比如男科医院、妇科医院等&#xff0c;这使得目标群体更加精准&#xff0c;同时也赋能用户可以快速享受到服务。 当然相应的男科医院在实际经营中也面临痛点&#xff1a;…

SAM + YOLO 智能抠图

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

【PyQt】(自制类)简易的控件画布

说一下标题的意思&#xff0c;就是一个可往上面放QtWidgets控件(例如QLabel、QPushButton)并且画布可拖拽缩放的一个简易画布类。 强调一下的就是&#xff0c;这和涂鸦画布(类比于win自带的画图软件)不是同个东西。 只不过通过这个自制类我明白了一点的就是控件数量太多会造成…