检测载体是否至少有1个 NA 的最快方法?

检测一个矢量在 R 中是否至少有1个 NA的最快方法是什么?我一直在用:

sum( is.na( data ) ) > 0

但是这需要检查每个元素、强制和和函数。

89542 次浏览

你可以试试:

d <- c(1,2,3,NA,5,3)


which(is.na(d) == TRUE, arr.ind=TRUE)

我在想:

any(is.na(data))

应该稍微快一点。

我们可以写一个在 NA 处停止的 for 循环,但是 system. time 取决于 NA 在... 的位置(如果没有,就需要 looooong)

set.seed(1234)
x <- sample(c(1:5, NA), 100000000, replace = TRUE)


nacount <- function(x){
for(i in 1:length(x)){
if(is.na(x[i])) {
print(TRUE)
break}
}}


system.time(
nacount(x)
)
[1] TRUE
User      System verstrichen
0.14        0.04        0.18


system.time(
any(is.na(x))
)
User      System verstrichen
0.28        0.08        0.37


system.time(
sum(is.na(x)) > 0
)
User      System verstrichen
0.45        0.07        0.53

下面是我的(慢速)机器上目前为止讨论的各种方法的一些实际时间:

x <- runif(1e7)
x[1e4] <- NA


system.time(sum(is.na(x)) > 0)
> system.time(sum(is.na(x)) > 0)
user  system elapsed
0.065   0.001   0.065


system.time(any(is.na(x)))
> system.time(any(is.na(x)))
user  system elapsed
0.035   0.000   0.034


system.time(match(NA,x))
> system.time(match(NA,x))
user  system elapsed
1.824   0.112   1.918


system.time(NA %in% x)
> system.time(NA %in% x)
user  system elapsed
1.828   0.115   1.925


system.time(which(is.na(x) == TRUE))
> system.time(which(is.na(x) == TRUE))
user  system elapsed
0.099   0.029   0.127

match%in%相似并不奇怪,因为 %in%是使用 match实现的。

我们在一些 Rcpp演示文稿中提到了这一点,并且实际上有一些基准测试,它们显示了在 R 解决方案上使用 Rcpp 从嵌入式 C + + 获得的漂亮的 巨大的收益,因为

  • 向量化 R 解仍然计算向量表达式的 每一个元素

  • 如果你的目标只是满足 any(),那么你可以在第一次匹配之后放弃——这就是我们的 Rcpp Sugar(本质上: 一些 C + + 模板魔术使 C + + 表达式看起来更像 R 表达式,参见 这个小插曲了解更多)解决方案所做的。

因此,通过得到一个汇编的专门解决方案的工作,我们确实得到了一个快速的解决方案。我应该补充一点,虽然我没有将这个问题与这个 SO 问题中提供的解决方案进行比较,但是我对性能相当有信心。

编辑 并且 Rcpp 包包含目录 sugarPerformance中的示例。它比 any()的“ R- 计算-全载体表达式”增加了几千个“ Sugar-can-abort-soon”,但我应该补充的是,这种情况不涉及 is.na(),而是一个简单的布尔表达式。

从 R3.1.0开始,anyNA()就是解决这个问题的方法。在原子向量上,这将在第一个 NA 之后停止,而不是像 any(is.na())那样遍历整个向量。此外,这样可以避免使用 is.na创建立即丢弃的中间逻辑向量。借用乔兰的例子:

x <- y <- runif(1e7)
x[1e4] <- NA
y[1e7] <- NA
microbenchmark::microbenchmark(any(is.na(x)), anyNA(x), any(is.na(y)), anyNA(y), times=10)
# Unit: microseconds
#           expr        min         lq        mean      median         uq
#  any(is.na(x))  13444.674  13509.454  21191.9025  13639.3065  13917.592
#       anyNA(x)      6.840     13.187     13.5283     14.1705     14.774
#  any(is.na(y)) 165030.942 168258.159 178954.6499 169966.1440 197591.168
#       anyNA(y)   7193.784   7285.107   7694.1785   7497.9265   7865.064

注意,即使我们修改了向量的最后一个值,它的速度也大大提高了; 这在一定程度上是因为避免了中间逻辑向量。