我正在查看this answer中的基准测试,并想将它们与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)
注释:我使用
identical
测试了它们。我从this homework question的答案之一中获得了“cond”。结果类似于整数矩阵1:26
而不是letters
。结果:
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
这只是一个矩阵子集运算,所以我不知道为什么会有这么多的开销。在函数内部,我看到了一些检查,然后是
c(m)[v]
,其中v
与“vec”基准测试中使用的 vector 相同。定时这两个...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
...似乎我找到了罪魁祸首。因此,我的问题的新变化是:为何
c
中似乎有不必要且耗时的diag
? 最佳答案
摘要
从R version 3.2.1(世界著名宇航员)开始,diag()
已收到更新。讨论移至r-devel,其中注意到c()
剥离了非名称属性,并且可能就是为什么将其放置在此处。尽管有些人担心删除c()
会在类似矩阵的对象上引起未知问题,但Peter Dalgaard发现:“c()
中的diag()
起作用的唯一情况是M[i,j] != M[(i-1)*m+j]
和c(M)
会按列的主要顺序将M
字符串化,因此M[i,j] == c(M)[(i-1)*m+j]
。”
卢克·蒂尔尼(Luke Tierney)测试了@Frank对c()
的删除,发现它对CRAN或BIOC没有任何影响,因此实现了用line 27上的x [...]替换c(x)[...]。这导致diag()
中的相对较大的加速。下面是一个速度测试,显示了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
关于r - 为什么diag功能这么慢? [在R 3.2.0或更早版本中],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30035939/