为什么"逻辑"类型的子集比"数字"类型的子集慢?

Aru*_*run 13 r subset

假设我们有vector(或者data.frame就此而言)如下:

set.seed(1)
x <- sample(10, 1e6, TRUE)
Run Code Online (Sandbox Code Playgroud)

而一个人想获得的所有值都x在那里x > 4,说:

a1 <- x[x > 4] # (or) 
a2 <- x[which(x > 4)]

identical(a1, a2) # TRUE
Run Code Online (Sandbox Code Playgroud)

我想大多数人都会喜欢x[x > 4].但令人惊讶的是(至少对我来说),使用子集which更快!

require(microbenchmark)
microbenchmark(x[x > 4], x[which(x > 4)], times = 100)

Unit: milliseconds
            expr      min       lq   median       uq       max neval
        x[x > 4] 56.59467 57.70877 58.54111 59.94623 104.51472   100
 x[which(x > 4)] 26.62217 27.64490 28.31413 29.97908  99.68973   100
Run Code Online (Sandbox Code Playgroud)

它比我快2.1倍.

我认为,差异的一种可能性可能是由于which不考虑NA但同时>返回它们的事实.但是逻辑运算本身应该是造成这种差异的原因,而事实并非如此(显然).那是:

microbenchmark(x > 4, which(x > 4), times = 100)

Unit: milliseconds
         expr       min       lq   median       uq      max neval
        x > 4  8.182576 10.06163 12.68847 14.64203 60.83536   100
 which(x > 4) 18.579746 19.94923 21.43004 23.75860 64.20152   100
Run Code Online (Sandbox Code Playgroud)

which在子集化之前使用大约慢1.7倍.但which似乎在子集化过程中大幅度地追赶.

似乎不可能使用我常用的武器debugonce(感谢@GavinSimpson)作为which呼叫.Internal(which(x))不是==呼叫.Primitive("==").

因此,我的问题是为什么[numeric类型上产生的which 速度比逻辑矢量更快>?有任何想法吗?

koh*_*ske 3

这似乎是因为按逻辑向量进行子集化比按数字索引进行子集化要慢。

> ii <- x > 4
> ij <- which(x > 4)
> 
> head(ii)
[1] FALSE FALSE  TRUE  TRUE FALSE  TRUE
> head(ij)
[1] 3 4 6 7 8 9
>
> microbenchmark(x[ii], x[ij], times = 100)
Unit: milliseconds
  expr       min       lq    median        uq      max neval
 x[ii] 25.574977 26.15414 28.299858 31.080903 82.04686   100
 x[ij]  3.037134  3.31821  3.670096  7.516761 12.39738   100
Run Code Online (Sandbox Code Playgroud)

更新:

原因之一可能是,较小的索引数字长度可以减少子集化的(内部)循环,并导致评估速度变慢。你可以找到ik<<ijil

ii但还会有另一个区别,因为和 之间存在巨大差异il

> ii <- x > 4
> 
> ij <- which(x > 4)
> ik <- which(x > 9)
> il <- which(x > -1)
> 
> microbenchmark(x[ii], x[ij], x[ik], x[il], times = 100)
Unit: microseconds
  expr       min         lq    median        uq       max neval
 x[ii] 25645.621 25986.2720 28466.412 30693.158 79582.484   100
 x[ij]  3111.974  3281.8280  3477.627  6142.216 55076.121   100
 x[ik]   585.723   628.2125   650.184   682.888  7551.084   100
 x[il]  5266.032  5773.9015  9073.614 10583.312 15113.791   100
Run Code Online (Sandbox Code Playgroud)