【问题标题】:remove duplicates and collapse near duplicates based on time difference根据时差删除重复项并在重复项附近折叠
【发布时间】:2020-07-30 20:15:07
【问题描述】:

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

DF = structure(list(Age_visit = c(48, 48, 48, 49, 49, 77), Date_1 = c("8/6/2169 9:40", "8/6/2169 9:40", 
                                                                     "8/6/2169 9:41", "8/6/2169 9:42", "24/7/2169 8:31", "12/9/2169 10:30", 
                                                                     "19/6/2237 12:15"), Date_2 = c("NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", 
                                                                                                            "NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", 
                                                                                                            "NA-NA-NA NA:NA:NA"), person_id = c("21",
                                                                                                                                                  "21", 
                                                                                                                                                  "21", 
                                                                                                                                                  "21", 
                                                                                                                                                  "21", 
                                                                                                                                                  "21", 
                                                                                                                                                  "31"
                                                                                                            ), enc_id = c("A21BC","A21BC", 
                                                                                                                                       "A22BC", 
                                                                                                                                       "A23BC", 
                                                                                                                                       "A24BC", 
                                                                                                                                       "A25BC", 
                                                                                                                                       "A31BC"
                                                                                                            )), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"
                                                                                                            ))

数据框

  Age_visit Date_1          Date_2            person_id enc_id
      <dbl> <chr>           <chr>             <chr>     <chr> 
1        48 8/6/2169 9:40   NA-NA-NA NA:NA:NA  21        A21BC 
2        48 8/6/2169 9:40   NA-NA-NA NA:NA:NA  21        A21BC 
3        48 8/6/2169 9:41   NA-NA-NA NA:NA:NA  21        A22BC 
4        49 8/6/2169 9:42   NA-NA-NA NA:NA:NA  21        A23BC 
5        49 24/7/2169 8:31  NA-NA-NA NA:NA:NA  21        A24BC 
6        77 12/9/2169 10:30 NA-NA-NA NA:NA:NA  31        A31BC 

我有两个规则/步骤要实施。

规则 1(步骤 1)

首先,根据Date_1person_idenc_id 等 3 列删除重复项

DF[!duplicated(DF[,c('Date_1','person_id','enc_id')]),]  # this will remove 1st row as it's a plain straight forward duplicate

规则 2(步骤 2)

从步骤 1 的输出中,如果这些记录之间的时间差小于一小时,则将基于时间的重复记录(注意 DATE_1enc_id 列中的微小差异)折叠成一条记录。

例如,如果你看到person_id = 21,你可以看到在step-1之后,他所有的Date_1时间值都在同一天,但相差只有一分钟(9:40 --> 9: 41 --> 9:42)。由于不到一个小时(60 分钟),我们将它们全部折叠成一条记录并仅保留第一条记录(即 9:40)。 我们对数据框中的每个主题进行此检查

我已经根据如下所示的几列删除了重复项

DF[!duplicated(DF[,c('Date_1','person_id','enc_id')]),]

我希望我的输出如下所示

  Age_visit Date_1          Date_2            person_id enc_id
      <dbl> <chr>           <chr>             <chr>     <chr> 
1        48 8/6/2169 9:40   NA-NA-NA NA:NA:NA  21        A21BC 
4        49 24/7/2169 8:31  NA-NA-NA NA:NA:NA  21        A24BC 
5        77 12/9/2169 10:30 NA-NA-NA NA:NA:NA  31        A31BC 

