найдите средние инциденты за рабочий день

#r #dplyr #lubridate #bizdays

Вопрос:

У меня есть набор данных, как показано ниже:

  ---- ------- --------------------- 
| ID | SUBID |        date         |
 ---- ------- --------------------- 
| A  |     1 | 2021-01-01 12:00:00 |
| A  |     1 | 2021-01-02 01:00:00 |
| A  |     1 | 2021-01-02 02:00:00 |
| A  |     1 | 2021-01-03 03:00:00 |
| A  |     2 | 2021-01-05 16:00:00 |
| A  |     2 | 2021-01-06 13:00:00 |
| A  |     2 | 2021-01-07 06:00:00 |
| A  |     2 | 2021-01-08 08:00:00 |
| A  |     2 | 2021-01-08 10:00:00 |
| A  |     2 | 2021-01-08 11:00:00 |
| A  |     3 | 2021-01-09 09:00:00 |
| A  |     3 | 2021-01-10 19:00:00 |
| A  |     3 | 2021-01-11 20:00:00 |
| A  |     3 | 2021-01-12 22:00:00 |
| B  |     1 | 2021-02-01 23:00:00 |
| B  |     1 | 2021-02-02 15:00:00 |
| B  |     1 | 2021-02-03 06:00:00 |
| B  |     1 | 2021-02-04 08:00:00 |
| B  |     2 | 2021-02-05 18:00:00 |
| B  |     2 | 2021-02-05 19:00:00 |
| B  |     2 | 2021-02-06 22:00:00 |
| B  |     2 | 2021-02-06 23:00:00 |
| B  |     2 | 2021-02-07 04:00:00 |
| B  |     2 | 2021-02-08 02:00:00 |
| B  |     3 | 2021-02-09 01:00:00 |
| B  |     3 | 2021-02-10 03:00:00 |
| B  |     3 | 2021-02-11 13:00:00 |
| B  |     3 | 2021-02-12 14:00:00 |
 ---- ------- --------------------- 
 

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

  ---- ------- --------------------- ------------------------------------------------------------------ 
| ID | SUBID |        date         | timediff (hours) with preceding date for each group (ID, SUBID) |
 ---- ------- --------------------- ------------------------------------------------------------------ 
| A  |     1 | 2021-01-01 12:00:00 |                                                                0 |
| A  |     1 | 2021-01-02 01:00:00 |                                                               13 |
| A  |     1 | 2021-01-02 02:00:00 |                                                                1 |
| A  |     1 | 2021-01-03 03:00:00 |                                                                1 |
| A  |     2 | 2021-01-05 16:00:00 |                                                                0 |
| A  |     2 | 2021-01-06 13:00:00 |                                                               21 |
| A  |     2 | 2021-01-07 06:00:00 |                                                               17 |
| A  |     2 | 2021-01-08 08:00:00 |                                                                2 |
| A  |     2 | 2021-01-08 10:00:00 |                                                                2 |
| A  |     2 | 2021-01-08 11:00:00 |                                                                1 |
| A  |     3 | 2021-01-09 09:00:00 |                                                                0 |
| A  |     3 | 2021-01-10 19:00:00 |                                                               36 |
| A  |     3 | 2021-01-11 20:00:00 |                                                                1 |
| A  |     3 | 2021-01-12 22:00:00 |                                                                1 |
| B  |     1 | 2021-02-01 23:00:00 |                                                                0 |
| B  |     1 | 2021-02-02 15:00:00 |                                                               16 |
| B  |     1 | 2021-02-03 06:00:00 |                                                               15 |
| B  |     1 | 2021-02-04 08:00:00 |                                                               26 |
| B  |     2 | 2021-02-05 18:00:00 |                                                                0 |
| B  |     2 | 2021-02-05 19:00:00 |                                                                1 |
| B  |     2 | 2021-02-06 22:00:00 |                                                               27 |
| B  |     2 | 2021-02-06 23:00:00 |                                                                1 |
| B  |     2 | 2021-02-07 04:00:00 |                                                                5 |
| B  |     2 | 2021-02-08 02:00:00 |                                                               22 |
| B  |     3 | 2021-02-09 01:00:00 |                                                                0 |
| B  |     3 | 2021-02-10 03:00:00 |                                                               26 |
| B  |     3 | 2021-02-11 13:00:00 |                                                               11 |
| B  |     3 | 2021-02-12 14:00:00 |                                                                1 |
 ---- ------- --------------------- ------------------------------------------------------------------ 
 

