为什么R diff功能慢?

时间:2017-02-12 18:17:41

标签: r diff benchmarking

在R中使用向量时,diff函数计算每个值与前一个值之间的差异。来自?diff

  

如果x是长度为ndifferences = 1的向量,则计算结果等于连续差异x[(1+lag):n] - x[1:(n-lag)]

但是,当我测试diff函数的执行时间与其理论表达式(使用microbenchmark包中的microbenchmark函数)时,diff函数速度较慢。这是我的代码:

library(microbenchmark)

mb.diff1 <- function(n, seed){
  set.seed(seed)
  vec <- runif(n)
  out <- diff(vec)
  return(out)
}

mb.diff2 <- function(n, seed){
  set.seed(seed)
  vec <- runif(n)
  out <- vec[2:n]-vec[1:(n-1)]
  return(out)
}

times.diff1 <- c()  
times.diff2 <- c()
vec.sizes <- c(1e1, 1e2, 1e3, 1e4)
for (n in vec.sizes){
  bench <- microbenchmark(
    mb.diff1(n,1),
    mb.diff2(n,1))
  times.median <- aggregate(
    bench$time,
    by  = list(bench$expr), 
    FUN = median)
  times.diff1 <- c(times.diff1, times.median[1,2])
  times.diff2 <- c(times.diff2, times.median[2,2])
}

perf.ratio <- times.diff1/times.diff2
names(perf.ratio) <- vec.sizes
print(perf.ratio)

我完成了1e4的vec.sizes,所以你们的执行时间不会太长,但我会让它们持续到1e7。你可以在这里看到结果:

enter image description here

如您所见,diff函数对于所有矢量大小都较慢。由于在两种情况下执行时间都是矢量大小的线性函数,因此商容趋于减小,因此我们不能说diff在n增加时表现更好。所以问题出现了:

  1. (显而易见的问题)在测量执行时间时,我的代码是否出错?
  2. diff函数的原因可能比理论表达式慢?
  3. 您是否知道计算差异向量的最有效方法是x[(1+lag):n] - x[1:(n-lag)]
  4. 我在Linux中使用R 3.1.2。

    非常感谢你。

1 个答案:

答案 0 :(得分:0)

以下是一些有助于扩展和说明我在评论中提出的观点的代码。

library(microbenchmark)

mb.diff2 <- compiler::cmpfun(function(vec) {
  n <- length(vec)
  vec[2:n]-vec[1:(n-1L)]
})

times.diff1 <- c()  
times.diff2 <- c()
times.diff3 <- c()
vec.sizes <- c(1e1, 1e2, 1e3, 1e4, 1e5)

for (n in vec.sizes) {
  set.seed(21)
  vec <- runif(n)
  bench <- microbenchmark(diff(vec), mb.diff2(vec), diff.default(vec))
  times.median <- aggregate(bench$time, by = list(bench$expr), FUN = median)
  times.diff1 <- c(times.diff1, times.median[1,2])
  times.diff2 <- c(times.diff2, times.median[2,2])
  times.diff3 <- c(times.diff3, times.median[3,2])
}

setNames(times.diff1/times.diff2, vec.sizes)
setNames(times.diff1/times.diff3, vec.sizes)

首先,您会注意到我编译了mb.diff2函数。这是因为diffdiff.default是字节编译的。我还将n的计算放在mb.diff2内,因为计算向量长度应该是测量函数调用的一部分。

以下是时间的结果以及我的sessionInfo()

R> setNames(times.diff1/times.diff2, vec.sizes)
       10       100      1000     10000     1e+05 
3.5781536 2.3330988 1.2488135 0.9011312 0.9660411 
R> setNames(times.diff1/times.diff3, vec.sizes)
       10       100      1000     10000     1e+05 
1.5945010 1.4609283 1.1021190 1.0034623 0.9987618 
R> sessionInfo()
R version 3.3.2 (2016-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.1 LTS

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] microbenchmark_1.4-2

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.9      digest_0.6.8     MASS_7.3-45      grid_3.3.2      
 [5] plyr_1.8.4       gtable_0.1.2     magrittr_1.5     scales_0.3.0    
 [9] ggplot2_1.0.1    stringi_0.4-1    reshape2_1.4.1   proto_0.3-10    
[13] tools_3.3.2      stringr_1.0.0    munsell_0.4.2    compiler_3.3.2  
[17] colorspace_1.2-6