编辑距离 Edit Distance

编辑距离,又被称为Levenshtein距离,是指两个字符串之间,由其中一个转变成另一个所需的最小编辑操作次数。

比如:"sea" 转变为 "eat" 需要2次操作:

1、将 s 删除

2、在末尾添加 t

所以"sea"和"eat"两个字串的编辑距离为2。

这里需要注意的是:所谓的操作只包含 (1) 插入 (2) 删除 (3) 替换 ,并不包括字符的交换操作!

 

编辑距离的应用:

编辑距离可以表示两个字串的相似程度,编辑距离越小,两个字串相似度就越高。

1、DNA序列分析

2、拼写纠错

3、机器翻译

机器翻译通常使用的是Seq2seq模型。编辑距离可以作为Seq2seq的损失函数,即度量标记值和输出值之间的相似程度。

4、网址归类

性质相近的网站,它们的url地址通常也相似,比如csdn不同用户的网址。根据编辑距离可以有效地对网址进行大规模处理。

......

Levenshtein算法:

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] 的三条路径,而我们就是根据前一次状态,去选择能使当前状态最优的一条路径。

具体代码(Java):

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<matrix.length;i++) {
    		matrix[i][0] = i;
    	}
    	for(int i=0;i<matrix[0].length;i++) {
    		matrix[0][i] = i;
    	}
    	for(int i=0;i<word2.length();i++) {
    		char c2 = word2.charAt(i);
    		for(int j=0;j<word1.length();j++) {
    			char c1 = word1.charAt(j);
    			int cost = 0;
    			if(c1 != c2) cost = 1;
                        //状态转移方程
    			int[] nums = {matrix[j][i+1]+1,matrix[j+1][i]+1,matrix[j][i]+cost};
    			matrix[j+1][i+1] = Solution.Min(nums);
    		}
    	}
    	return matrix[word1.length()][word2.length()];
    }

}

Levenshtein在Python中的应用:

现在Levenshtein算法已经有现成的模块可以调用,所以在这里介绍一下python-Levenshtein,希望对大家在NLP领域的应用有所帮助。

首先需要安装Levenshtein相关包,安装语句如下:

pip install python-Levenshtein

下面是一些Levenshtein中具体的方法和应用:

http://nbviewer.jupyter.org/github/DiggerWang/Levenshtein/blob/master/Levenshtein.ipynb

猜你喜欢

转载自blog.csdn.net/qq_38310176/article/details/81149558