使用R向量化双重求和

时间:2017-04-22 16:35:10

标签: r math addition

我正在努力使用via vectorization技术将此函数转换为R:

enter image description here

到目前为止,我能做到的只有:

c <- matrix(1:9, 3)
z <- 1:3

sum(abs(outer(z, z,"-")) * c)/sum(c)

但我不认为它必然是正确的。我尝试了一个for循环版本,但这太长了,无论如何我的答案可能都是错误的。有人热衷于此吗?我错过了什么(或做错了什么)?任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:3)

这是一个双循环版本:

q = 
function(z,c){
num = 0
 for(i in 1:length(z)){
  for(j in 1:length(z)){
    num = num + abs(z[i]-z[j]) * c[i,j]
  }
 }
num/sum(c)
}

这是你的矢量化版本,功能化:

q2 = 
function(z,c){sum(c*abs(outer(z,z,'-')) /sum(c))}

对于小矩阵来说,它们之间的时序差别不大:

> microbenchmark::microbenchmark(q(z,c), q2(z,c))
Unit: microseconds
     expr    min      lq     mean  median      uq    max neval cld
  q(z, c) 15.368 15.7505 16.59644 16.0225 16.6290 30.346   100   b
 q2(z, c) 12.232 12.8885 13.79178 13.2225 13.6585 44.085   100  a 

但是对于更大的测试来说,这是一个巨大的胜利:

> c2 = matrix(runif(100*100),100,100)
> z2 = runif(100)
> microbenchmark::microbenchmark(q(z2,c2), q2(z2,c2))
Unit: microseconds
       expr      min       lq       mean   median       uq       max neval cld
  q(z2, c2) 7437.031 7588.131 8046.92272 7794.927 8332.104 10729.799   100   b
 q2(z2, c2)   74.742   78.647   94.20153   86.113  100.125   188.428   100  a 
> 

数值差异在浮点容差范围内:

> q(z2,c2) - q2(z2,c2)
[1] 6.661338e-16

因此,除非有人有更快的代码,否则我会坚持你所拥有的。

答案 1 :(得分:1)

正如@Spacedman完美解释的那样,你的方法非常有效,但如果你还想加快速度,可以试试Rcpp:

library(Rcpp)

sourceCpp(code='
#include <Rcpp.h>

// [[Rcpp::export]]
double qRcpp(const Rcpp::NumericVector z, const Rcpp::NumericMatrix cm){
  int zlen = z.length();
  if(!(zlen == cm.nrow() && cm.nrow() == cm.ncol()))
    Rcpp::stop("Invalid sizes");

  double num = 0;
  for(int i = 0 ; i < zlen ; i++){
    for(int j = 0 ; j < zlen ; j++){
      num = num + std::abs(z[i]-z[j]) * cm(i,j);
    }
  } 
  return num / Rcpp::sum(cm);
}

')

基准:

c2 = matrix(runif(100*100),100,100)
z2 = runif(100)
microbenchmark::microbenchmark(q(z2,c2), q2(z2,c2),qRcpp(z2,c2))
# Unit: microseconds
#           expr       min         lq        mean    median         uq       max neval
#      q(z2, c2) 10273.035 10976.3050 11680.85554 11348.763 11765.2010 44115.632   100
#     q2(z2, c2)    64.292    67.9455    80.56427    75.543    86.3565   244.019   100
#  qRcpp(z2, c2)    21.042    21.9180    25.30515    24.256    26.8860    56.403   100