2017-02-12 90 views
1

使用R中的向量时,diff函数会计算每个值与前一个值之间的差异。从?diffR diff函数为什么很慢?

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

然而,当我测试的执行时间diff函数的VS其理论表达式(使用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,所以excution时间为你们并不需要太长时间,但我让他们去,直到1E7。你可以看到结果这里:

enter image description here

正如你所看到的,diff功能是所有矢量大小慢。商数趋于减少,因为在两种情况下,执行时间似乎都是向量大小的线性函数,所以我们不能说随着n的增加diff表现更好。因此,这里提出的问题:

  1. (显而易见的问题)我在测量执行时间时在代码中做错了什么?
  2. diff函数的原因是什么可能比他们的理论表达式慢?
  3. 你知道计算差异向量的最有效方法吗?比x[(1+lag):n] - x[1:(n-lag)]

我在Linux中使用R 3.1.2。

非常感谢您提前。

+2

R-3.1.2是2岁以上。你的时间安排包括产生一个随机向量,所以你并不是孤立你所要求的差异。使用只调用'diff'和'vec []'的简化函数,在我运行R-3.3.2的Ubuntu 14.04机器上,'diff'更快。 'diff'也是通用的,所以方法调度有一定的成本。直接调用'diff.default'(通常不推荐)速度更快。 –

+1

另外'diff.default'将其输入转换为矩阵并进行一些检查。 https://github.com/wch/r-source/blob/trunk/src/library/base/R/diff.R –

+0

感谢@JoshuaUlrich,我将Ubuntu更新至16.04并安装了R 3.3.2。我还调用runif函数以外的函数,以便可以衡量diff函数的实际执行时间。对于所有这些,Whit比1e4更好。我认为小尺寸的vec []更好的性能是由于检查。非常感谢你。 –

回答

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