【问题标题】:filter() but keep groups without valuefilter() 但保留没有价值的组
【发布时间】:2020-05-09 02:01:03
【问题描述】:

我正在尝试压缩一个分组的 df,只提取包含某个值的行,但该值并未反映在所有组中。我想找到一种方法来提取具有该值的所有行,但也为不包含该值的组创建 NA 或 0 行。

例如:

x1 <- c('1','1','1','1','1','2','2','2','2','2','3','3','3','3','3')
x2 <- c('a','b','c','d','e','b','c','d','e','f','a','b','d','e','f')
df <- data.frame(x1,x2)

df %>% group_by(x1) %>%
  filter(x2 =="a")

返回:

  x1    x2   
  <fct> <fct>
1 1     a    
2 3     a  

但我希望它返回:

  x1    x2   
  <fct> <fct>
1 1     a    
2 2     NA
3 3     a  

显然真正的代码要复杂得多,所以我正在寻找以可重现的方式保留这些空组的最佳方法。

PS - 我想留在 dplyr 以保持函数链的顺畅

谢谢!

【问题讨论】:

    标签: r filter dplyr


    【解决方案1】:

    一个dplyr 选项可能是:

    df %>%
     group_by(x1) %>%
     slice(which.max(x2 == "a")) %>%
     mutate(x2 = replace(x2, x2 != "a", NA_complex_))
    
      x1    x2   
      <fct> <fct>
    1 1     a    
    2 2     <NA> 
    3 3     a   
    

    如果每个组有多个目标值相关:

    df %>%
     group_by(x1) %>%
     filter(x2 == "a") %>%
     bind_rows(df %>%
                group_by(x1) %>%
                filter(all(x2 != "a")) %>%
                slice(1) %>%
                mutate(x2 = replace(x2, x2 != "a", NA_complex_)))
    

    【讨论】:

      【解决方案2】:

      由于您没有仅指定 dplyr 解决方案,因此这里是 library(data.table) 的一个选项

      setDT(df)
      df[, .(x2 = x2[match('a', x2)]), x1]
      #    x1   x2
      # 1:  1    a
      # 2:  2 <NA>
      # 3:  3    a
      

      【讨论】:

        【解决方案3】:

        发生这种情况是因为 Dplyr 的编写方式。 根据 Hadley Wickham(包创建者)维护 NA 值,您应该明确声明您想要它们。正如他在 github 上的this issue 中所说,你应该filter(a == x | is.na(a))。在您的情况下,您使用以下内容:

        df %>% group_by(x1) %>%
        filter(x2 =="a" | is.na(x2)
        

        结果你会退回给你:

          x1    x2   
         <fct> <fct>
        1 1     a    
        2 2     NA
        3 3     a  
        

        在此代码中,您要求 R 所有 x2 等于“a”的行以及 x2 为 NA 的行。

        【讨论】:

        • 您好,这看起来很有希望,但没有奏效! r df %&gt;% group_by(x1) %&gt;% filter(x2 =="a" | is.na(x2)) 返回:r x1 x2 1 1 a 2 3 a 我错过了什么吗? (对不起,我不能在 cmets 中换行,所以这看起来很愚蠢,但你明白了。仍然缺少 NA 行)
        【解决方案4】:

        我们可以在filter 步骤之后使用complete 来获取缺失的组合。默认情况下,所有其他列将使用NA 填充(可以使用fill 参数自定义值)

        library(dplyr)
        library(tidyr)
        df %>% 
          filter(x2 == 'a') %>% 
          complete(x1 = unique(df$x1))
        # A tibble: 3 x 2
        #  x1    x2   
        #  <fct> <fct>
        #1 1     a    
        #2 2     <NA> 
        #3 3     a    
        

        另一个选项是match

        df %>% 
             group_by(x1) %>% 
             summarise(x2 = x2[match('a', x2)])
        

        如果有很多列,则mutate 'x2' 与match 然后slice 第一行

        df %>%
           group_by(x1) %>%
           mutate(x2 = x2[match('a', x2)]) %>%
           slice(1)
        

        【讨论】:

          【解决方案5】:

          使用aggregate() 的基本 R 解决方案怎么样?

          dfout <- aggregate(x2~x1,df,function(v) ifelse("a" %in% v,"a",NA))
          

          dfout <- aggregate(x2~x1,df,function(v) v[match("a", v)])
          

          这样

          > dfout
            x1   x2
          1  1    a
          2  2 <NA>
          3  3    a
          

          【讨论】:

            猜你喜欢
            • 2021-10-14
            • 2010-12-13
            • 1970-01-01
            • 1970-01-01
            • 2015-03-18
            • 2013-07-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多