Группировка по нескольким переменным, включая данные временных рядов - PullRequest
0 голосов
/ 14 мая 2019

У меня есть датафрейм, в котором перечислены все «события» (термин, используемый для действия), выполняемые в приложении.Каждое событие имеет среди прочих идентификатор пользователя, метку времени (в формате: 'hms' num) и метку даты (в формате: Date), но это единственные переменные, относящиеся к моей проблеме.Я пытаюсь сгруппировать события, которые происходят в течение 30 минут друг от друга для каждого пользователя.Например, 8 строк событий для пользователя 123 будут сгруппированы в 2 строки, представляющие различные сеансы активности в приложении.

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

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

Ниже приведен пример того, как выглядит мой фрейм данных:

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

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

В идеале я пытаюсь получить конечный результат, который выглядит следующим образом:

user ID         Event Name         Date         Time

23              Session            01/01/2019   10:20:52
87              Session            01/01/2019   11:42:51
87              Session            01/01/2019   12:16:02
23              Session            01/01/2019   15:42:51
64              Session            01/01/2019   18:01:33

Таким образом, по сути, несколько строксобытия, происходящие в течение 30 минут друг от друга, были сведены в 1 строку, где имя события было переименовано в сеанс.Любая помощь будет высоко ценится, так как я все еще новичок в R, и эта проблема, кажется, немного более продвинута, чем я привык до сих пор.

1 Ответ

3 голосов
/ 14 мая 2019

Я бы выбрал итеративный подход. Подход, приведенный ниже, будет обрабатывать случаи, когда сеанс (в простом английском языке) так или иначе длится более 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))

Тогда итерируем!

  1. left_join(), чтобы найти, какие события уже находятся в известном сеансе.
  2. anti_join() сообщает нам, каких записей нет в этой таблице известных совпадений.
  3. Если таких неизвестных нет, все готово!
  4. Если они есть, получите эти сеансы и добавьте их в таблицу 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

...