#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
вместо afor
-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
.