在 R 中跟踪整个网站的用户会话

Tracking User Sessions across a website in R

我正在寻求有关使用 R 创建和跟踪用户会话以及会话内活动的帮助。在较高级别上,我有一列用户 ID 和一列时间戳。

对于每个用户 ID,我想计算时间戳之间的时间差,并使用它根据时间限制值分配会话号。 (即用户的第一个时间戳的会话号为 1。如果下一个时间戳小于 30 分钟,则会话号将保持为 1,否则将增加到 2,依此类推。)

为每个用户操作观察分配一个会话编号后,我想对每个会话中的活动进行排序。每个会话的第一个观察结果的 activity 数量为 1,会话中的第二个观察结果的 activity 数量为 2,依此类推。当会话编号更改(或用户 ID 更改)时,activity 编号将重置回 1。

我有以下重现,它可以满足我的要求,但是,这段代码在我的完整数据集(140 万行)上运行速度非常慢。特别是,对 difftime 和 for 循环的调用非常慢。我想知道是否有更好的方法来做到这一点并且对多种想法持开放态度。也许有一种方法可以在不使用 purrr 循环的情况下执行此操作,或者这可能是并行库的一个很好的用例。很高兴听到有关如何简化此过程的任何建议。

library(tidyverse)

session_time_limit <- 30

x <- tibble(ID = c("a", "a", "a", "a", "b", "b", "c", "c", "c"),
       Date = c(as.POSIXct("2021-01-25 19:17:12 UTC"), #a1
                as.POSIXct("2021-01-25 19:17:30 UTC"), #a2
                as.POSIXct("2021-01-25 19:57:12 UTC"), #a3
                as.POSIXct("2021-01-25 19:59:12 UTC"), #a4
                as.POSIXct("2021-01-25 20:11:12 UTC"), #b1
                as.POSIXct("2021-01-25 20:42:12 UTC"), #b2
                as.POSIXct("2021-01-25 21:15:42 UTC"), #c1
                as.POSIXct("2021-01-25 21:17:12 UTC"), #c2
                as.POSIXct("2021-01-25 21:20:13 UTC"))) #c3

x <- x %>% 
  arrange(ID, Date) %>% 
  group_by(ID) %>% 
  mutate(tdiff = difftime(Date, lag(Date), units = "mins"),
         session_number = 1,
         activity_within_session = 1)

for(i in seq(2, nrow(x))) {
  if(!is.na(x$tdiff[i]) &
     #     x$ID[i] == x$ID[i-1] &
     x$tdiff[i] > session_time_limit)
  {
    x$session_number[i] = x$session_number[i-1] + 1
  } else if(!is.na(x$tdiff[i]) &
            x$ID[i] == x$ID[i-1] &
            x$tdiff[i] <= session_time_limit)
  {
    x$session_number[i] = x$session_number[i-1]
  }
}

# Activity within Session
for(i in seq(2, nrow(x))) {
  if(!is.na(x$tdiff[i]) &
     #  x$ID[i] == x$ID[i-1] &
     x$session_number[i] == x$session_number[i-1])
  {
    x$activity_within_session[i] = 
      x$activity_within_session[i-1] + 1
  }
}

选项可以是:

library(tidyverse)
library(lubridate)

session_time_limit <- 30
df <- tibble(ID = c("a", "a", "a", "a", "b", "b", "c", "c", "c"),
             Date = c(as.POSIXct("2021-01-25 19:17:12 UTC"), #a1
                      as.POSIXct("2021-01-25 19:17:30 UTC"), #a2
                      as.POSIXct("2021-01-25 19:57:12 UTC"), #a3
                      as.POSIXct("2021-01-25 19:59:12 UTC"), #a4
                      as.POSIXct("2021-01-25 20:11:12 UTC"), #b1
                      as.POSIXct("2021-01-25 20:42:12 UTC"), #b2
                      as.POSIXct("2021-01-25 21:15:42 UTC"), #c1
                      as.POSIXct("2021-01-25 21:17:12 UTC"), #c2
                      as.POSIXct("2021-01-25 21:20:13 UTC"))) #c3

df %>% 
  group_by(ID) %>%
  mutate(tdiff = replace_na(interval(lag(Date), Date)/dminutes(1), 0),
         session_number = cumsum(tdiff > session_time_limit) + 1) %>% 
  group_by(session_number, .add = T) %>% 
  mutate(activity_within_session = row_number()) %>% 
  ungroup()
#> # A tibble: 9 x 5
#>   ID    Date                tdiff session_number activity_within_session
#>   <chr> <dttm>              <dbl>          <dbl>                   <int>
#> 1 a     2021-01-25 19:17:12  0                 1                       1
#> 2 a     2021-01-25 19:17:30  0.3               1                       2
#> 3 a     2021-01-25 19:57:12 39.7               2                       1
#> 4 a     2021-01-25 19:59:12  2                 2                       2
#> 5 b     2021-01-25 20:11:12  0                 1                       1
#> 6 b     2021-01-25 20:42:12 31                 2                       1
#> 7 c     2021-01-25 21:15:42  0                 1                       1
#> 8 c     2021-01-25 21:17:12  1.5               1                       2
#> 9 c     2021-01-25 21:20:13  3.02              1                       3

reprex package (v2.0.0)

于 2021-05-26 创建

data.table

library(data.table)
setDT(df)
df[, tdiff := c(0, diff(as.numeric(Date)) / 60), by = ID
   ][, session_number := cumsum(tdiff > session_time_limit) + 1, by = ID
     ][, activity_within_session := rowid(ID, session_number)][]

library(data.table)
library(magrittr)
df[, tdiff := c(0, diff(as.numeric(Date)) / 60), by = ID] %>% 
  .[, session_number := cumsum(tdiff > session_time_limit) + 1, by = ID] %>% 
  .[, activity_within_session := rowid(ID, session_number)] %>% 
  .[]
    
   ID                Date     tdiff session_number activity_within_session
1:  a 2021-01-25 19:17:12  0.000000              1                       1
2:  a 2021-01-25 19:17:30  0.300000              1                       2
3:  a 2021-01-25 19:57:12 39.700000              2                       1
4:  a 2021-01-25 19:59:12  2.000000              2                       2
5:  b 2021-01-25 20:11:12  0.000000              1                       1
6:  b 2021-01-25 20:42:12 31.000000              2                       1
7:  c 2021-01-25 21:15:42  0.000000              1                       1
8:  c 2021-01-25 21:17:12  1.500000              1                       2
9:  c 2021-01-25 21:20:13  3.016667              1                       3