为什么诊断功能这么慢? [在 R 3.2.0 或更早版本中]
Why is the diag function so slow? [in R 3.2.0 or earlier]
我正在查看 中的基准,并想将它们与 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" 基准测试中使用的向量相同。为这两个计时...
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
...看来我找到了罪魁祸首。因此,我的问题的新变体是:为什么 diag
中有看似不必要且非常耗时的 c
?
总结
从 R version 3.2.1 (World-Famous Astronaut) diag()
has received an update. The discussion moved to r-devel 开始,有人指出 c()
去除了非名称属性,这可能就是它被放在那里的原因。虽然有些人担心删除 c()
会导致类矩阵对象出现未知问题,但 Peter Dalgaard 发现,"The only case where the c()
inside diag()
has an effect is where M[i,j] != M[(i-1)*m+j]
AND c(M)
will stringize M
in column-major order, so that M[i,j] == c(M)[(i-1)*m+j]
."
Luke Tierney 测试了@Frank 对 c()
的移除,发现它对 CRAN 或 BIOC 没有任何影响,因此被实施以用 x[.. .] 在 line 27 上。这导致 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
我正在查看 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" 基准测试中使用的向量相同。为这两个计时...
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
...看来我找到了罪魁祸首。因此,我的问题的新变体是:为什么 diag
中有看似不必要且非常耗时的 c
?
总结
从 R version 3.2.1 (World-Famous Astronaut) diag()
has received an update. The discussion moved to r-devel 开始,有人指出 c()
去除了非名称属性,这可能就是它被放在那里的原因。虽然有些人担心删除 c()
会导致类矩阵对象出现未知问题,但 Peter Dalgaard 发现,"The only case where the c()
inside diag()
has an effect is where M[i,j] != M[(i-1)*m+j]
AND c(M)
will stringize M
in column-major order, so that M[i,j] == c(M)[(i-1)*m+j]
."
Luke Tierney 测试了@Frank 对 c()
的移除,发现它对 CRAN 或 BIOC 没有任何影响,因此被实施以用 x[.. .] 在 line 27 上。这导致 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