两个独立数据框的距离矩阵

5

我想创建一个矩阵,其中包含一个数据框的行与另一个数据框的行之间的欧几里得距离。例如,假设我有以下数据框:

a <- c(1,2,3,4,5)
b <- c(5,4,3,2,1)
c <- c(5,4,1,2,3)
df1 <- data.frame(a,b,c)

a2 <- c(2,7,1,2,3)
b2 <- c(7,6,5,4,3)
c2 <- c(1,2,3,4,5)
df2 <- data.frame(a2,b2,c2)

我想创建一个矩阵,用于存储df1的每一行与df2的距离。因此,矩阵[2,1]应该是df1[2,]和df2[1,]之间的欧几里得距离,矩阵[3,2]应该是df1[3,]和df2[2,]之间的距离,以此类推。有没有人知道如何实现这个功能?
2个回答

8
也许你可以使用fields包:函数rdist 可能是你想要的:

rdist: 欧几里得距离矩阵
描述:给定两组位置,计算所有配对之间的欧几里得距离矩阵。

> rdist(df1, df2)
     [,1]     [,2]     [,3]     [,4]     [,5]
[1,] 4.582576 6.782330 2.000000 1.732051 2.828427
[2,] 4.242641 5.744563 1.732051 0.000000 1.732051
[3,] 4.123106 5.099020 3.464102 3.316625 4.000000
[4,] 5.477226 5.000000 4.358899 3.464102 3.316625
[5,] 7.000000 5.477226 5.656854 4.358899 3.464102

类似的情况也出现在pdist包中。

pdist:分区矩阵中观测值之间的距离
描述:计算矩阵X的行与另一个矩阵Y的行之间的欧几里得距离。

> pdist(df1, df2)
An object of class "pdist"
Slot "dist":
[1] 4.582576 6.782330 2.000000 1.732051 2.828427 4.242640 5.744563 1.732051
[9] 0.000000 1.732051 4.123106 5.099020 3.464102 3.316625 4.000000 5.477226
[17] 5.000000 4.358899 3.464102 3.316625 7.000000 5.477226 5.656854 4.358899
[25] 3.464102
attr(,"Csingle")
[1] TRUE

Slot "n":
[1] 5

Slot "p":
[1] 5

Slot ".S3Class":
[1] "pdist"

注意:如果您正在寻找行之间的欧几里得范数,您可以尝试以下方法:

a <- c(1,2,3,4,5)
b <- c(5,4,3,2,1)
c <- c(5,4,1,2,3)
df1 <- rbind(a, b, c)

a2 <- c(2,7,1,2,3)
b2 <- c(7,6,5,4,3)
c2 <- c(1,2,3,4,5)
df2 <- rbind(a2,b2,c2)

rdist(df1, df2)

这将得到:
> rdist(df1, df2)
         [,1]     [,2]     [,3]
[1,] 6.164414 7.745967 0.000000
[2,] 5.099020 4.472136 6.324555
[3,] 4.242641 5.291503 5.656854

这看起来很有用,但不是一个答案。你应该展示如何在问题的数据上实现答案;仅提供链接的答案在SO上表现不佳。 - alistaire
@alistaire 感谢你的评论。这就是它应该看起来的样子吗? - Diego
1
是的,这样好多了! - alistaire
如何将每个数据框的标签 (a、b、c、a1、b2、c2) 包含到 rdist 输出中? - Amc

2
这是从我之前在这里的回答进行改编的。
对于一般的n维欧几里得距离,我们可以利用以下方程(不是R,而是代数):
square_dist(b,a) = sum_i(b[i]*b[i]) + sum_i(a[i]*a[i]) - 2*inner_prod(b,a)

这里的求和是针对向量 ab 的维度,其中 i=[1,n]。在这里,ab 分别是来自 df1df2 的一对列。关键在于,该方程可以被写成一个矩阵方程,适用于 df1df2 中所有的列对。

代码示例:

d <- sqrt(matrix(rowSums(expand.grid(rowSums(df1*df1),rowSums(df2*df2))),
                 nrow=nrow(df1)) - 
          2. * as.matrix(df1) %*% t(as.matrix(df2)))

注意:

  1. inner rowSums计算每个a(在df1)和b(在df2)的sum_i(a[i]*a[i])sum_i(b[i]*b[i])
  2. expand.grid生成df1df2之间的所有数据对。
  3. outer rowSums计算所有这些数据对的sum_i(a[i]*a[i]) + sum_i(b[i]*b[i])
  4. 然后将结果重新排列成一个matrix。请注意,此矩阵的行数是df1的行数。
  5. 最后,减去所有数据对的内积的两倍。这个内积可以写成矩阵乘法df1 %*% t(df2),其中我省略了为清晰起见的强制转换为矩阵的步骤。
  6. 最终,取平方根。

使用您的数据运行此代码:

print(d)
##         [,1]     [,2]     [,3]     [,4]     [,5]
##[1,] 4.582576 6.782330 2.000000 1.732051 2.828427
##[2,] 4.242641 5.744563 1.732051 0.000000 1.732051
##[3,] 4.123106 5.099020 3.464102 3.316625 4.000000
##[4,] 5.477226 5.000000 4.358899 3.464102 3.316625
##[5,] 7.000000 5.477226 5.656854 4.358899 3.464102

请注意,此代码适用于任何n>1。在您的情况下,n=3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接