【问题标题】:Fastest way to detect if vector has at least 1 NA?检测向量是否至少有1个NA的最快方法?
【发布时间】:2011-09-26 23:11:55
【问题描述】:

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

sum( is.na( data ) ) > 0

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

【问题讨论】:

    标签: r na


    【解决方案1】:

    我在想:

    any(is.na(data))
    

    应该稍微快一点。

    【讨论】:

    • 虽然它仍然需要遍历每个元素。想知道是否有 first() 函数或类似的函数,一旦满足条件就会停止
    • 不确定,如果any() 在发现 FALSE 后停止,我不会感到惊讶。无论如何,any(...) 变得太慢而无法处理的那一刻可能已经过了你的 RAM 用完的那一刻。
    • 还有 all() 函数按预期工作。可能有用(不适用于这个问题,但一般来说)。
    • anyall 分别在达到 TRUEFALSE 时停止迭代;见checkValuessvn.r-project.org/R/trunk/src/main/logic.cis.na 仍然强制一切。
    • Aaron,剩余成本是首先计算的is.na(data),并且对于数据的所有元素,无论早期的元素是否实际上是NA。我们确实使用is.na() 的 Rcpp 糖版本(在 C++ 中实现以通过 Rcpp 使用)对此进行了改进。有关更多信息,请参阅我的答案。
    【解决方案2】:

    从 R 3.1.0 开始,anyNA() 是执行此操作的方法。在原子向量上,这将在第一个 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
    

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

    【讨论】:

      【解决方案3】:

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

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

      • 如果您的目标只是满足any(),那么您可以在第一场比赛后中止——这就是我们的 Rcpp 糖(本质上是:制作一些 C++ 模板魔法C++ 表达式看起来更像 R 表达式,请参阅 this vignette 了解更多信息)解决方案确实如此。

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

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

      【讨论】:

      • R 的any 计算每一个元素,而不是在第一个实例上停止,有什么原因吗?
      • R 的any 不知道里面有什么;它只是评估它的论点(全部),然后将any 应用于它,它确实在第一个FALSE 处停止,但同样,只有在评估其所有论点之后。 Dirk 的 any 的 Rcpp 糖版本(据我所知)确实知道如何逐项评估其中的内容(至少对于某些表达式,无论如何),因此它可以检查每个术语的 TRUE/FALSE,因为它是依次评估的.
      • @Dirk - 非常酷。似乎最有效的方法是使用嵌入式 c++ ...或者是作弊,因为它不是纯 R 答案 =) 感谢 Rcpp 的链接!
      【解决方案4】:

      可以编写一个在 NA 处停止的 for 循环,但 system.time 取决于 NA 的位置...(如果没有,则需要很长时间)

      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 
      

      【讨论】:

      • 对 nacount 函数进行基准测试的好主意!你是对的,时间取决于第一个 NA 的位置(如果有的话)。我重复了你的实验,只是我在长向量的末尾放置了一个 NA。结果如下:nacount(x) = 86.14,any(is.na(x)) = .4,sum(is.na(x)) > 0 = 1.64。在这种情况下,nacount(如预期的那样)是可怕的。更有趣的是 any(...) 比 sum(...)>0
      【解决方案5】:

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

      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 实现的。

      【讨论】:

      • 感谢您将这些放在一起。我认为这表明 any(...) 是一个很棒的纯 R 解决方案。
      【解决方案6】:

      你可以试试:

      d <- c(1,2,3,NA,5,3)
      
      which(is.na(d) == TRUE, arr.ind=TRUE)
      

      【讨论】:

      • 我认为 is.na(d) == TRUE 相当于只声明 is.na(d)
      猜你喜欢
      • 1970-01-01
      • 2023-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-13
      • 1970-01-01
      • 2012-07-09
      • 1970-01-01
      相关资源
      最近更新 更多