【问题标题】:R dplyr - Filter unique row in each group with dplyrR dplyr - 使用 dplyr 过滤每个组中的唯一行
【发布时间】:2021-03-07 01:23:24
【问题描述】:

我的数据是这样的

id     col2     col3    flag    val
1       a         q 
1       a         w        1
1       b         r    
2       c         q        1      5
2       c         q
2       c         q        1      6    

我只想要这些行

id    col2      col3     flag    val
1       a         q 
1       a         w        1  
1       b         r    
2       c         q        1      5

基本上前 3 列确定group。对于每个group,如果只有1 个观察/行,则无论flag 是什么值,都保留该行。如果每个 group 有超过 1 个观察值/行,则保持 group 中具有 flag 等于 1 的第一行。我想知道在 R 中是否有任何方法可以使用 dplyr 执行此操作

【问题讨论】:

  • 当有两行,都没有标志时会发生什么?
  • 顺便说一句,这些是字符串("""1")还是数字(NA1)?您的数据不干净(或清晰),最好包含dput(x) 的输出。谢谢。

标签: r dplyr


【解决方案1】:

dplyr::distinct 正好帮助解决这个问题,.keep_all 标志保留了其他列,就像您的输出一样。

my_data %>%
  distinct(id, col2, col3, .keep_all = TRUE)

结果

# A tibble: 4 x 5
     id col2  col3   flag   val
  <int> <chr> <chr> <int> <int>
1     1 a     q        NA    NA
2     1 a     w         1    NA
3     1 b     r        NA    NA
4     2 c     q         1     5

数据

my_data <- tibble::tribble(
  ~id, ~col2, ~col3, ~flag, ~val,
   1L,   "a",   "q",    NA,   NA,
   1L,   "a",   "w",    1L,   NA,
   1L,   "b",   "r",    NA,   NA,
   2L,   "c",   "q",    1L,   5L,
   2L,   "c",   "q",    NA,   NA,
   2L,   "c",   "q",    1L,   6L
  )

【讨论】:

    【解决方案2】:
    dat %>%
      mutate(rn = row_number()) %>%
      arrange(flag) %>%
      group_by(id, col2, col3) %>%
      slice(1) %>%
      ungroup() %>%
      arrange(rn) %>%
      select(-rn)
    # # A tibble: 4 x 5
    #      id col2  col3   flag   val
    #   <int> <chr> <chr> <int> <int>
    # 1     1 a     q        NA    NA
    # 2     1 a     w         1    NA
    # 3     1 b     r        NA    NA
    # 4     2 c     q         1     5
    

    如果您的数据是带有空字符串的字符串(问题中并不清楚),那么

    dat %>%
      # this is just to transform my number-based 'flag'/'val' to strings, you don't need this
      mutate(across(c(flag, val), ~ if_else(is.na(.), "", as.character(.)))) %>%
      # pick up here
      mutate(rn = row_number()) %>%
      arrange(!nzchar(flag)) %>%       # this is the only difference from above
      group_by(id, col2, col3) %>%
      slice(1) %>%
      ungroup() %>%
      arrange(rn) %>%
      select(-rn)
    # # A tibble: 4 x 5
    #      id col2  col3  flag  val  
    #   <int> <chr> <chr> <chr> <chr>
    # 1     1 a     q     ""    ""   
    # 2     1 a     w     "1"   ""   
    # 3     1 b     r     ""    ""   
    # 4     2 c     q     "1"   "5"  
    

    rn 的使用只是为了确保在过滤过程中保留顺序。如果顺序不是问题(也许是通过其他方式推断出来的),那么您可以删除 mutate 和尾随的 arrange(rn) %&gt;% select(-rn)


    数据

    dat <- structure(list(id = c(1L, 1L, 1L, 2L, 2L, 2L), col2 = c("a", "a", "b", "c", "c", "c"), col3 = c("q", "w", "r", "q", "q", "q"), flag = c(NA, 1L, NA, 1L, NA, 1L), val = c(NA, NA, NA, 5L, NA, 6L)), class = "data.frame", row.names = c(NA, -6L))
    

    【讨论】:

      【解决方案3】:

      您可以在以下情况下选择一行:

      1. 组中只有一行 OR
      2. flag = 1 在组中的第一行。
      library(dplyr)
      
      df %>%
        group_by(id, col2, col3) %>%
        filter(n() == 1 | row_number() == match(1, flag)) %>%
        ungroup()
      
      #     id col2  col3   flag   val
      #  <int> <chr> <chr> <int> <int>
      #1     1 a     q        NA    NA
      #2     1 a     w         1    NA
      #3     1 b     r        NA    NA
      #4     2 c     q         1     5
      

      数据

      df <- structure(list(id = c(1L, 1L, 1L, 2L, 2L, 2L), col2 = c("a", 
      "a", "b", "c", "c", "c"), col3 = c("q", "w", "r", "q", "q", "q"
      ), flag = c(NA, 1L, NA, 1L, NA, 1L), val = c(NA, NA, NA, 5L, 
      NA, 6L)), class = "data.frame", row.names = c(NA, -6L))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-09
        • 1970-01-01
        • 2017-10-29
        • 1970-01-01
        • 1970-01-01
        • 2015-02-01
        • 2018-06-23
        相关资源
        最近更新 更多