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

SFu*_*n28 68 r na

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

sum( is.na( data ) ) > 0
Run Code Online (Sandbox Code Playgroud)

但这需要检查每个元素,强制和和函数.

Sac*_*amp 68

我在想:

any(is.na(data))
Run Code Online (Sandbox Code Playgroud)

应该稍快一些.

  • `any`和`all`分别在达到'TRUE'或'FALSE'时停止迭代; 请参阅http://svn.r-project.org/R/trunk/src/main/logic.c中的`checkValues`; 但是`is.na`仍然强迫一切. (7认同)
  • 这是我第一次听到"任何"功能.谢谢! (3认同)
  • Aaron,剩下的成本是首先计算的`is.na(data)`,以及*所有*数据元素,不论早期的数据是否实际上是NA.我们使用`is.na()`的Rcpp糖版本对其进行了改进(它在C++中实现,可以通过Rcpp使用).请参阅我的回答. (2认同)

Bro*_*ieG 59

从R 3.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
Run Code Online (Sandbox Code Playgroud)

注意即使我们修改向量的最后一个值,它也会快得多; 这部分是因为避免了中间逻辑矢量.


Dir*_*tel 16

我们在一些Rcpp演示文稿中提到了这一点,并且实际上有一些基准测试显示嵌入式C++与Rcpp在R解决方案上的相当大的收益,因为

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

  • 如果你的目标只是满足any(),那么你可以在第一场比赛后中止 - 这就是我们的Rcpp糖(实质上:一些C++模板魔术使C++表达式看起来更像R表达式,请参阅此插图以获得更多)解决方案.

因此,通过编译专用解决方案,我们确实可以获得快速解决方案.我应该补充一点,虽然我没有将此与此SO问题中提供的解决方案进行比较,但我对性能有了相当的信心.

编辑并且Rcpp包中包含目录中的示例sugarPerformance.对于'R-computes-full-vector-expression'而言any(),它已经增加了几千个"糖罐中止" ,但是我应该补充一点,这个案例不涉及is.na()一个简单的布尔表达式.

  • R'`any`不知道里面是什么; 它只是评估它的参数是什么(全部)然后对它应用`any`,它在第一个`FALSE'停止,但是再次,只有在评估了它的所有参数之后.德克的Rcpp糖版"任何"(据我所知)确实知道如何按期限评估其中的内容(至少对于某些表达式,无论如何),因此它可以检查每个术语为TRUE/FALSE,因为它依次被评估. (3认同)

EDi*_*EDi 8

可以写一个for循环停止在NA,但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 
Run Code Online (Sandbox Code Playgroud)


jor*_*ran 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
Run Code Online (Sandbox Code Playgroud)

这并不奇怪,match并且%in%类似,因为%in%使用match.