【问题标题】:Unable to subset (filter) a data frame due to NA's由于 NA 无法对数据帧进行子集化(过滤)
【发布时间】:2016-12-21 06:03:27
【问题描述】:

为什么在 dplyr 的 filter 下方的代码中没有返回与基本 R 子集相同的 data.frame?

事实上,它们都没有按预期工作。我想同时删除b==1 AND c==1 的观察/行。也就是说,我只想删除第三行。

require(dplyr)
df <- data.frame(a=c(0,0,0,0,1,1,1),
  b=c(0,0,1,1,0,0,1),
  c=c(1,NA,1,NA,1,NA,NA))

filter(df, !(b==1 & c==1))

df[!(df$b==1 & df$c==1),]

【问题讨论】:

    标签: r data.table dplyr subset


    【解决方案1】:

    或者使用complete.cases将结果逻辑向量中的NA转换为FALSE,这样就可以在取反后挑出对应的行,这利用了NA &amp; F = F

    filter(df, !(b == 1 & c == 1 & complete.cases(df[c('b', 'c')])))
    
    #   a b  c
    # 1 0 0  1
    # 2 0 0 NA
    # 3 0 1 NA
    # 4 1 0  1
    # 5 1 0 NA
    # 6 1 1 NA
    

    这里涉及到NA的更多逻辑操作,乍一看有点混乱,但它们遵循逻辑:

    NA & F
    # [1] FALSE
    NA | T
    # [1] TRUE
    NA & T
    # [1] NA
    NA | F
    # [1] NA
    

    【讨论】:

      【解决方案2】:

      这是我能想到的最简单的选择:

      filter(df, !((b==1 & c==1) %in% TRUE))
      #  a b  c
      #1 0 0  1
      #2 0 0 NA
      #3 0 1 NA
      #4 1 0  1
      #5 1 0 NA
      #6 1 1 NA
      
      # or equivalently in data.table
      dt[!((b==1 & c==1) %in% TRUE)]
      

      另一个可能更详细/清晰的选项是使用!(b==1 &amp; c==1) | is.na(b+c) 作为比较。

      【讨论】:

      • 不错。如果isTRUE 被矢量化,这将是这个逻辑的一个很好的表达。我想有人可以强制解决问题df %&gt;% filter(!Vectorize(isTRUE)(b == 1 &amp; c == 1)),但我不确定这是否更清楚。
      【解决方案3】:

      使用data.table

      library(data.table)
      setDT(df)[df[,!(b==1 & c== 1& complete.cases(.SD[, c('b', 'c'), with = FALSE]))]]
      #   a b  c
      #1: 0 0  1
      #2: 0 0 NA
      #3: 0 1 NA
      #4: 1 0  1
      #5: 1 0 NA
      #6: 1 1 NA
      

      【讨论】:

        【解决方案4】:

        是的,NA 值会导致问题。这里有 4 种解决方法:

        方法一:两步排除

        n <- (df$b+df$c==2)
        df[n %in% c(NA, "FALSE"),]
        
          a b  c
        1 0 0  1
        2 0 0 NA
        4 0 1 NA
        5 1 0  1
        6 1 0 NA
        7 1 1 NA
        

        方法二:条件和

        df[!(complete.cases(df$b,df$c) & df$b+df$c == 2),]
        
          a b  c
        1 0 0  1
        2 0 0 NA
        4 0 1 NA
        5 1 0  1
        6 1 0 NA
        7 1 1 NA
        

        方法三:循环/函数

        filterwithNA <- function(df,n){
          for(i in 1:nrow(df)){
            if(!is.na(df$b[i]) & !(is.na(df$c[i]))){
              if(df$b[i] == n & df$c[i] == n){
                df <- df[-i,]
              }
            }
          }
          return(df)
        }
        
        filterwithNA(df, n=1)
        
          a b  c
        1 0 0  1
        2 0 0 NA
        4 0 1 NA
        5 1 0  1
        6 1 0 NA
        7 1 1 NA
        

        方法四:临时数字替换

        df[is.na(df)] <- 999
        
        df[!(df$b==1 & df$c==1),]
        df[df==999] <- NA
        df
        
          a b  c
        1 0 0  1
        2 0 0 NA
        4 0 1 NA
        5 1 0  1
        6 1 0 NA
        7 1 1 NA
        

        【讨论】:

        • 这是一个解决方案,@Hack-R。我认为这不是最好的,但它有效。在我看来,R(和 dplyr)应该更好地处理这些类型的 NA,毕竟它们是生活的一部分。
        • @RodrigoRemedio 是的,NA 一直在造成问题。相信我,我明白。
        • @RodrigoRemedio 我又添加了 2 个解决方案
        • @thelatemail 不用担心
        猜你喜欢
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        • 2017-11-09
        • 1970-01-01
        • 2019-06-12
        • 2021-06-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多