Как рассчитать разницу в количестве дней с предыдущей действительной строкой данных в той же группе без использования нескольких циклов?

Я хотел бы рассчитать разницу в количестве дней между каждым ответом с предыдущей действительной строкой под тем же человеком / именем.

Набор упрощенных данных как таковой:

data <- data.frame(ID = c(1, 2, 3, 4, 5, 6),
                   Name = c("Jane", rep("May", 3), "Jane", "May"),
                   `Date Received` = as.POSIXct(c("2018-04-30 00:32", "2018-05-01 18:17",
                                       "2018-06-23 17:12", "2018-07-12 10:17",
                                       "2018-08-02 19:30", "2018-08-17 15:41")))

# ID   Name   `Date Received`
   1   Jane    2018-04-30 00:32
   2   May     2018-05-01 18:17
   3   May     2018-06-23 17:12
   4   May     2018-07-12 10:17
   5   Jane    2018-08-02 19:30
   6   May     2018-08-17 15:41

И вот результат, которого я хотел бы добиться:

# ID   Name   `Date Received`     Difference    Valid
   1   Jane    2018-04-30 00:32   NA             Y
   2   May     2018-05-01 18:17   NA             Y
   3   May     2018-06-23 17:12   53             N
   4   May     2018-07-12 10:17   72             Y
   5   Jane    2018-08-02 19:30   95             Y
   6   May     2018-08-17 15:41   37             N

Первый ответ, полученный от отправителя, всегда действителен. Ответ определяется как недействительный и впоследствии игнорируется, если он получен в течение 60 дней после предыдущего действительного ответа, отправленного тем же отправителем.

Расчет разницы во времени для ответов, полученных от Джейн, прост, поскольку всего всего 2 ответа.

Однако расчет на май сложен. Поскольку разница в ответе №3 составляет 53 дня (с 01.05.2018 по 23.06.2018), он будет помечен как недействительный. Следовательно, чтобы вычислить разницу во времени для ответа №4, он сравнивается с ответом №2 вместо ответа №3, поскольку ответ №2 является предыдущими действительными данными. Поскольку разница во времени для ответа № 4 рассчитана на 72 дня (с 2018-05-01 по 2018-07-12), он также помечен как действительный ответ. Следовательно, чтобы вычислить разницу во времени для ответа № 6 (с 12 июля 2018 г. по 17 августа 2018 г.), оно сравнивается с ответом № 4, который является предыдущими действительными данными, и так далее.

Я рассмотрел несколько похожих вопросов по вычислению разницы во времени, но они либо между соседними рядами, либо с первым наблюдением в группе.

Это код, который у меня есть в настоящее время, который вычисляет разницу с первым ответом, полученным от отправителя (что является неправильным методом), и я не знаю, как продолжить работу с этого момента.

data %>%
  group_by(Name) %>%
  mutate(Difference = difftime(`Date Received`, head(`Date Received`, 1), units = "days"))

Кто-нибудь может посоветовать мне решение этого вопроса, пожалуйста?

Большое спасибо!

================================================== ========================= Отредактировано 05.10.2019

Я придумал решение для каждой группы / человека, использующего цикл for, используя в качестве примера May:

name <- "May"

dates <- data %>%
  filter(Name == name) %>%
  pull(Date.Received)

diff <- NA_integer_
valid <- "Y"

for (i in 2:length(dates)) {
  day <- dates[i]
  valid_dates_pos <- tail(which(valid == "Y"), 1)
  recent_valid_day <- dates[valid_dates_pos]
  diff_days <- ceiling(as.numeric(difftime(day, recent_valid_day, units = "days")))
  diff <- c(diff, diff_days)
  valid <- c(valid, ifelse(diff_days <= 60, "N", "Y"))
}

Однако я бы не хотел использовать вложенные циклы.

Как я могу применить это одновременно для каждой группы / человека более эффективным образом?


person Wyn Z.    schedule 09.05.2019    source источник


Ответы (1)


Это то, что вы ищете?

n_vars <- 50
id <- seq(from=1,to=n_vars)
name <- sample(c("n1","n2","n3"),size=n_vars,replace=TRUE)
dte <- sample(seq(as.Date('2018/01/01'), as.Date('2019/01/01'), by="day"), size=n_vars)

data <- data.frame(id,name,dte) %>% 
  group_by(name) %>% 
  arrange(name,dte) %>% 
  mutate(
    diff=dte-lag(dte),
    valid=ifelse(diff<60,"Y","N")
  )
person Zeus    schedule 10.05.2019
comment
Спасибо за попытку, но, к сожалению, это не то решение, которое я ищу. Мой вопрос не просто в вычислении разницы с предыдущей строкой (лаг = 1). Ему необходимо искать самый последний действительный ответ (Valid == Y), полученный перед каждым наблюдением, чтобы вычислить разницу. Кроме того, Valid == Y, когда разница ›60, вы получили наоборот. - person Wyn Z.; 10.05.2019