【问题标题】:Remove duplicate entries given certain criteria using the tidyverse使用 tidyverse 删除给定特定条件的重复条目
【发布时间】:2019-08-28 00:06:27
【问题描述】:

考虑以下示例数据:

library(dplyr)
d <- tibble("ID" = rep(c(1111, 2222, 3333, 4444), each = 4),
            "DAY" = c(1, 2, 3, 4, 1, 2, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4),
            "FINISHED" = c(1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0))

我想从完成给定日期的调查 (DAY) 两次的参与者 (ID) 中删除一个条目。具体来说,我想删除他们未完成整个调查 (FINISHED == 0) 的那一行(或多行,如果在一天内完成 3 次以上)。

这可能与group_by 有关吗?欢迎任何tidyverse 解决方案。

预期输出(删除第 7 行):

# A tibble: 16 x 3
      ID   DAY FINISHED
   <dbl> <dbl>    <dbl>
 1  1111     1        1
 2  1111     2        1
 3  1111     3        1
 4  1111     4        1
 5  2222     1        1
 6  2222     2        1
 8  2222     3        1
 9  3333     1        1
10  3333     2        1
11  3333     3        1
12  3333     4        1
13  4444     1        1
14  4444     2        1
15  4444     3        1
16  4444     4        0

编辑:

如果参与者在某一天完成了 2 次以上的调查并完成了两次 (FINISH == 1),我想删除最早的完成时间(即,保持最接近今天的日期)。这是一个扩展的示例数据集:

library(dplyr)
library(lubridate)
d <- tibble("ID" = rep(c(1111, 2222, 3333, 4444), each = 4),
            "DAY" = c(1, 2, 3, 3, 1, 2, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4),
            "FINISHED" = c(1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0),
            "DATE" = as_date(c("2019-08-01", "2019-08-02", "2019-08-03", "2019-08-04",
                       "2019-08-01", "2019-08-02", "2019-08-02", "2019-08-03",
                       "2019-08-01", "2019-08-02", "2019-08-03", "2019-08-04",
                       "2019-08-01", "2019-08-02", "2019-08-03", "2019-08-04")))

以及预期的输出(删除第 3、7 行):

# A tibble: 16 x 4
      ID   DAY FINISHED DATE      
   <dbl> <dbl>    <dbl> <date>    
 1  1111     1        1 2019-08-01
 2  1111     2        1 2019-08-02
 4  1111     3        1 2019-08-04
 5  2222     1        1 2019-08-01
 6  2222     2        1 2019-08-02
 8  2222     3        1 2019-08-03
 9  3333     1        1 2019-08-01
10  3333     2        1 2019-08-02
11  3333     3        1 2019-08-03
12  3333     4        1 2019-08-04
13  4444     1        1 2019-08-01
14  4444     2        1 2019-08-02
15  4444     3        1 2019-08-03
16  4444     4        0 2019-08-04

【问题讨论】:

  • @RonakShah 刚做了,谢谢你的建议。
  • 这不是 tidyverse,而是 d[!(duplicated(d[c("ID","DAY")]) &amp; d$FINISHED == 0),] - 如果你愿意的话,我怀疑它可以被塞进filter()

标签: r dplyr


【解决方案1】:

这是dplyr 中的一种方法,它仅过滤掉重复的DAYFINISHED == 0,仅用于具有3 天以上的IDs。 -

d %>% 
  group_by(ID) %>% 
  filter(n() >= 3 & !(duplicated(DAY) & FINISHED == 0)) %>% 
  ungroup()

# A tibble: 15 x 3
      ID   DAY FINISHED
   <dbl> <dbl>    <dbl>
 1  1111     1        1
 2  1111     2        1
 3  1111     3        1
 4  1111     4        1
 5  2222     1        1
 6  2222     2        1
 7  2222     3        1
 8  3333     1        1
 9  3333     2        1
10  3333     3        1
11  3333     4        1
12  4444     1        1
13  4444     2        1
14  4444     3        1
15  4444     4        0

【讨论】:

    【解决方案2】:

    我们可以 group_by IDDAY 并删除 group 超过一行和 FINISHED == 0 的行

    library(dplyr)
    d %>%
      group_by(ID, DAY) %>%
      filter(!(n() > 1 & FINISHED == 0))
    
    #      ID   DAY FINISHED
    #   <dbl> <dbl>    <dbl>
    # 1  1111     1        1
    # 2  1111     2        1
    # 3  1111     3        1
    # 4  1111     4        1
    # 5  2222     1        1
    # 6  2222     2        1
    # 7  2222     3        1
    # 8  3333     1        1
    # 9  3333     2        1
    #10  3333     3        1
    #11  3333     4        1
    #12  4444     1        1
    #13  4444     2        1
    #14  4444     3        1
    #15  4444     4        0
    

    在基础 R 中使用相同的逻辑 ave

    d[!with(d, ave(FINISHED == 0, ID, DAY, FUN = function(x) length(x) > 1 & x == 0)), ]
    

    data.table

    library(data.table)
    setDT(d)[, .SD[!(.N > 1 & FINISHED == 0)], by = .(ID, DAY)]
    

    编辑

    对于更新后的数据,我们可以再添加一个&amp;条件

    d %>%
      group_by(ID, DAY) %>%
      dplyr::filter(!(n() > 1 & FINISHED == 0) &
                    !(n() > 1 & all(FINISHED == 1) & DATE == min(DATE)))
    
    #      ID   DAY FINISHED DATE      
    #   <dbl> <dbl>    <dbl> <date>    
    # 1  1111     1        1 2019-08-01
    # 2  1111     2        1 2019-08-02
    # 3  1111     3        1 2019-08-04
    # 4  2222     1        1 2019-08-01
    # 5  2222     2        1 2019-08-02
    # 6  2222     3        1 2019-08-03
    # 7  3333     1        1 2019-08-01
    # 8  3333     2        1 2019-08-02
    # 9  3333     3        1 2019-08-03
    #10  3333     4        1 2019-08-04
    #11  4444     1        1 2019-08-01
    #12  4444     2        1 2019-08-02
    #13  4444     3        1 2019-08-03
    #14  4444     4        0 2019-08-04
    

    【讨论】:

    • 谢谢,这很好用。我编辑了我的答案,以包括我现在正在处理的复杂程度。您能否扩展您的 dplyr 回复以包含此新信息?
    • @Ronak_Shah re:min(DATE) 部分,如果某一天有 3 个条目,我需要删除底部的两个日期怎么办?这只会删除第一个(最短日期)提交。 TIA。
    • @Brigadeiro 在这种情况下你可以使用maxd %&gt;% group_by(ID, DAY) %&gt;% dplyr::filter(!(n() &gt; 1 &amp; FINISHED == 0) &amp; !(n() &gt; 1 &amp; all(FINISHED == 1) &amp; DATE != max(DATE)))
    猜你喜欢
    • 2015-11-24
    • 1970-01-01
    • 2021-10-23
    • 2014-03-14
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    相关资源
    最近更新 更多