注意:我对 SQL 提出的类似问题 -如何使用窗口函数来确定何时在 Hive 或 Postgres 中执行不同的任务?
数据
我有一些数据显示了每人不同优先任务的开始日期和结束日期:
input_df <- data.frame(person = c(rep("Kate", 2), rep("Adam", 2), rep("Eve", 2), rep("Jason", 5)),
task_key = c(c("A","B"), c("A","B"), c("A","B"), c("A","B","C","D","E")),
start_day = c(c(1L,1L), c(1L,2L), c(2L,1L), c(1L,4L,3L,5L,4L)),
end_day = 5L)
person task_key start_day end_day 1 Kate A 1 5 2 Kate B 1 5 3 Adam A 1 5 4 Adam B 2 5 5 Eve A 2 5 6 Eve B 1 5 7 Jason A 1 5 8 Jason B 4 5 9 Jason C 3 5 10 Jason D 5 5 11 Jason E 4 5
注意:任务键是有序的,因此较高的字母具有较高的优先级。
问题
我需要确定每个人每天应该完成的任务,条件是:
- 字母较高的任务优先于字母较低的任务。
- 如果较高字母的任务与较低字母任务的任何部分重叠,则较低字母的任务将设置为 NA(表示此人永远不应从事该任务)。
简化
在实际数据中,原始表中的 end_day 始终为 5,即只有 start_day 变化,而 end_day 是恒定的。这意味着我想要的输出将具有与原始表相同的行数:)
输出
这是我需要的那种输出(Jason 更能代表我拥有的数据,它可以是涵盖 90 天的 100 多个任务):
output_df <- data.frame(person = c(rep("Kate", 2), rep("Adam", 2), rep("Eve", 2), rep("Jason", 5)),
task_key = c(c("A","B"), c("A","B"), c("A","B"), c("A","B","C","D","E")),
start_day = c(c(1L,1L), c(1L,2L), c(2L,1L), c(1L,4L,3L,5L,4L)),
end_day = 5L,
valid_from = c( c(NA,1L), c(1L,2L), c(NA,1L), c(1L,NA,3L,NA,4L) ),
valid_to = c( c(NA,5L), c(2L,5L), c(NA,5L), c(3L,NA,4L,NA,5L) ))
person task_key start_day end_day valid_from valid_to 1 Kate A 1 5 NA NA 2 Kate B 1 5 1 5 3 Adam A 1 5 1 2 4 Adam B 2 5 2 5 5 Eve A 2 5 NA NA 6 Eve B 1 5 1 5 7 Jason A 1 5 1 3 8 Jason B 4 5 NA NA 9 Jason C 3 5 3 4 10 Jason D 5 5 NA NA 11 Jason E 4 5 4 5
最初的想法
有效,但我想要一个使用 dbplyr 包函数的解决方案,并且通常比这更好:
tmp <- input_df %>% filter(person == "Jason")
num_rows <- nrow(tmp)
tmp$valid_from <- NA
tmp$valid_to <- NA
for(i in 1:num_rows) {
# Curent value
current_value <- tmp$start_day[i]
# Values to test against
vec <- lead(tmp$start, i)
# test
test <- current_value >= vec
# result
if(any(test, na.rm = TRUE) & i!=num_rows) {
tmp$valid_from[i] <- NA
tmp$valid_to[i] <- NA
} else if(i!=num_rows) {
tmp$valid_from[i] <- current_value
tmp$valid_to[i] <- min(vec, na.rm = TRUE)
} else {
tmp$valid_from[i] <- current_value
tmp$valid_to[i] <- max(tmp$end_day, na.rm = TRUE)
}
}
tmp
person task_number start_day end_day valid_from valid_to 1 Jason A 1 5 1 3 2 Jason B 4 5 NA NA 3 Jason C 3 5 3 4 4 Jason D 5 5 NA NA 5 Jason E 4 5 4 5
跟进问题
最终我需要在 SQL 中执行此操作,但这似乎太难了。我听说“dbply”包可以帮助我,因为如果我可以使用 dplyr 函数解决这个问题,那么它会以某种方式将其转换为有效的 SQL 查询?