在组中有条件并按顺序计算变量(dplyr)

时间:2018-09-12 18:45:37

标签: r dplyr tidyverse

我正在尝试基于一组基本决策规则来计算两个变量。但是,大多数行的计算取决于其他行中的值,这要求此计算顺序进行。我不知道如何有效地做到这一点(最好是在tidyverse中)。预先感谢!

数据

数据集的每一行代表一个提交的工作报告。每个报告都嵌套在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")

我正在尝试计算两个新值:startend,这是每个提交的作品的开始和结束时间。有数千行,所以我正在寻找一种有效的解决方案。

决策逻辑

如果报告是该组中的最后一个(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 :(得分:0)

这是一种没有循环的整理方法。

在绘制图片之后,我意识到每个报告的开始只是从组的末尾推迟,该报告要么增加零缓冲(如果是最后一个),要么增加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