Вычислять переменные условно и последовательно внутри групп (dplyr) - PullRequest
0 голосов
/ 12 сентября 2018

Я пытаюсь вычислить две переменные на основе набора основных правил принятия решений.Однако вычисление для большинства строк зависит от значений в других строках, что требует, чтобы это вычисление выполнялось последовательно.Я не могу понять, как сделать это эффективно (в идеале в тидиверсе).Заранее спасибо!

Данные :

Каждая строка набора данных представляет представленный рабочий отчет.Каждый отчет вложен в group, где k указывает на индекс отчета в группе, а n представляет количество отчетов в группе.time - это отметка времени отправки, length - приблизительная продолжительность работы в минутах, а wait указывает, было ли ожидание перед началом работы (wait == 1) или работа была начата немедленно.после завершения предыдущего (wait == 0)

+-------+---+---+---------------------+--------+------+
| group | k | n |        time         | length | wait |
+-------+---+---+---------------------+--------+------+
| A     | 1 | 5 | 2017-10-17 12:43:29 |   17.5 |    1 |
| A     | 2 | 5 | 2017-10-17 12:44:52 |   45.5 |    0 |
| A     | 3 | 5 | 2017-10-17 12:45:58 |   17.5 |    1 |
| A     | 4 | 5 | 2017-10-17 13:45:31 |      5 |    1 |
| A     | 5 | 5 | 2017-10-17 13:46:48 |   17.5 |    0 |
| B     | 1 | 3 | 2017-11-14 12:07:18 |   45.5 |    1 |
| B     | 2 | 3 | 2017-11-14 12:14:43 |   45.5 |    1 |
| B     | 3 | 3 | 2017-11-14 12:17:45 |   45.5 |    1 |
+-------+---+---+---------------------+--------+------+

Редактировать: Пример импортируемых данных

structure(list(group = c("A", "A", "A", "A", "A", "B", "B", "B"
), k = c(1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L), n = c(5L, 5L, 5L, 5L, 
5L, 3L, 3L, 3L), time = structure(c(1508258609.388, 1508258692.614, 
1508258758.234, 1508262331.385, 1508262408.434, 1510679238.849, 
1510679683.961, 1510679865.964), class = c("POSIXct", "POSIXt"
), tzone = "America/New_York"), length = c(17.5, 45.5, 17.5, 5, 17.5, 45.5, 45.5, 
45.5), wait = c(1, 0, 1, 1, 0, 1, 1, 1)), row.names = c(NA, -8L
), class = "data.frame")

Я пытаюсь вычислить два новых значения: start и end, время начала и окончания каждой представленной работы.Есть несколько тысяч строк, поэтому я ищу эффективное решение.

Логика принятия решения :

Если отчет является последним в своей группе (k == n)

end = time

start = end - length

Если отчет не последний, а за ним следует отчет без ожидания (k < n & lead(wait) == 0)

end = lead(start) - 1

start = end - length

Если отчет не последний и за ним следует одинэто включало ожидание (k < n & lead(wait) == 1)

end = lead(start) - 0.5 * length

start = end - length

Таким образом, вычисления начинаются с последнего отчета в каждой группе, а затем циклически возвращаются по строкам до первой строки.

Желаемый выход :

+-------+---+---+---------------------+--------+------+----------+----------+
| group | k | n |        time         | length | wait |   end    |  start   |
+-------+---+---+---------------------+--------+------+----------+----------+
| A     | 1 | 5 | 2017-10-17 12:43:29 |   17.5 |    1 | 11:47:48 | 11:30:18 |
| A     | 2 | 5 | 2017-10-17 12:44:52 |   45.5 |    0 | 12:34:18 | 11:48:48 |
| A     | 3 | 5 | 2017-10-17 12:45:58 |   17.5 |    1 | 13:14:33 | 12:57:03 |
| A     | 4 | 5 | 2017-10-17 13:45:31 |      5 |    1 | 13:28:18 | 13:23:18 |
| A     | 5 | 5 | 2017-10-17 13:46:48 |   17.5 |    0 | 13:46:48 | 13:29:18 |
| B     | 1 | 3 | 2017-11-14 12:07:18 |   45.5 |    1 | 10:01:15 | 9:15:45  |
| B     | 2 | 3 | 2017-11-14 12:14:43 |   45.5 |    1 | 11:09:30 | 10:24:00 |
| B     | 3 | 3 | 2017-11-14 12:17:45 |   45.5 |    1 | 12:17:45 | 11:32:15 |
+-------+---+---+---------------------+--------+------+----------+----------+

1 Ответ

0 голосов
/ 13 сентября 2018

Вот тидиверс подход без петель.

После того, как я нарисовал картинку, я понял, что начало каждого отчета просто отодвигается во времени от конца группы, где этот отчет либо добавляет нулевую подушку (если она последняя), 1 мин (если следующий отчет не ждал ) или половина текущей длины отчета (если ожидался следующий отчет). enter image description here

Итак, если мы изменим порядок, нам просто нужно отследить, сколько задержки нужно добавить для каждой строки, добавить ее к каждой длине, а затем взять их совокупную сумму. Вот сколько времени нужно вычесть из времени окончания группы (которое в этом порядке равно time в первом ряду каждой группы).

output <- df %>%
  arrange(group, -k) %>%
  group_by(group) %>%
  mutate(wait = as.logical(wait)) %>%
  mutate(delay = case_when(k == n      ~ 0,  
                           # is *next* rpt no wait? (use lag since order reversed)
                           lag(!wait)  ~ 1,
                           TRUE        ~ 0.5 * length),
         pushback_alone = length + delay,
         pushback_cumul = cumsum(pushback_alone),
         # So the last shall be first, and the first last...
         start = first(time) - seconds(pushback_cumul*60),              
         end = start + seconds(length*60)
  ) %>% ungroup() %>%  # EDIT: to make the table ungrouped like it started
  arrange(group, k)

Результат

output
# A tibble: 8 x 11
# Groups:   group [2]
  group     k     n time                length wait  delay pushback_alone pushback_cumul start               end                
  <chr> <int> <int> <dttm>               <dbl> <lgl> <dbl>          <dbl>          <dbl> <dttm>              <dttm>             
1 A         1     5 2017-10-17 12:43:29   17.5 TRUE   1              18.5          136.  2017-10-17 11:30:18 2017-10-17 11:47:48
2 A         2     5 2017-10-17 12:44:52   45.5 FALSE 22.8            68.2          118   2017-10-17 11:48:48 2017-10-17 12:34:18
3 A         3     5 2017-10-17 12:45:58   17.5 TRUE   8.75           26.2           49.8 2017-10-17 12:57:03 2017-10-17 13:14:33
4 A         4     5 2017-10-17 13:45:31    5   TRUE   1               6             23.5 2017-10-17 13:23:18 2017-10-17 13:28:18
5 A         5     5 2017-10-17 13:46:48   17.5 FALSE  0              17.5           17.5 2017-10-17 13:29:18 2017-10-17 13:46:48
6 B         1     3 2017-11-14 12:07:18   45.5 TRUE  22.8            68.2          182   2017-11-14 09:15:45 2017-11-14 10:01:15
7 B         2     3 2017-11-14 12:14:43   45.5 TRUE  22.8            68.2          114.  2017-11-14 10:24:00 2017-11-14 11:09:30
8 B         3     3 2017-11-14 12:17:45   45.5 TRUE   0              45.5           45.5 2017-11-14 11:32:15 2017-11-14 12:17:45
...