代码之家  ›  专栏  ›  技术社区  ›  dan

向data.frame中添加一个布尔列,指示特定列是否都是NAS

  •  2
  • dan  · 技术社区  · 5 年前

    我有一个 data.frame ,它有 NA 在多个列中:

    df <- data.frame(a0 = 1:3, a1 = c("A","B",NA), a2 = c("a",NA,NA), 
                     a3 = rep(NA,3), stringsAsFactors = FALSE)
    

    我想添加一个新列, all.na ,指示列是否: c("a1","a2","a3") all(is.na) ,每行。

    可以使用 sapply :

    df$all.na <- sapply(1:nrow(df), function(x) all(is.na(df[x,c("a1","a2","a3")])))
    

    但我在找更快的东西。

    我想用 dplyr::mutate 可能是一个很好的解决方案,但是:

    > df %>% dplyr::mutate(all(is.na(c(a1,a2,a3))))
      a0   a1   a2 a3 all(is.na(c(a1, a2, a3)))
    1  1    A    a NA                     FALSE
    2  2    B <NA> NA                     FALSE
    3  3 <NA> <NA> NA                     FALSE
    

    不会给我期望的结果。

    知道怎么弄吗 DPLYR::突变 给予:

    df$all.na <- c(FALSE, FALSE, TRUE)
    

    关于这个?

    2 回复  |  直到 5 年前
        1
  •  1
  •   Ronak Shah    5 年前

    我们可以使用 rowwise 具有 do

    library(dplyr)
    
    cols <- c("a1","a2","a3")
    
    df %>%
      rowwise() %>%
      do( (.) %>% as.data.frame %>% 
      mutate(all.na = all(is.na(.[cols]))))
    
    #     a0 a1    a2    a3    all.na
    #  <int> <chr> <chr> <lgl> <lgl> 
    #1     1 A     a     NA    FALSE 
    #2     2 B     NA    NA    FALSE 
    #3     3 NA    NA    NA    TRUE  
    

    或者更一般的方法 tidyverse gather spread

    library(tidyverse)
    
    df %>%
      gather(key, value, -a0) %>%
      group_by(a0) %>%
      mutate(all.na = all(is.na(value))) %>%
      spread(key, value)
    

    然而,在R基中,有一种更好的方法 is.na rowSums

    df$all.na <- rowSums(is.na(df[cols])) == length(cols)
    
    df
    #  a0   a1   a2 a3 all.na
    #1  1    A    a NA  FALSE
    #2  2    B <NA> NA  FALSE
    #3  3 <NA> <NA> NA   TRUE
    

    这也可以通过使用 apply 按行排列(行) MARGIN = 1 )但这对任何速度改进都没有帮助。

    df$all.na <- apply(df[cols], 1, function(x) all(is.na(x)))
    
        2
  •  1
  •   akrun    5 年前

    这里有一个选择 tidyverse 利用 pmap

    library(tidyverse)
    df %>%
         mutate(all.na = pmap_lgl(.[cols], ~ all(is.na(c(...))))) 
    #   a0   a1   a2 a3 all.na
    #1  1    A    a NA  FALSE
    #2  2    B <NA> NA  FALSE
    #3  3 <NA> <NA> NA   TRUE
    

    或者另一种选择是转换为逻辑向量 map reduce 它回到一个单一的逻辑 vector

    df %>% 
        mutate(all.na = map(.[cols], is.na) %>%
             reduce(`&`))
    

    base R ,这可以通过使用 Reduce lapply

    df$all.na <- Reduce(`&`, lapply(df[cols], is.na))
    

    数据

    cols <- c("a1","a2","a3")