我有正数和负数的矢量
vec<-c(seq(-100,-1), rep(0,20), seq(1,100))
所述载体是比例大,并且呈现出随机的一组值。 我不得不反复找负数的向量的数量......我发现这是非常低效的。
因为我只需要找到负数的数量,以及矢量进行排序,我只需要知道第一个0或正数的指数(有可能是在实际的随机向量没有0)。
目前我使用这个代码,以查找长度
length(which(vec<0))
但是这迫使R键完成整个载体,但由于它的排序,也没有必要。
我可以用
match(0, vec)
但我的矢量并不总是有0
所以我的问题是,是否有某种匹配()函数的适用条件,而不是寻找一个特定的值吗? 或者是有经营我这()的代码更有效的方法?
谢谢
提供了到目前为止所有的解决方案表示可以创建一个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
也许有,我已经错了一些棘手的边界情况! 移动到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-帮助列表。 它是缓慢的,但安全检查vec
实际上是分类和处理NA值。 如果想住上边缘(可以说是不差,实施F3或F4),然后
f5.i <- function(v)
.Internal(findInterval(v, 0 - .Machine$double.neg.eps, FALSE, FALSE))
几乎是一样快的C实现,但可能更强大和矢量(即查找值向量在第二个参数,便于范围样计算)。
使用sum()
和逻辑比较:
sum( vec < 0 )
[1] 100
这将是相当快,当你总结的逻辑, TRUE
为1, FALSE
为0,因此总的将是负值的数量。
嗯哦,我觉得一个基准比较的需要... :-)向量的长度为2E5
library(microbenchmark)
vec<-c(seq(-100,-1,length.out=1e5), rep(0,20), seq(1,100,length.out=1e5))
microbenchmark( (which.min(vec < 0) - 1L) , (sum( vec < 0 )) )
Unit: milliseconds
expr min lq median uq max neval
(which.min(vec < 0) - 1L) 1.883847 2.130746 2.554725 3.141787 75.943911 100
(sum(vec < 0)) 1.398100 1.500639 1.508688 1.745088 2.662164 100