假设我们有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 速度比逻辑矢量更快>?有任何想法吗?
这似乎是因为按逻辑向量进行子集化比按数字索引进行子集化要慢。
> 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)