Python 最小编辑距离重建
我知道在堆栈上和在线上都有类似的答案,但我觉得我遗漏了一些东西。给定下面的代码,我们需要重建导致产生最小编辑距离的事件序列。对于下面的代码,我们需要编写一个输出:Python 最小编辑距离重建,python,matrix,nlp,dynamic-programming,Python,Matrix,Nlp,Dynamic Programming,我知道在堆栈上和在线上都有类似的答案,但我觉得我遗漏了一些东西。给定下面的代码,我们需要重建导致产生最小编辑距离的事件序列。对于下面的代码,我们需要编写一个输出: Equal, L, L Delete, E Equal, A, A Substitute, D, S Insert, T 编辑:使用我的(部分正确的)解决方案更新代码 下面是代码,以及我的部分解决方案。例如,它适用于我被给予(“lead”->“last”),但不适用于下面的示例(“hint”->“isnt”)。我怀疑这是因为第一个字
Equal, L, L
Delete, E
Equal, A, A
Substitute, D, S
Insert, T
编辑:使用我的(部分正确的)解决方案更新代码
下面是代码,以及我的部分解决方案。例如,它适用于我被给予(“lead”->“last”),但不适用于下面的示例(“hint”->“isnt”)。我怀疑这是因为第一个字符是相等的,这会使我的代码失效。任何正确方向的提示或指针都将非常棒
def printMatrix(M):
for row in M:
print row
print
def med(s, t):
k = len(s) + 1
l = len(t) + 1
M = [[0 for i in range(k)] for j in range(l)]
MTrace = [["" for i in range(k)] for j in range(l)]
M[0][0] = 0
for i in xrange(0, k):
M[i][0] = i
MTrace[i][0] = s[i-1]
for j in xrange(0, l):
M[0][j] = j
MTrace[0][j] = t[j-1]
MTrace[0][0] = "DONE"
for i in xrange(1, k):
for j in xrange(1, l):
sub = 1
sub_op = "sub"
if s[i-1] == t[j-1]:
# equality
sub = 0
sub_op = "eq"
# deletion
min_value = M[i-1][j] + 1
op = "del"
if min_value > M[i][j-1] + 1:
# insertion
min_value = M[i][j-1] + 1
op = "ins"
if min_value > M[i-1][j-1] + sub:
# substitution
min_value = M[i-1][j-1] + sub
op = sub_op
M[i][j] = min_value
MTrace[i][j] = op
print "final Matrix"
printMatrix(M)
printMatrix(MTrace)
############ MY PARTIAL SOLUTION
def array_append(array,x,y):
ops_string = MTrace[x][y]
if ops_string == 'ins':
array.append(("Insert",MTrace[0][y]))
elif ops_string == 'sub':
array.append(("Substitute",MTrace[x][0],MTrace[0][y]))
elif ops_string == 'eq':
array.append(("Equal",MTrace[x][0],MTrace[0][y]))
elif ops_string == 'del':
array.append(("Delete",MTrace[x][0]))
i = len(s)
j = len(t)
ops_array = []
base = M[i][j]
array_append(ops_array,i,j)
while MTrace[i][j] != "DONE":
base = M[i][j]
local_min = min(M[i][j-1],M[i-1][j],M[i-1][j-1])
if base == local_min:
i = i - 1
j = j - 1
array_append(ops_array,i,j)
elif M[i][j-1] < M[i-1][j]:
j = j -1
array_append(ops_array,i,j)
elif M[i-1][j] < M[i][j-1]:
i = i - 1
array_append(ops_array,i,j)
else:
i = i - 1
j = j - 1
array_append(ops_array,i,j)
print ops_array
#########
return M[k-1][l-1]
print med('lead', 'last')
def打印矩阵(M):
对于以M为单位的行:
打印行
打印
def med(s,t):
k=透镜+1
l=len(t)+1
M=[[0代表范围(k)中的i]代表范围(l)中的j]
MTrace=[[“”表示范围(k)中的i]表示范围(l)中的j]
M[0][0]=0
对于x范围内的i(0,k):
M[i][0]=i
MTrace[i][0]=s[i-1]
对于X范围内的j(0,l):
M[0][j]=j
MTrace[0][j]=t[j-1]
MTrace[0][0]=“完成”
对于x范围内的i(1,k):
对于X范围内的j(1,l):
sub=1
sub_op=“sub”
如果s[i-1]==t[j-1]:
#平等
sub=0
sub_op=“eq”
#删除
最小值=M[i-1][j]+1
op=“del”
如果最小值>M[i][j-1]+1:
#插入
最小值=M[i][j-1]+1
op=“ins”
如果最小值>M[i-1][j-1]+sub:
#替代品
最小值=M[i-1][j-1]+sub
op=sub_op
M[i][j]=最小值
MTrace[i][j]=op
打印“最终矩阵”
打印矩阵(M)
打印矩阵(MTrace)
############我的偏解
def array_append(数组,x,y):
ops_string=MTrace[x][y]
如果ops_字符串=='ins':
array.append((“Insert”,MTrace[0][y]))
elif ops_string==“sub”:
array.append((“替换”,MTrace[x][0],MTrace[0][y]))
elif ops_字符串=='eq':
array.append((“Equal”,MTrace[x][0],MTrace[0][y]))
elif ops_string==“del”:
array.append((“Delete”,MTrace[x][0]))
i=len(s)
j=len(t)
ops_数组=[]
基数=M[i][j]
数组附加(操作数组,i,j)
而MTrace[i][j]!=“完成”:
基数=M[i][j]
局部_min=min(M[i][j-1],M[i-1][j],M[i-1][j-1])
如果基==局部最小值:
i=i-1
j=j-1
数组附加(操作数组,i,j)
elif M[i][j-1]
我建议您看看该模块。这可能会让你有很长的路要走:
>>> import Levenshtein
>>> Levenshtein.editops('LEAD','LAST')
[('replace', 1, 1), ('replace', 2, 2), ('replace', 3, 3)]
您可以处理编辑操作的输出以创建详细的指令。我认为,在这种情况下,更深入地理解算法非常重要。我将引导您完成算法的基本步骤,并向您展示所需数据如何在最终生成的矩阵中“编码”,而不是给您一些伪代码。当然,如果您不需要使用自己的算法,那么您显然应该使用其他人的算法,例如 大局 在我看来,这就像是。基本思想是计算“附近”前缀之间的距离,取最小值,然后计算当前字符串对与该前缀之间的距离。例如,假设您有两个字符串
'i'
和'h'
。让我们沿着矩阵的垂直轴和水平轴进行布局,如下所示:
_ h
_ 0 1
i 1 1
这里,'
表示一个空字符串,矩阵中的每个单元格对应一个编辑序列,该序列将输入('
或'i'
)转换为输出('
或'h'
)
从空字符串到长度为L的任何字符串的距离为L(需要插入L)。长度为L的任何字符串到空字符串的距离也是L(需要删除L)。这包括第一行和第一列中的值,它们只是增量
在此基础上,您可以通过从左上角、左上角和左上角的值中取最小值并添加一个值来计算任何位置的值,或者,如果字符串中该点的字母相同,则取左上角的值不变。对于上表中(1,1)
处的值,在(0,0)
处的最小值是0
,因此(1,1)
处的值是1
,这是从'i'
到'h'
的最小编辑距离(一次替换)。所以一般来说,最小编辑距离总是在矩阵的右下角
现在让我们做另一个,比较is
和hi
。这里,矩阵中的每个单元格都对应一个编辑序列,该序列将输入('
,'i'
,或'is'
)转换为输出('
,'h'
,或'hi'
)
我们首先放大矩阵,使用#
作为p
_ h i
_ 0 1 2
i 1 1 #
s 2 # #
_ h i
_ 0 1 2
i 1 1 #
s 2 2 #
_ h i
_ 0 1 2
i 1 1 1
s 2 2 #
_ h i
_ 0 1 2
i 1 1 1
s 2 2 2
_ h i n t
_ 0 1 2 3 4
i 1 1 1 2 3
s 2 2 2 2 3
n 3 3 3 2 3
t 4 4 4 3 2
(4, 4) -> (3, 3) -> (2, 2) -> (1, 2) -> (0, 1) -> (0, 0)
(4, 4) -> (3, 3) -> (2, 2) -> (1, 1) -> (0, 0)
(0, 0) -> (0, 1) -> (1, 2) -> (2, 2) -> (3, 3) -> (4, 4)
(0, 0) -> (1, 1) -> (2, 2) -> (3, 3) -> (4, 4)
Insert, h
Equal, i, i
Delete, s
Equal, n, n
Equal, t, t
isnt (No change)
hisnt (Insertion)
hisnt (No change)
hint (Deletion)
hint (No change)
hint (No change)
[TestMethod]
public void TestEditDistance()
{
var expected = new[]
{
Move.Delete,
Move.Substitute,
Move.Match,
Move.Match,
Move.Match,
Move.Match,
Move.Match,
Move.Insert,
Move.Substitute,
Move.Match,
Move.Substitute,
Move.Match,
Move.Match,
Move.Match,
Move.Match
};
Assert.IsTrue(expected.SequenceEqual(new EditDistanceCalculator().CalcEditDistance("thou-shalt-not", "you-should-not")));
var calc = new EditDistanceCalculator(3, 1, 1);
var edit = calc.CalcEditDistance("democrat", "republican");
Console.WriteLine(string.Join(",", edit));
Assert.AreEqual(3, edit.Count(m => m == Move.Match)); //eca
}