Это может быть неэффективно, но я считаю, что может быть над чем работать. Он использует lubridate
/ tidyverse
. Я подозреваю, что подход data.table
может быть лучше.
Во-первых, убедитесь, что ваше время указано в формате POSIXct
. Затем вы можете свернуть свои временные диапазоны из-за перекрытия.
Затем создайте последовательность часовых интервалов на основе минимального и максимального времени из ваших временных диапазонов.
Наконец, чтобы создать свой результат с количеством минут для каждого часа в последовательности часовых интервалов, используйте intersect
между интервалами.
Пожалуйста, дайте мне знать, если это близко к тому, что вы имели в виду.
library(tidyverse)
library(lubridate)
# Determine overlapping ranges of times
time_ranges <- df %>%
mutate_at(c("session_start", "session_stop", "observation_time"), as.POSIXct) %>%
arrange(session_start) %>%
group_by(g = c(0, cumsum(as.numeric(lead(session_start)) > cummax(as.numeric(session_stop)))[-n()])) %>%
summarise(start = min(session_start), stop = max(session_stop)) %>%
mutate(interval = interval(start, stop))
# Create hourly intervals needed
hour_start <- seq(from = floor_date(min(time_ranges$start), unit = "hours"),
to = ceiling_date(max(time_ranges$stop), unit = "hours"),
by = "hours")
hour_int <- interval(hour_start, hour_start + hours(1))
# Determine overlap between hourly intervals and determined time ranges
data.frame(
hour = hour_start,
min_watched = sapply(seq_along(hour_int), function(x) sum(as.numeric(as.duration(intersect(hour_int[x], time_ranges$interval)), "minutes"), na.rm = TRUE))
)
Редактировать :
Если вы sh используете 30-минутные интервалы вместо одного часа, вы можете создать последовательность из 30-минутных интервалов:
# Create half hour intervals
half_hour_start <- seq(from = floor_date(min(time_ranges$start), unit = "hours"),
to = ceiling_date(max(time_ranges$stop), unit = "hours"),
by = "30 min")
half_hour_int <- interval(half_hour_start, half_hour_start + minutes(30))
Я считаю, что остальная часть кода должна быть такой же.
Изменить (10.08.2020) : Чтобы также включить временные диапазоны для каждого часа, попробуйте это при создании окончательных данных .frame:
data.frame(
hour = hour_start,
min_watched = sapply(seq_along(hour_int), function(x) sum(as.numeric(as.duration(intersect(hour_int[x], time_ranges$interval)), "minutes"), na.rm = TRUE)),
time_range = sapply(seq_along(hour_int), function(x) as.character(intersect(hour_int[x], time_ranges$interval)))
)
Или, если вам просто нужно время, вы можете выполнить собственное форматирование и отбросить даты с помощью специальной функции, например:
get_range <- function(hour, interval) {
time_int <- intersect(hour, interval)
return(paste(format(int_start(time_int), "%H:%M"), "-", format(int_end(time_int), "%H:%M")))
}
Затем вы можно использовать это при создании окончательного data.frame:
time_range = sapply(seq_along(hour_int), function(x) get_range(hour_int[x], time_ranges$interval))