Я бы выбрал итеративный подход. Подход, приведенный ниже, будет обрабатывать случаи, когда сеанс (в простом английском языке) так или иначе длится более 30 минут. Вы захотите сделать точку отсечения после первых 30, а затем сразу же приступить к новой «сессии» (ваше определение). Я не мог придумать, как это сделать без итерации таким образом.
Для начала с вашими примерами данных:
library(tidyverse)
library(lubridate)
events <- tribble(
~`user ID`, ~`Event Name`, ~Date, ~Time,
23, "Press", "01/01/2019", "10:20:52",
23, "Read" , "01/01/2019", "10:21:43",
23, "Click", "01/01/2019", "10:27:21",
23, "Press", "01/01/2019", "10:28:05",
87, "Read" , "01/01/2019", "11:42:51",
87, "Press", "01/01/2019", "12:16:02",
87, "Read" , "01/01/2019", "12:17:49",
23, "Click", "01/01/2019", "15:42:51",
23, "Click", "01/01/2019", "15:43:45",
23, "Press", "01/01/2019", "15:45:12",
64, "Read" , "01/01/2019", "18:01:33",
64, "Click", "01/01/2019", "18:02:26",
64, "Click", "01/01/2019", "18:02:58",
64, "Read" , "01/01/2019", "18:04:19",
64, "Press", "01/01/2019", "18:10:47"
)
Затем добавить идентификатор строки ссылки и полезное поле даты и времени:
events <- events %>%
mutate(
event_id = row_number(),
date_time = mdy_hms(paste(Date, Time))
)
Теперь мы создаем нашу первую таблицу сессий, просто получая первую сессию для каждого пользователя:
sessions <- events %>%
group_by(`user ID`) %>%
summarise(session_start = min(date_time)) %>%
mutate(session_end = session_start + minutes(30))
Тогда итерируем!
left_join()
, чтобы найти, какие события уже находятся в известном сеансе.
anti_join()
сообщает нам, каких записей нет в этой таблице известных совпадений.
- Если таких неизвестных нет, все готово!
- Если они есть, получите эти сеансы и добавьте их в таблицу
sessions
.
while(TRUE) {
in_a_known_session <- events %>%
left_join(sessions, by = "user ID") %>%
filter(date_time >= session_start & date_time < session_end)
unassigned <- events %>%
anti_join(in_a_known_session, by = "event_id")
if (nrow(unassigned) == 0) {
break
}
sessions <- sessions %>%
bind_rows(
unassigned %>%
group_by(`user ID`) %>%
summarise(session_start = min(date_time)) %>%
mutate(session_end = session_start + minutes(30))
)
}
Наконец, получите именно ту форму, которую вы ищете в своем примере:
sessions <- sessions %>%
arrange(session_start) %>%
mutate(
`Event Name` = "Session",
Date = format(session_start, "%m/%d/%Y"),
Time = format(session_start, "%H:%M:%S")
) %>%
select(-starts_with("session_"))
Если это работает для вас, и вы принимаете это, это будет мой первый принятый ответ StackOverflow! : D