编辑距离,又被称为Levenshtein距离,是指两个字符串之间,由其中一个转变成另一个所需的最小编辑操作次数。
比如:"sea" 转变为 "eat" 需要2次操作:
1、将 s 删除
2、在末尾添加 t
所以"sea"和"eat"两个字串的编辑距离为2。
这里需要注意的是:所谓的操作只包含 (1) 插入 (2) 删除 (3) 替换 ,并不包括字符的交换操作!
编辑距离可以表示两个字串的相似程度,编辑距离越小,两个字串相似度就越高。
1、DNA序列分析
2、拼写纠错
3、机器翻译
机器翻译通常使用的是Seq2seq模型。编辑距离可以作为Seq2seq的损失函数,即度量标记值和输出值之间的相似程度。
4、网址归类
性质相近的网站,它们的url地址通常也相似,比如csdn不同用户的网址。根据编辑距离可以有效地对网址进行大规模处理。
......
Levenshtein算法的本质其实是动态规划。以 "holiday" 和 "today" 为例,它的具体步骤是:
1、建立一个二维数组,大小为 (word1.length+1)*(word2.length+1)
t | o | d | a | y | ||
h | ||||||
o | ||||||
l | ||||||
i | ||||||
d | ||||||
a | ||||||
y |
2、将数组的第一行和第一列设定为0—n:
t | o | d | a | y | ||
0 | 1 | 2 | 3 | 4 | 5 | |
h | 1 | |||||
o | 2 | |||||
l | 3 | |||||
i | 4 | |||||
d | 5 | |||||
a | 6 | |||||
y | 7 |
这一步的本质其实是计算空字符转化为对应字符需要的操作次数。比如:matrix[0][0]=0代表空字符转空字符需要0次操作;matrix[1][0]=1代表空字符转"h"需要1次操作;matrix[2][0]=2代表空字符转"ho"需要两次操作……以此类推。
3、假设当前遍历到i、j,判断当前行对应的字母是否等于当前列对应的字母。如果相等,记操作代价cost=0;如果不等,记操作代价cost=1。然后matrix[i][j] = min( matrix[i-1][j]+1, matrix[i][j-1]+1, matrix[i-1][j-1]+cost )。
按照上述原则,最后得到完整的matrix为:
t | o | d | a | y | ||
0 | 1 | 2 | 3 | 4 | 5 | |
h | 1 | 1 | 1 | 2 | 3 | 4 |
o | 2 | 2 | 1 | 2 | 3 | 4 |
l | 3 | 3 | 2 | 2 | 3 | 4 |
i | 4 | 4 | 3 | 3 | 3 | 4 |
d | 5 | 5 | 4 | 3 | 4 | 4 |
a | 6 | 6 | 5 | 4 | 3 | 4 |
y | 7 | 7 | 6 | 5 | 4 | 3 |
matrix中的最后一个元素即为编辑距离!所以Edit_Distance( holiday, today ) = 3。
那么上述步骤到底在做些什么呢?我们来看一下结果:
t | o | d | a | y | ||
0 | 1 | 2 | 3 | 4 | 5 | |
h | 1 | 1 | 1 | 2 | 3 | 4 |
o | 2 | 2 | 1 | 2 | 3 | 4 |
l | 3 | 3 | 2 | 2 | 3 | 4 |
i | 4 | 4 | 3 | 3 | 3 | 4 |
d | 5 | 5 | 4 | 3 | 4 | 4 |
a | 6 | 6 | 5 | 4 | 3 | 4 |
y | 7 | 7 | 6 | 5 | 4 | 3 |
首先,假设蓝色部分是matrix[i][j],绿色部分matrix[i-1][j-1]代表由h转为t所需的操作,如果i行和j列对应的字母相等,那就说明新加一个字母不会引起操作次数的增加,所以cost=0,即matrix[i][j] = matrix[i-1][j-1]。"h" -> "t"需要1次操作,同时加上一个"o","ho" -> "to"同样只需要1次操作。
再看一下黄色的部分,假设黄色部分是matrix[i][j],显然matrix[i][j] = matrix[i][j-1]+1。matrix[i-1][j]+1 和 matirx[i][j-1]+1 的作用主要体现在当字符串长度不一样的时候,在图中,就是表示说会选择从"to"转变为"holid",而不是选择从"t"转变为"holid"。+1代表的意思就是在原来的基础上进行一次插入操作。
总体来看,其实就是一个动态规划的过程:matrix[i-1][j-1]、matrix[i-1][j] 和 matrix[i][j-1] 是到达 matrix[i][j] 的三条路径,而我们就是根据前一次状态,去选择能使当前状态最优的一条路径。
public class Solution {
//求nums数组中的最小值
public static int Min(int[] nums) {
int min = 100;
for(int i:nums) {
if(i < min) min = i;
}
return min;
}
public int minDistance(String word1, String word2) {
int[][] matrix = new int[word1.length()+1][word2.length()+1];
//初始化第一行和第一列
for(int i=0;i
现在Levenshtein算法已经有现成的模块可以调用,所以在这里介绍一下python-Levenshtein,希望对大家在NLP领域的应用有所帮助。
首先需要安装Levenshtein相关包,安装语句如下:
pip install python-Levenshtein
下面是一些Levenshtein中具体的方法和应用:
http://nbviewer.jupyter.org/github/DiggerWang/Levenshtein/blob/master/Levenshtein.ipynb