按日期和ID筛选重复数据

3

我有一个如下所示的数据框

Id      Date1        Date2        QuestionId   AnswerValue
10      2000-01-14   2000-01-14   1339         3
10      2000-01-14   1999-12-09   1339         2
10      2000-01-14   1999-11-23   1461         1 
10      2000-01-14   2000-01-03   1461         18
10      2000-01-14   1999-11-16   274          0
57      2014-02-01   2014-12-10   278          0
57      2014-02-01   2012-11-07   280          0
57      2014-02-01   2012-09-30   280          0 
57      2014-02-01   2012-01-15   261          0 

我的目标是根据以下标准保留观察结果。

  1. 保留ID和QuestionID组合中的行,其中QuestionID是唯一的,并且在该ID + QuestionID组合中没有其他重复的QuestionIDs。例如:保留最后一行
Id      Date1        Date2        QuestionId   AnswerValue
57      2014-02-01   2012-01-15   261          0 
  • 如果每个QuestionID+ID组合存在重复的QuestionIDs,则仅保留Date2列值最接近Date1列值的QuestionID行,例如:Id 10有两个QuestionID 1339。根据此标准,只应保留第一行,因为Question ID 1339的Date2值2000-01-14与Date1值2000-01-14相比更接近,而第二行的Date2值是1999-12-09,与Date1值2000-01-14相比较远。
  • Id      Date1        Date2        QuestionId   AnswerValue
    10      2000-01-14   2000-01-14   1339         3
    
    1. 删除任何Date2值大于Date1的行,例如第6行应该被删除

      Id Date1 Date2 QuestionId AnswerValue 57 2014-02-01 2014-12-10 278 0

    最终数据集应该如下所示。

    Id      Date1        Date2        QuestionId   AnswerValue
    10      2000-01-14   2000-01-14   1339         3
    10      2000-01-14   2000-01-03   1461         18
    10      2000-01-14   1999-11-16   274          0
    57      2014-02-01   2014-12-10   278          0
    57      2014-02-01   2012-11-07   280          0
    57      2014-02-01   2012-01-15   261          0 
    

    任何关于实现这个的帮助都非常感激。提前致谢。

    你的第一个标准非常难以遵循。第五和第六行不应该也被保留吗?你只是想要一个唯一的Id+QuestionId组合吗?在一个Id+QuestionId组合中,如何才能有一个唯一的QuestionId 另一个具有相同Id+QuestionId组合的观察值呢? - moman822
    2个回答

    4

    以下是一种使用 dplyr 的想法:

    library(dplyr)
    
    df %>% 
      group_by(Id, QuestionId) %>% 
      slice(which.min(difftime(Date1, Date2))) %>% 
      filter(Date2 <= Date1)
    
    #Source: local data frame [5 x 5]
    #Groups: Id, QuestionId [5]
    
    #     Id      Date1      Date2 QuestionId AnswerValue
    #  <int>     <date>     <date>      <int>       <int>
    #1    10 2000-01-14 1999-11-16        274           0
    #2    10 2000-01-14 2000-01-14       1339           3
    #3    10 2000-01-14 2000-01-03       1461          18
    #4    57 2014-02-01 2012-01-15        261           0
    #5    57 2014-02-01 2012-11-07        280           0
    

    注意

    确保您的日期列已设置为as.Date


    1
    使用data.table,首先按照您的标准3进行过滤(Date2 <= Date1),然后仅返回Date1 - Date2最小的行(即日期最接近的行),并使用by = .(Id, QuestionId)对每个唯一的IdQuestionId组合执行此操作:
    library(data.table)
    dt <- structure(list(Id = c(10L, 10L, 10L, 10L, 10L, 57L, 57L, 57L, 
    57L), Date1 = structure(c(10970, 10970, 10970, 10970, 10970, 
    16102, 16102, 16102, 16102), class = "Date"), Date2 = structure(c(10970, 
    10934, 10918, 10959, 10911, 16414, 15651, 15613, 15354), class = "Date"), 
        QuestionId = c(1339L, 1339L, 1461L, 1461L, 274L, 278L, 280L, 
        280L, 261L), AnswerValue = c(3L, 2L, 1L, 18L, 0L, 0L, 0L, 
        0L, 0L)), .Names = c("Id", "Date1", "Date2", "QuestionId", 
    "AnswerValue"), row.names = c(NA, -9L), class = "data.frame")
    
    setDT(dt)
    dt[Date2 <= Date1, .SD[which.min(Date1-Date2)], by = .(Id, QuestionId)]
    
       Id QuestionId      Date1      Date2 AnswerValue
    1: 10       1339 2000-01-14 2000-01-14           3
    2: 10       1461 2000-01-14 2000-01-03          18
    3: 10        274 2000-01-14 1999-11-16           0
    4: 57        280 2014-02-01 2012-11-07           0
    5: 57        261 2014-02-01 2012-01-15           0
    

    请注意,在您最终的数据示例中,此行未满足第三个条件(Date2 <= Date1):
    Id           Date1      Date2     QuestionId   AnswerValue
    57      2014-02-01   2014-12-10   278          0
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接