72

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

sum( is.na( data ) ) > 0

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

4

6 回答 6

75

我在想:

any(is.na(data))

应该稍微快一点。

于 2011-07-01T18:38:41.947 回答
72

从 R 3.1.0anyNA()开始就是这样做的方法。在原子向量上,这将在第一个 NA 之后停止,而不是像any(is.na()). 此外,这避免了创建一个中间逻辑向量,is.na该向量被立即丢弃。借用 Joran 的例子:

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

请注意,即使我们修改了向量的最后一个值,它也明显更快;这部分是因为避免了中间逻辑向量。

于 2016-03-01T01:45:57.003 回答
17

我们在一些Rcpp演示文稿中提到了这一点,实际上有一些基准测试表明,使用 Rcpp 的嵌入式 C++ 比 R 解决方案获得了相当大的收益,因为

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

  • 如果您的目标只是满足any(),那么您可以在第一次匹配后中止——这就是我们的Rcpp 糖(本质上:一些 C++ 模板魔术使 C++ 表达式看起来更像 R 表达式,请参阅此小插图了解更多)解决方案所做的.

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

编辑并且 Rcpp 包包含目录中的示例sugarPerformance。与 'R-computes-full-vector-expression' 相比,它增加了数千个 'sugar-can-abort-soon' any(),但我应该补充一点,这种情况只涉及is.na()一个简单的布尔表达式。

于 2011-07-01T20:48:52.597 回答
8

可以编写一个在 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 
于 2011-07-01T19:34:19.713 回答
6

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

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.

于 2011-07-01T19:55:18.747 回答
3

你可以试试:

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

which(is.na(d) == TRUE, arr.ind=TRUE)
于 2011-07-01T18:37:30.647 回答