到目前爲止提供的解決方案都意味着創建一個logical(length(vec))
並對此進行全面或部分掃描。正如你注意到的那樣,矢量是排序的。我們可以通過二進制搜索來利用這一點。我開始認爲我會超級聰明,並且以更快的速度在C中實現它,但是在調試算法的索引(這是棘手的部分!)時遇到了麻煩。所以我寫了它在R:
f3 <- function(x) {
imin <- 1L
imax <- length(x)
while (imax >= imin) {
imid <- as.integer(imin + (imax - imin)/2)
if (x[imid] >= 0)
imax <- imid - 1L
else
imin <- imid + 1L
}
imax
}
爲了與其他建議
f0 <- function(v) length(which(v < 0))
f1 <- function(v) sum(v < 0)
f2 <- function(v) which.min(v < 0) - 1L
和樂趣
library(compiler)
f3.c <- cmpfun(f3)
通往
> vec <- c(seq(-100,-1,length.out=1e6), rep(0,20), seq(1,100,length.out=1e6))
> identical(f0(vec), f1(vec))
[1] TRUE
> identical(f0(vec), f2(vec))
[1] TRUE
> identical(f0(vec), f3(vec))
[1] TRUE
> identical(f0(vec), f3.c(vec))
[1] TRUE
> microbenchmark(f0(vec), f1(vec), f2(vec), f3(vec), f3.c(vec))
Unit: microseconds
expr min lq median uq max neval
f0(vec) 15274.275 15347.870 15406.1430 15605.8470 19890.903 100
f1(vec) 15513.807 15575.229 15651.2970 17064.8830 18326.293 100
f2(vec) 21473.814 21558.989 21679.3210 22733.1710 27435.889 100
f3(vec) 51.715 56.050 75.4495 78.5295 100.730 100
f3.c(vec) 11.612 17.147 28.5570 31.3160 49.781 100
可能有一些比較棘手的邊緣情況下,我有wr翁!移動到C,我沒
library(inline)
f4 <- cfunction(c(x = "numeric"), "
int imin = 0, imax = Rf_length(x) - 1, imid;
while (imax >= imin) {
imid = imin + (imax - imin)/2;
if (REAL(x)[imid] >= 0)
imax = imid - 1;
else
imin = imid + 1;
}
return ScalarInteger(imax + 1);
")
與
> identical(f3(vec), f4(vec))
[1] TRUE
> microbenchmark(f3(vec), f3.c(vec), f4(vec))
Unit: nanoseconds
expr min lq median uq max neval
f3(vec) 52096 53192.0 54918.5 55539.0 69491 100
f3.c(vec) 10924 12233.5 12869.0 13410.0 20038 100
f4(vec) 553 796.0 893.5 1004.5 2908 100
findInterval
上前當有人問R-help名單上類似的問題。這是緩慢但安全的,檢查vec
實際上是排序並處理NA值。如果想住上邊緣(可以說是不差,實施F3或F4),然後
f5.i <- function(v)
.Internal(findInterval(v, 0 - .Machine$double.neg.eps, FALSE, FALSE))
幾乎是一樣快的C實現,但可能更強大和矢量(即查找值的向量在第二個參數中,用於簡單的範圍計算)。
+1哇。我會從中學到很多東西。非常感謝您發佈這樣一個深思熟慮的答案 – 2013-04-25 20:59:29
當我的f4函數獲取時出現錯誤https://gist.github.com/anonymous/5785498 – Juancentro 2013-06-14 21:35:11
@Juancentro代碼的C版本要求您有一個C編譯器安裝。對於Windows,[請按照這些說明](http://cran.r-project.org/bin/windows/Rtools/)。 – 2013-06-14 21:57:35