我有一个数据框,其中列出了在应用程序上执行的每个“事件”(用于执行操作的术语)。每个事件都有一个用户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的新手,而且这个问题似乎比我到目前为止所遇到的要先进得多。
答案 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))
然后我们进行迭代!
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