Сравните временные метки на основе нескольких критериев из нескольких строк и столбцов - PullRequest
2 голосов
/ 30 апреля 2019

У меня есть два фрейма данных с временными метками (в as.POSIXct, формат = "% Y-% m-% d% H:% M:% S"), как показано ниже.

df_ID1
 ID         DATETIME               TIMEDIFF                 EV
  A         2019-03-26 06:13:00    2019-03-26 00:13:00      1
  B         2019-04-03 08:00:00    2019-04-03 02:00:00      1
  B         2019-04-04 12:35:00    2019-04-04 06:35:00      1

df_ID0
  ID         DATETIME                   
  A         2019-03-26 00:02:00         
  A         2019-03-26 04:55:00     
  A         2019-03-26 11:22:00
  B         2019-04-02 20:43:00
  B         2019-04-04 11:03:00
  B         2019-04-06 03:12:00

Я хочу сравнить DATETIME в df_ID1 с DATETIME в df_ID0 с тем же идентификатором, и DATETIME «меньше, чем ближайший к» в df_ID1,

Для пары в двух совпадающих фреймах данных я хочу дополнительно сравнить TIMEDIFF в df_ID1 с соответствующим DATETIME в df_ID0, если TIMEDIFF в df_ID1 больше, чем DATETIME в df_ID0, изменить EV 1 на 4 в df_ID1.

Мой желаемый результат -

 df_ID1
 ID         DATETIME               TIMEDIFF                 EV
  A         2019-03-26 06:13:00    2019-03-26 00:13:00      1
  B         2019-04-03 08:00:00    2019-04-03 02:00:00      4
  B         2019-04-04 12:35:00    2019-04-04 06:35:00      1

Я проверил, как сравнивать временные метки и вычислять разницу во времени, а также как изменять значения на основе критериев ... Но я не могу найти ничего, чтобы выбрать «меньшие, но самые близкие» временные метки, и не могу понять, как применить всю эту логику тоже.

Любая помощь будет признательна!

Ответы [ 2 ]

2 голосов
/ 30 апреля 2019

Вы можете сделать это с помощью цикла for, имея в виду, что если ваша фактическая база данных очень велика, то издержки будут весьма плохими с точки зрения производительности.

for(i in 1:nrow(df_1)){
  sub <- subset(df_0, ID == df_1$ID[i]) # filter on ID
  df_0_dt <- max(sub[sub$DATETIME < df_1$DATETIME[i],]$DATETIME) # Take max of those with DATETIME less than (ie less than but closest to)
  if(df_0_dt < df_1$TIMEDIFF[i]){ # final condition
    df_1[i, "EV"] <- 4
  } 
}
df_1
# A tibble: 3 x 4
  ID    DATETIME            TIMEDIFF               EV
  <chr> <dttm>              <dttm>              <dbl>
1 A     2019-03-26 06:13:00 2019-03-26 00:13:00     1
2 B     2019-04-03 08:00:00 2019-04-03 02:00:00     4
3 B     2019-04-04 12:35:00 2019-04-04 06:35:00     1
1 голос
/ 30 апреля 2019

Один из вариантов использования вложенных mapply, это сначала split df_ID1 и df_ID0 на основе ID.Рассчитайте разницу во времени между каждым значением в df_ID1 и значением df_ID0 того же ID.Получите индекс «меньше, но ближайший к» и сохраните его в inds и измените значение на 4, если значение соответствующего столбца TIMEDIFF больше соответствующего значения DATETIME.

df_ID1$EV[unlist(mapply(function(x, y) {
                   mapply(function(p, q) {
                     vals = as.numeric(difftime(p, y$DATETIME))
                     inds = which(vals == min(vals[vals > 0]))
                     q > y$DATETIME[inds]
                    }, x$DATETIME, x$TIMEDIFF)
                 }, split(df_ID1, df_ID1$ID), split(df_ID0, df_ID0$ID)))] <- 4


df_ID1
#  ID            DATETIME            TIMEDIFF EV
#1  A 2019-03-26 06:13:00 2019-03-26 00:13:00  1
#2  B 2019-04-03 08:00:00 2019-04-03 02:00:00  4
#3  B 2019-04-04 12:35:00 2019-04-04 06:35:00  1

данные

df_ID0 <- structure(list(ID = structure(c(1L, 1L, 1L, 2L, 2L, 2L), 
.Label = c("A", 
"B"), class = "factor"), DATETIME = structure(c(1553529720, 1553547300, 
1553570520, 1554208980, 1554346980, 1554491520), class = c("POSIXct", 
"POSIXt"), tzone = "")), row.names = c(NA, -6L), class = "data.frame")

df_ID1 <- structure(list(ID = structure(c(1L, 2L, 2L), .Label = c("A", 
"B"), class = "factor"), DATETIME = structure(c(1553551980, 1554249600, 
1554352500), class = c("POSIXct", "POSIXt"), tzone = ""), TIMEDIFF = 
structure(c(1553530380, 
1554228000, 1554330900), class = c("POSIXct", "POSIXt"), tzone = ""), 
EV = c(1, 1, 1)), row.names = c(NA, -3L), class = "data.frame")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...