Одновременный подсчет пользователей из файла журнала

#r

#r

Вопрос:

Я ищу самый быстрый подход к анализу файлов журналов, в которых есть два интересующих столбца: login_time и logout_time получить количество одновременных пользователей, зарегистрированных в системе за определенный промежуток времени ( bin ).

Подход # 1 дает правильное количество на ячейку, но циклы в R не поощряются, поэтому я полагаю, что это не удастся для больших журналов (я ожидаю, что файлы будут содержать даже сотни тысяч строк). Я использовал список, чтобы объект был изменен на месте (проверено address() с pryr помощью библиотеки).

Подход № 2 — это то, что, как я думал, может быть быстрее, но он работает не так, как мне бы хотелось. Теперь он повторяется bins и выдает результат для каждой hist строки. Я хотел бы получить 2D-матрицу, чтобы затем я мог суммировать строки, чтобы получить тот же результат, что и в подходе № 1. Однако я боюсь, что этот подход может быть неэффективным с точки зрения памяти.

 library(tidyverse)
library(lubridate)
#> The following objects are masked from 'package:base':
#> 
#>     date, intersect, setdiff, union

bins <- seq(ymd_hms("2020-09-01 00:00:00"), ymd_hms("2020-09-01 01:00:00"), by = dminutes(15))
n_bins <- length(bins)
hist <- tibble(login_time = rep(ymd_hms("2020-09-01 00:20:00"), 10),
               logout_time = rep(ymd_hms("2020-09-01 00:40:00"), 10))
concurrent_users_list <- list(bin = bins, count = 0)

# Approach #1

for (x in 1:nrow(hist)) {
  hist_row <- hist[x, ]
  bin_first <- floor((hist_row$login_time - ymd_hms("2020-09-01 00:00:00")) / dminutes(15))
  bin_last <- ceiling((hist_row$logout_time - ymd_hms("2020-09-01 00:00:00")) / dminutes(15))

  to_add <- list(x = c(rep(0, bin_first), rep(1, bin_last - bin_first), rep(0, n_bins - bin_last   1)))
  
  concurrent_users_list[["count"]] <-
    concurrent_users_list[["count"]]   to_add$x
}
concurrent_users_list
#> $bin
#> [1] "2020-09-01 00:00:00 UTC" "2020-09-01 00:15:00 UTC"
#> [3] "2020-09-01 00:30:00 UTC" "2020-09-01 00:45:00 UTC"
#> [5] "2020-09-01 01:00:00 UTC"
#> 
#> $count
#> [1]  0 10 10  0  0  0

# Approach #2

hist$login_time <= (bins   minutes(15)) amp; hist$logout_time >= bins
#>  [1] FALSE  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE
  

Создано 2020-11-15 пакетом reprex (версия 0.3.0)

Комментарии:

1. Подход № 1 хорош, но вы могли бы использовать lapply вместо a for -loop для повышения эффективности. Просто перепишите цикл в функцию и используйте lapply(your_list, your_function)

2. Я думаю for , что цикл или применение имеют одинаковую эффективность

3. Я переписал # 1 как test_fun1 <- function(concurrent_users_list) { bin_first <- floor((sess_hist$login_time - ymd_hms("2020-09-01 00:00:00")) / dminutes(15)) bin_last <- ceiling((sess_hist$logout_time - ymd_hms("2020-09-01 00:00:00")) / dminutes(15)) to_add <- list(x = c(rep(0, bin_first - 1), rep(1, bin_last - bin_first 1), rep(0, n_bins - bin_last))) concurrent_users_list[["count"]] <- concurrent_users_list[["count"]] to_add$x } lapply(concurrent_users_list, test_fun1) , но я получаю Error in rep(0, bin_first - 1) : invalid 'times' argument .