为什么诊断function如此缓慢?

我正在看这个答案的基准,并想与diag (在不同的答案中使用)进行比较。 不幸的是, diag似乎需要很长时间:

 nc <- 1e4 set.seed(1) m <- matrix(sample(letters,nc^2,replace=TRUE), ncol = nc) microbenchmark( diag = diag(m), cond = m[row(m)==col(m)], vec = m[(1:nc-1L)*nc+1:nc], mat = m[cbind(1:nc,1:nc)], times=10) 

评论 :我testing了这些identical 。 我从这个作业问题的答案之一采取“cond”。 结果与整数matrix类似,而不是letters ,而是1:26

结果

 Unit: microseconds expr min lq mean median uq max neval diag 604343.469 629819.260 710371.3320 706842.3890 793144.019 837115.504 10 cond 3862039.512 3985784.025 4175724.0390 4186317.5260 4312493.742 4617117.706 10 vec 317.088 329.017 432.9099 350.1005 629.460 651.376 10 mat 272.147 292.953 441.7045 345.9400 637.506 706.860 10 

这只是一个matrix子集操作,所以我不知道为什么有这么多的开销。 看看函数内部,我看到一些检查,然后c(m)[v] ,其中v是“vec”基准testing中使用的相同向量。 定时这两个…

 v <- (1:nc-1L)*nc+1:nc microbenchmark(diaglike=c(m)[v],vec=m[v]) # Unit: microseconds # expr min lq mean median uq max neval # diaglike 579224.436 664853.7450 720372.8105 712649.706 767281.5070 931976.707 100 # vec 334.843 339.8365 568.7808 646.799 663.5825 1445.067 100 

看来我find了我的罪魁祸首 所以,我的问题的新变化是: 为什么diag有一个看似不必要和非常耗时的c

概要

从R版本3.2.1 (世界着名宇航员) diag()已收到更新。 讨论转到了r-devel ,注意到c()剥离了非名称属性,可能是为什么它放在那里。 虽然有些人担心删除c()会导致类matrix对象上的未知问题,但是Peter Dalgaard发现:“内部diag()有效的唯一情况是M[i,j] != M[(i-1)*m+j] AND c(M)将以列 – 次序串联M ,使得M[i,j] == c(M)[(i-1)*m+j]

Luke Tierneytesting了@Frank删除了c() ,发现它对CRAN或BIOC没有任何影响,所以在第27行用x来replacec(x)。 这导致diag()相对较大的加速。 下面是一个速度testing,显示了R 3.2.1版本的diag()

 library(microbenchmark) nc <- 1e4 set.seed(1) m <- matrix(sample(letters,nc^2,replace=TRUE), ncol = nc) microbenchmark(diagOld(m),diag(m)) Unit: microseconds expr min lq mean median uq max neval diagOld(m) 451189.242 526622.2775 545116.5668 531905.5635 540008.704 682223.733 100 diag(m) 222.563 646.8675 644.7444 714.4575 740.701 1015.459 100