我不知道有哪个本机函数会在遇到非NA值时停止,但我们可以使用RCPP编写一个简单的函数:
Rcpp::cppFunction("bool any_NonNA(NumericVector v) {
for(size_t i = 0; i < v.length(); i++) {
if(!(Rcpp::traits::is_na<REALSXP>(v[i]))) return true;
}
return false;
}")
这将创建一个名为any_NonNA
的R函数,它执行我们所需的操作.让我们在一个有any_NonNA
,000 nA值的大向量上测试它:
test <- rep(NA, 1e5)
any_NonNA(test)
#> [1] FALSE
any(!is.na(test))
#> [1] FALSE
现在,让我们将第一个元素设为非NA:
test[1] <- 1
any_NonNA(test)
#> [1] TRUE
any(!is.na(test))
#> [1] TRUE
所以它给出了正确的结果,但它更快吗?
当然,在本例中,因为它应该在第一个元素之后停止,所以它应该快得多.如果我们逐一比较,情况确实是这样:
microbenchmark::microbenchmark(
baseR = any(!is.na(test)),
Rcpp = any_NonNA(test)
)
#> Unit: microseconds
#> expr min lq mean median uq max neval cld
#> baseR 275.1 525.0 670.948 533.05 568.7 13029.9 100 b
#> Rcpp 1.6 2.1 4.319 3.30 5.1 33.7 100 a
正如预期的那样,这要快几个数量级.如果我们的第一个非NA值位于向量的中间,情况会怎样呢?
test[1] <- NA
test[50000] <- 1
microbenchmark::microbenchmark(
baseR = any(!is.na(test)),
Rcpp = any_NonNA(test)
)
#> Unit: microseconds
#> expr min lq mean median uq max neval cld
#> baseR 332.1 579.35 810.948 597.95 624.40 12010.4 100 b
#> Rcpp 299.4 300.70 311.516 305.10 309.25 370.1 100 a
速度更快,但不会太快.
如果我们把非NA值放在最后,我们应该看不到太大的区别:
test[50000] <- NA
test[100000] <- 1
microbenchmark::microbenchmark(
baseR = any(!is.na(test)),
Rcpp = any_NonNA(test)
)
#> Unit: microseconds
#> expr min lq mean median uq max neval cld
#> baseR 395.6 631.65 827.173 642.6 663.8 11357.0 100 a
#> Rcpp 596.3 602.25 608.011 605.8 612.6 632.6 100 a
因此,这看起来确实比基本R解更快(至少对大矢量来说是这样).