и, наконец, я хочу рассчитать среднее время, которое будет представлять собой сумму различий во времени для каждой группы (ID, SUBID), разделенную на общее количество для каждой группы, как указано ниже:

  ---- ------- ------------------------------------------------------------ 
| ID | SUBID | Average  time (count per group/ total time diff of group ) |
 ---- ------- ------------------------------------------------------------ 
| A  |     1 | 15/4                                                       |
| A  |     2 | 43/6                                                       |
| A  |     3 | 38/4                                                       |
| B  |     1 | 57/4                                                       |
| B  |     2 | 56/6                                                       |
| B  |     3 | 38/4                                                       |
 ---- ------- ------------------------------------------------------------ 
 

Я довольно новичок в R, и я наткнулся на lubridate, чтобы помочь мне отформатировать даты, и я смог получить разницу во времени, используя приведенный ниже код

 df%>%
        group_by(ID, SUBID) %>%
        mutate(time_diff = difftime(date, lag(date), unit = 'min'))
 

Однако у меня возникли проблемы с получением разницы только во времени рабочих дней, а также со средним временем в соответствии с последней таблицей

Ответ №1:

Добро пожаловать на SO! Использование dplyr и lubridate :

Используемые данные:

 library(tidyverse)
library(lubridate)
df <- data.frame(ID = c("A","A","A","A"),
                 SUBID = c(1,1,2,2),
                 Date = lubridate::as_datetime(c("2021-01-01 12:00:00","2021-01-02 1:00:00","2021-01-01 2:00:00","2021-01-01 13:00:00")))

  ID SUBID                Date
1  A     1 2021-01-01 12:00:00
2  A     1 2021-01-02 01:00:00
3  A     2 2021-01-01 02:00:00
4  A     2 2021-01-01 13:00:00
 

Код:

 df %>% 
  group_by(ID, SUBID) %>% 
  mutate(diff = Date - lag(Date)) %>% 
  mutate(diff = ifelse(is.na(diff), 0, diff)) %>% 
  summarise(Average = sum(diff)/n())
 

Выход:

   ID    SUBID Average
  <chr> <dbl>   <dbl>
1 A         1     6.5
2 A         2     5.5
 

Изменить: Как обрабатывать выходные недели

Для выходных более простым решением является перенос дня на следующий понедельник:

 df %>% 
  mutate(week_day = wday(Date,label = TRUE, abbr = FALSE)) %>%
  mutate(Date = ifelse(week_day == "samedi", Date   days(2),
                       ifelse(week_day == "dimanche", Date   days(1), Date))) %>%
  mutate(Date = as_datetime(Date))
 

Это создаст столбец week_day с именем дня. Если день является «самеди» (суббота) или «диманш» (воскресенье), он добавляет 2 или 1 день к Дате, поэтому он становится понедельником. Затем вам просто нужно изменить порядок дат ( df %>% arrange(ID, SUBID, Date)) и повторить первый код.

Поскольку мой местный язык-французский, вам придется изменить samedi и dimanche на saturday и sunday

Для праздников вы можете применить ту же систему, создав переменную временного интервала, которая представляет праздники, проверьте для каждой даты, находится ли она в этом интервале, и если да, измените дату на последний день этого интервала.

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

1. Спасибо, не могли бы вы сообщить мне, как перенести даты, приходящиеся на выходные или праздничные дни, на ближайший будний день перед расчетом ?

2. Извините, я не обратил внимания на эту часть вашей просьбы. Я подумаю над этим