两个向量之间的欧几里得距离

55

如何计算两个向量之间的欧几里得距离:

x1 <- rnorm(30)
x2 <- rnorm(30)
5个回答

72

使用dist()函数,但是你需要将前面的两个输入组成一个矩阵作为dist()的第一个参数:

dist(rbind(x1, x2))

对于OP问题中的输入,我们得到:

> dist(rbind(x1, x2))
        x1
x2 7.94821

一个单一的值,即x1x2之间的欧几里得距离。


7
我应该得到一个单一的距离度量作为答案,但你的解决方案给了我一个矩阵。 - Jana
通过上述示例数据,结果是一个单一的值。要求“单一距离度量”的评论可能是由于使用了不同的数据结构?! - BurninLeo
@Jana,我不知道你是如何从dist()中获取矩阵的,如果x1x2只是OP中的两个向量。你使用了cbind()吗? - Gavin Simpson

46

根据维基百科上的定义,这应该可以做到。

euc.dist <- function(x1, x2) sqrt(sum((x1 - x2) ^ 2))

还有一个fields包中的rdist函数也可能很有用。请参见这里


编辑:**运算符更改为^。感谢Gavin。


2
在我的Ubuntu系统中,dist(rbind(x1,x2))的速度快了三倍。 - JohnTortugo
5
我刚在Ubuntu上的R 3.0.2上尝试了这种方法,相比于“dist(rbind())”方法,我发现这种方法对我来说快了约12倍。(使用命令"system.time({a <- c(2,6,78); b <- c(4,6,2); for (i in 1:1000000) {dist(rbind(a,b))} })"进行测试) - naught101

17

试着使用这个:

sqrt(sum((x1-x2)^2))

3
如果您想使用更少的代码,也可以在stats中使用norm('F'代表Forbenius,即欧几里得范数):
norm(matrix(x1-x2), 'F')

尽管这样看起来更整洁,但并不更快。事实上,在非常大的向量上进行快速测试并没有显示出太大的差异,尽管so12311的方法略微更快。我们首先定义:
set.seed(1234)
x1 <- rnorm(300000000)
x2 <- rnorm(300000000)

然后测试时间产生以下结果:
> system.time(a<-sqrt(sum((x1-x2)^2)))
user  system elapsed 
1.02    0.12    1.18 
> system.time(b<-norm(matrix(x1-x2), 'F'))
user  system elapsed 
0.97    0.33    1.31 

0
如果您需要快速计算一个向量与多个向量矩阵之间的欧几里得距离,那么您可以使用此答案中提到的tcrossprod方法。
bench=function(...,n=1,r=3){
  a=match.call(expand.dots=F)$...
  t=matrix(ncol=length(a),nrow=n)
  for(i in 1:length(a))for(j in 1:n){t1=Sys.time();eval(a[[i]],parent.frame());t[j,i]=Sys.time()-t1}
  o=t(apply(t,2,function(x)c(median(x),min(x),max(x),mean(x))))
  round(100*`dimnames<-`(o,list(names(a),c("median","min","max","mean"))),r)
}

es=3:6
r=sapply(es,function(e){
  m=matrix(rnorm(10^e),ncol=10)
  v=rnorm(10)
  bench(n=10,
    tcrossprod={sqrt(outer(rowSums(m^2),rowSums(t(v)^2),"+")-tcrossprod(m,2*t(v)))},
    Rfast_dista={Rfast::dista(m,t(v))},
    vectorized={sapply(colSums((v-t(m))^2),sqrt)},
    regular={apply(m,1,function(x)sqrt(sum((v-x)^2)))},
    dotproduct={apply(m,1,function(x){q=v-x;sqrt(q%*%q)})},
    norm={apply((v-t(m)),2,function(x)norm(as.matrix(x),"F"))},
    rbind_single={apply(m,1,function(x)dist(rbind(v,x))[1])},
    rbind_all={if(e<=5)unname(as.matrix(dist(rbind(v,m)))[1,-1])})[,1]
})

colnames(r)=paste0("1e",es)
r[8,4]=NA
round(r,3)

输出:

               1e3   1e4     1e5     1e6
tcrossprod   0.004 0.012   0.093   0.972
Rfast_dista  0.003 0.013   0.115   1.148
vectorized   0.006 0.038   0.366   3.835
regular      0.021 0.181   1.901  20.437
dotproduct   0.020 0.183   2.010  24.560
norm         0.057 0.562   6.017  62.532
rbind_single 0.159 1.592  16.982 181.834
rbind_all    0.036 3.493 530.259      NA

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