根据多个变量进行分组,包括时间序列数据

时间:2019-05-14 15:36:52

标签: r time-series grouping

我有一个数据框,其中列出了在应用程序上执行的每个“事件”(用于执行操作的术语)。每个事件都有一个用户ID,时间戳(格式:“ hms” num)和日期戳(格式:Date)以及其他变量,但这是与我的问题有关的唯一变量。我正在尝试将每个用户彼此之间30分钟内发生的事件进行分组。例如,用户123的8行事件将被分为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 个答案:

答案 0 :(得分:3)

我会采用迭代方法。下面的方法将处理会话(纯英语定义)持续超过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"
)

然后添加参考行ID和有用的日期时间字段:

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