удалить дубликаты и свернуть рядом с дубликатами на основе разницы во времени - PullRequest
2 голосов
/ 17 апреля 2020

У меня есть фрейм данных, как показано ниже

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)

Сначала удалите дубликаты на основе 3 столбцов, таких как Date_1, person_id, enc_id

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_1 и enc_id) на основе вовремя в одну запись, если разница во времени между этими записями меньше часа.

Например, если вы видите person_id = 21, вы можете видеть, что после шага 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 

Ответы [ 3 ]

2 голосов
/ 17 апреля 2020

Ваш вопрос может быть решен с помощью конвейера dplyr.

  • Первый шаг решает проблему дублирования, используя distinct().
  • Шаг в секундах изменяет столбец Date_1 на тип Datetime (необходим для вычисления разницы во времени.
  • Третий шаг добавляет столбец с предыдущей отметкой времени, используя lag(). Это должно быть в group_by() для person_id, чтобы гарантировать, что отметки времени не будут перенесены на других людей. Также важно убедиться, что дата организовать правильно (используя 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)
2 голосов
/ 18 апреля 2020

Возможность скользящего соединения с использованием 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) берет уникальные строки из правой таблицы и затем фильтрует таблицу по этим строкам.

1 голос
/ 17 апреля 2020

Вы можете сделать оба в одном шаге, проверяя последовательную разницу во времени. Дубликаты имеют разницу во времени 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"
                                                                                                     ))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...