Самый быстрый способ определить, имеет ли вектор хотя бы 1 NA?


каков самый быстрый способ определить, имеет ли вектор хотя бы 1 NA в R? Я использую:

sum( is.na( data ) ) > 0

но это требует изучения каждого элемента, принуждения и функцию сумм.

6 64

6 ответов:

начиная с 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

обратите внимание, как это существенно быстрее, даже когда мы изменяем последнее значение вектора; это отчасти из-за избежания промежуточный логический вектор.

Я подумал:

any(is.na(data))

должен быть немного быстрее.

мы упоминаем об этом в некоторых из наших Rcpp презентации и на самом деле есть некоторые критерии, которые показывают довольно большие выгоды из встроенного C++ с Rcpp над решением R, потому что

  • векторизованное решение R все еще вычисляет каждый элемент векторного выражения

  • если ваша цель состоит в том, чтобы просто удовлетворить any(), то вы можете прервать после первого матча - что и наш Rcpp сахара (в сущности: некоторые c++ шаблон магии, чтобы сделать c++ выражения больше похожи на R выражения, см. эта виньетка дополнительные) решение.

таким образом, получая скомпилированное специализированное решение для работы, мы действительно получаем быстрое решение. Я должен добавить, что, хотя я не сравнивал это с решениями, предлагаемыми в этом вопросе SO здесь, я достаточно уверен в производительности.

Edit и Пакет Rcpp содержит примеры в каталоге sugarPerformance. Он имеет увеличение на несколько тысяч "сахар-может-прервать-скоро" над "R-вычисляет-полное векторное выражение" для any(), но я должен добавить, что этот случай не предполагает is.na() но простое логическое выражение.

можно было бы написать цикл for, останавливающийся на 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.

можно попробовать:

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

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