R中的实现:查找两个字符列表之间的距离

时间:2019-02-11 16:42:17

标签: r dataframe matrix datatable edit-distance

我是R的新手,并试图了解如何在R中实现以下算法。 我有两个字符列表,想看看这两个字符之间的最小距离是多少。

List 1: "a", "b", "c"
List 2: "a", "b", "c", "d"

第一步: 我创建了一个这样的表:

  a   b   c
a 0   1   2
b 1
c 2
d 3

第二步:我用0填充矩阵的其余部分

  a   b   c
a 0   1   2
b 1   0   0
c 2   0   0
d 3   0   0

现在,我要开始使用此算法计算这两个列表之间的距离并更新矩阵:

if (characters_in_header_of_matrix[i]==characters_in_column_of_matrix [j] & value[i,j] == value[i+1][j-1] )
then {get the 'diagonal value' #diagonal value= value[i, j-1]}

else{
value[i,j] = min(value[i-1, j], value[i-1, j-1],  value[i, j-1]) + 1
}
endif

为了找到您可以在矩阵的标题和列中看到的两个列表之间的差异,我使用了strcmp()函数。但是,我无法实现这一点。 最终结果应如下所示:

  a   b   c
a 0   1   2
b 1   0   1
c 2   1   0
d 3   2   1

感谢您的帮助。谢谢

1 个答案:

答案 0 :(得分:2)

在R中,您可以 使用for循环和条件进行暴力破解,但可以通过向量化方法轻松完成。好处可能是速度(尽管可能不是),但通常可以通过更简单的代码来理解,并且(一旦您可以使用这些功能)就可以提高可读性和可维护性。

以这个问题为例

l1 <- c("a", "b", "c")
l2 <- c("a", "b", "c", "d")

您要查找l1中每个字母与l2中每个字母之间的“距离”(即绝对距离)。 outer函数执行两个向量的"outer product"。例如,如果我们要建设性地(而不是实际地)进行outer(a:c, 1:3),它将配对a1a2a3b1,..., c3。 (那不是合法的R代码,只是用于演示,尽管只需添加少量的附加代码就可以很容易地完成它。)

在我们的案例中,如果执行outer(l1, l2),则它使用的函数默认为乘法(*),因为它的初始用法通常是线性代数,但是可以很容易地用{覆盖{1}}。在内部,它正在做的是创建两个(更长)的向量来完成所有配对。如果引入调试功能来检查状态,我们可以看到幕后发生的事情。

FUN=

debugfunc <- function(a, b) { browser(); 1; } 仅作为占位符。)

1

依次将outer(l1, l2, FUN=debugfunc) # Called from: FUN(X, Y, ...) # Browse[2]> a # <--- the object 'a' here is the first argument to this function # [1] "a" "b" "c" "a" "b" "c" "a" "b" "c" "a" "b" "c" # Browse[2]> b # <--- the second argument # [1] "a" "a" "a" "b" "b" "b" "c" "c" "c" "d" "d" "d" "a",然后将"a""b",然后将"a""c"配对,以此类推。第一个("a")向量,然后递增第二个向量,重复直到两个向量都用尽。此时,l1被这两个向量精确地调用了一次(有些人可能怀疑不是每对一次),因此您的debugfunc函数必须能够在一个调用中完成所有操作。 / p>

可能要看看这里的距离。您可以使用FUN=确定单个字母在字母表中的位置(同伴match("a", letters)是全大写字母)。通常,LETTERS查找第一个自变量在第二个自变量中的位置。因此,继续在match内:

debugfunc

因此,您真正想要的是这两个数值向量之间的差异。一个人可以轻松做到:

# Browse[2]> 
match(a, letters)
#  [1] 1 2 3 1 2 3 1 2 3 1 2 3
# Browse[2]> 
match(b, letters)
#  [1] 1 1 1 2 2 2 3 3 3 4 4 4

但是因为我们需要绝对距离,所以我们确实需要

# Browse[2]> 
match(a, letters) - match(b, letters)
#  [1]  0  1  2 -1  0  1 -2 -1  0 -3 -2 -1

好,所以我认为我们在这里有功能。让我们跳出调试器(# Browse[2]> abs( match(a, letters) - match(b, letters) ) # [1] 0 1 2 1 0 1 2 1 0 3 2 1 )并更正式地尝试一下:

Q

请注意,第一个参数成为行,因此长度为3的distfunc <- function(a, b) abs( match(a, letters) - match(b, letters) ) outer(l1, l2, FUN=distfunc) # [,1] [,2] [,3] [,4] # [1,] 0 1 2 3 # [2,] 1 0 1 2 # [3,] 2 1 0 1 给我们3行。如果您需要应用行/列名称,则:

l1

(更改参数的顺序将为您提供正要查找的矩阵。)