【问题讨论】:

    标签: r dataframe dplyr data.table tidyr


    【解决方案1】:

    使用data.table 的滚动连接选项:

    DT[, c("rn", "hrago") := .(.I, Date_1 - 60 * 60)]
    DT[DT[DT, on=.(person_id, Date_1=hrago), roll=-Inf, unique(rn)]]
    

    输出:

       Age_visit              Date_1 person_id enc_id rn               hrago
    1:        48 2169-06-08 09:40:00        21  A21BC  1 2169-06-08 08:40:00
    2:        49 2169-07-24 08:31:00        21  A24BC  5 2169-07-24 07:31:00
    3:        77 2169-09-12 10:30:00        31  A31BC  6 2169-09-12 09:30:00
    

    数据:

    library(data.table)
    DT <- fread("Age_visit Date_1    person_id enc_id
    48 8/6/2169-9:40    21        A21BC 
    48 8/6/2169-9:40    21        A21BC 
    48 8/6/2169-9:41    21        A22BC 
    49 8/6/2169-9:42    21        A23BC 
    49 24/7/2169-8:31   21        A24BC 
    77 12/9/2169-10:30  31        A31BC") 
    DT[, Date_1 := as.POSIXct(Date_1, format="%d/%m/%Y-%H:%M")]
    

    解释:

    1) DT[DT, on=.(person_id, Date_1=hrago), 是使用两个表中的person_id 和右表中的Date_1 和左表中的hrago 的自联接。

    2) roll=-Inf 如果未找到左表中观察值的相同匹配项,则将右表中的观察值向后滚动

    3) unique(rn) 从右表中获取唯一行,然后为这些行过滤表。

    【讨论】:

    • 感谢您的回复。赞成。如果需要,也会尝试您的答案并更新答案
    • 嗨,对不起,R 新手。我的输入数据是数据框格式。那么,我必须将我的数据框转换为数据表才能使用此解决方案吗?
    • 谢谢。我正在讨论数据表和滚动连接,但你能帮我理解这行代码的作用吗? DT[DT[DT, on=.(person_id, Date_1=hrago), roll=-Inf, unique(rn)]]
    • 我知道它基于 person_id 和 hrago 这两个键向后滚动和加入。将 DT 数据表加入自身???
    • @TheGreat 我在帖子中添加了一些解释
    【解决方案2】:

    您的问题可以使用 dplyr 管道解决。

    • 第一步使用distinct()解决重复问题。
    • 秒步骤将 Date_1 列更改为 Datetime 类型(计算时差所必需的。
    • 第三步使用lag() 添加具有先前时间戳的列。这必须在 person_id 上的 group_by() 中,以确保时间戳不会转移给其他人。此外,确保正确安排日期也很重要(使用arrange())。
    • 第四步计算自上一个时间戳以来的时间差(以秒为单位)。这将为一个人的第一行提供一个 NA。
    • 第五步删除时差小于一小时的所有记录
    • 最后一步删除了在管道中创建的所有其他列。
    library(dplyr)
    
    DF %>% 
      distinct(Date_1, person_id , enc_id, .keep_all = T) %>% 
      mutate(Date_1 = as.POSIXct(Date_1, format = '%d/%m/%Y %H:%M')) %>% 
      group_by(person_id) %>% 
      arrange(Date_1) %>%
      mutate(Date_lag = lag(Date_1)) %>% 
      ungroup() %>% 
      mutate(Date_diff = difftime(Date_1, Date_lag, units = 'secs')) %>% 
      filter(is.na(Date_diff) | Date_diff >= 3600) %>% 
      select(Age_visit, Date_1, Date_2, person_id, enc_id)
    

    【讨论】:

      【解决方案3】:

      通过检查连续的时间差,您可以在同一步骤中执行这两项操作。重复的时间差为0:

      library(dplyr)
      library(lubridate)
      
      DF %>%
        group_by(person_id)%>%
        mutate(Date_1 = dmy_hm(Date_1)) %>%
        arrange((Date_1)) %>%
        filter(c(5000,diff(Date_1))>3600)
      
      
        Age_visit Date_1              Date_2            person_id enc_id
            <dbl> <dttm>              <chr>             <chr>     <chr> 
      1        48 2169-06-08 09:40:00 NA-NA-NA NA:NA:NA 21        A21BC 
      2        49 2169-07-24 08:31:00 NA-NA-NA NA:NA:NA 21        A24BC 
      3        77 2169-09-12 10:30:00 NA-NA-NA NA:NA:NA 31        A25BC 
      

      您的数据有误(person_id 31 丢失)。这是我用过的:

      DF = structure(list(Age_visit = c(48, 48, 48, 49, 49, 77), Date_1 = c("8/6/2169 9:40", "8/6/2169 9:40", 
                                                                            "8/6/2169 9:41", "8/6/2169 9:42", "24/7/2169 8:31", "12/9/2169 10:30", 
                                                                            "19/6/2237 12:15"), Date_2 = c("NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", 
                                                                                                           "NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", "NA-NA-NA NA:NA:NA", 
                                                                                                           "NA-NA-NA NA:NA:NA"), person_id = c("21",
                                                                                                                                               "21", 
                                                                                                                                               "21", 
                                                                                                                                               "21", 
                                                                                                                                               "21", 
                                                                                                                                               "31"
                                                                                                           ), enc_id = c("A21BC","A21BC", 
                                                                                                                         "A22BC", 
                                                                                                                         "A23BC", 
                                                                                                                         "A24BC", 
                                                                                                                         "A25BC", 
                                                                                                                         "A31BC"
                                                                                                           )), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"
                                                                                                           ))
      

      【讨论】:

      • 是的,好点。滚动连接选项更好更干净。谢谢!
      猜你喜欢
      • 2021-12-30
      • 2016-03-03
      • 2016-09-16
      • 2021-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多