【问题标题】:Compute variables conditionally and sequentially within groups (dplyr)在组内有条件地和顺序地计算变量(dplyr)
【发布时间】:2018-09-12 18:45:36
【问题描述】:

我正在尝试根据一组基本决策规则计算两个变量。但是,大多数行的计算取决于其他行中的值,这需要按顺序执行此计算。我不知道如何有效地做到这一点(最好是在 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 |
+-------+---+---+---------------------+--------+------+----------+----------+

【问题讨论】:

  • 所有表格布局+-----+---+...您的数据很容易看到,但很难导入R进行实验。您介意编辑您的输入数据以使其更友好地复制/粘贴到 R 中吗?添加dput(your_sample_data) 将是完美的...
  • 我以前也问过类似的问题,data.table 包是最有效的方法。查看我的帖子和 Arun 的回答以获得一些想法Identify Value Changes and Summarize Values
  • @Gregor:添加了一个可导入的数据示例
  • 感谢您提供示例数据。当我将它加载到我的系统中时,时间会有所不同(例如第一行 09:43:29 而不是 12:43:29),大概是因为我们各自的一个或两个系统都将我们的本地时区强加在数据上。有谁知道如何以这种方式分享和/或接收 POSIXct 但没有 tz shift?
  • 似乎wait 值从您的输入反转到您的输出。这是故意的吗?

标签: r dplyr tidyverse


【解决方案1】:

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

画完图后,我意识到每个报告的开始时间只是从组的末尾向后推,该报告要么添加零缓冲(如果是最后一个),1 分钟(如果以下报告没有等待),或当前报告长度的一半(如果等待以下报告)。

因此,如果我们颠倒顺序,我们只需要跟踪为每行添加多少延迟,将其添加到每个长度,然后取它们的累积总和。这就是从组的结束时间中减去多少时间(按此顺序是每个组第一行中的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

【讨论】:

  • 完全按照预期工作并且适应性很好。非常感谢!
猜你喜欢
  • 2015-07-06
  • 2017-04-28
  • 2023-02-09
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2022-01-04
相关资源
最近更新 更多