【问题标题】:Count Trailing and Leading NA for each vector计算每个矢量的尾随和前导na
【发布时间】:2020-01-16 15:11:08
【问题描述】:

我有一些格式如下的向量

    v1 <- c(NA,NA,NA,10,10,10,10)
    v2 <- c(NA,NA, 3, 3, 3,NA,NA)
    v3 <- c( 5, 5, NA,NA,NA,NA,NA)

对于每个向量,我想计算有多少前导 NA 和尾随 NA。

    For v1, LeadNA = 3, TrailNA = 0
    For v2, LeadNA = 2, TrailNA = 2
    For v3, LeadNA = 0, TrailNA = 5

【问题讨论】:

    标签: r vector na


    【解决方案1】:

    1) Cumsum - 一种选择是在存在非 NA 元素的情况下使用 cumsum 创建一个逻辑向量并获取 sumbase R - 不使用任何包)

    f1 <- function(vec, trail = FALSE) {
      if(trail) {
         vec <- rev(vec)
        }
        sum(!cumsum(!is.na(vec)))
     }
    
    f1(v1)
    #[1] 3
    f1(v1, TRUE)
    #[1] 0
    
    sapply(mget(paste0("v", 1:3)), f1)
    #  v1 v2 v3 
    # 3  2  0 
    sapply(mget(paste0("v", 1:3)), f1, TRUE)  
    #  v1 v2 v3 
    #  0  2  5 
    

    2 rle - 另一个base R 选项是rle(不使用任何包)

    with(rle(is.na(v2)), lengths[values & seq_along(values) %in% c(1, length(values))])
    

    【讨论】:

      【解决方案2】:

      1) na.locf 使用 na.locf 删除前导 NA,并确定原始向量和缩减向量之间的长度差异。对尾随的 NA 执行相同的操作。如果输入向量为空或全部为 NA,则不清楚应该返回什么,因此我们为 left 和 right 返回 NA。

      library(zoo)
      
      countNA <- function(x) {
        len <- function(fromLast = FALSE) length(na.locf(x, fromLast = fromLast))
        if (all(is.na(x))) c(left = NA, right = NA)
        else length(x) - c(left = len(), right = len(TRUE))
      }
      
      countNA(v1)
      ##  left right 
      ##     3     0 
      
      countNA(v2)
      ##  left right 
      ##     2     2 
      
      countNA(v3)
      ##  left right 
      ##     0     5 
      

      也可以使用na.fill 来执行此计算。

      2) 减少 第二种方法是使用Reduce。它给出了相同的答案。没有使用任何包。

      countNA2 <- function(x) {
        f <- function(x) sum(Reduce(all, is.na(x), acc = TRUE))
        if (all(is.na(x))) c(left = NA, right = NA)
        else c(left = f(x), right = f(rev(x)))
      }
      

      【讨论】:

        【解决方案3】:

        包装which.max:

        leading.nas <- function(x) {
          if (length(x) == 0) {
           0L 
          }
          else {
            which.min(!is.na(x)) - 1
          }
        }
        

        【讨论】:

        • 也可以使用which.min
        【解决方案4】:

        一个函数返回两个数字。第一个是前导NA 的计数。第二个是尾随NA 的计数。它需要 data.table 包中的 rleid 函数。

        library(data.table)
        
        count_fun <- function(x){
          y <- rleid(x)
          z <- split(x, y)[c(1, length(unique(y)))]
          ans <- sapply(z, function(x) sum(is.na(x)))
          return(unname(ans))
        }
        
        count_fun(v1)
        # [1] 3 0
        
        count_fun(v2)
        # [1] 2 2
        
        count_fun(v3)
        # [1] 0 5
        

        【讨论】:

          【解决方案5】:

          这与@Bulat 的解决方案类似

          count_nas <- function(x) {
            nas <- is.na(x)
          
            if (sum(nas) == length(x)) {
              warning('all elements were NA')
              return(c(start_na = NA_integer_, end_na = NA_integer_))
            }
          
            c(start_na = which.min(nas) - 1,
              end_na = which.min(rev(nas)) - 1)
          }
          
          count_nas(v1)
          #start_na   end_na 
          #       3        0 
          
          sapply(list(v1,v2,v3), count_nas)
          #         [,1] [,2] [,3]
          #start_na    3    2    0
          #end_na      0    2    5
          

          就性能而言,这是@akrun 方法中最快的方法。

          v_test3 <- sample(10000)
          v_test3[c(1:3, 9998:10000)] <- NA_integer_
          
          Unit: microseconds
                       expr     min       lq      mean   median       uq     max neval
               akrun_cumsum   175.7   182.15   193.580   186.55   200.80   354.7   100
                  akrun_rle   168.6   199.25   210.635   209.25   221.00   289.3   100
              g_grothen_zoo  1848.5  1904.45  2008.994  1941.40  2001.35  4799.6   100
           g_grothen_reduce 12467.3 12888.10 14174.157 13445.15 15054.35 28241.6   100
                  www_rleid  5357.2  5439.40  5741.471  5517.15  5947.15  8470.4   100
             bulat_and_cole    63.5    66.45    73.681    71.25    75.75    96.9   100
          

          重现性代码:

          library(microbenchmark)
          library(zoo)
          library(data.table)
          
          v_test3 <- sample(10000)
          v_test3[c(1:3, 9998:10000)] <- NA_integer_
          
          count_nas <- function(x) {
            nas <- is.na(x)
          
            if (sum(nas) == length(x)) {
              warning('all elements were NA')
              return(c(start_na = NA_integer_, end_na = NA_integer_))
            }
          
            c(start_na = which.min(nas) - 1,
              end_na = which.min(rev(nas)) - 1)
          }
          
          countNA <- function(x) {
            len <- function(fromLast = FALSE) length(na.locf(x, fromLast = fromLast))
            if (all(is.na(x))) c(left = NA, right = NA)
            else length(x) - c(left = len(), right = len(TRUE))
          }
          
          f1 <- function(vec, trail = FALSE) {
            if(trail) {
              vec <- rev(vec)
            }
            sum(!cumsum(!is.na(vec)))
          }
          
          count_fun <- function(x){
            y <- rleid(x)
            z <- split(x, y)[c(1, length(unique(y)))]
            ans <- sapply(z, function(x) sum(is.na(x)))
            return(unname(ans))
          }
          
          countNA2 <- function(x) {
            f <- function(x) sum(Reduce(all, is.na(x), acc = TRUE))
            if (all(is.na(x))) c(left = NA, right = NA)
            else c(left = f(x), right = f(rev(x)))
          }
          
          microbenchmark(
            akrun_cumsum = {
              f1(v_test3, TRUE)
              f1(v_test3, FALSE)
            }
            , 
            akrun_rle = {
              with(rle(is.na(v_test3)), lengths[values & seq_along(values) %in% c(1, length(values))])
            }
            ,
            g_grothen_zoo = {
              countNA(v_test3)
            }
            ,
            g_grothen_reduce = {
              countNA2(v_test3)
            }
            ,
            www_rleid = {
              count_fun(v_test3)
            }
            ,
            bulat_and_cole = {
              count_nas(v_test3)
            }
          )
          

          【讨论】:

            猜你喜欢
            • 2017-08-03
            • 1970-01-01
            • 2021-10-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多