在R/SQL中按Key分组处理行:基于duration与Cond的合并或日期更新
嘿,我来帮你搞定这个分组内的行合并和时间调整需求!先理清楚逻辑,再给你写可运行的R代码~
解决方案:分组内逐行合并与时间调整
首先,我们需要先把原始数据中的日期列转换成日期类型,方便后续的日期运算。然后针对每个key分组,逐行判断下一行的duration是否小于其对应的Cond,来决定是合并行还是调整下一行的起始日期。
步骤说明
- 数据预处理:将
Start和End列从字符型转换为日期类型,同时确保duration和Cond是数值型,避免运算错误。 - 分组处理逻辑:
- 对每个
key组内的行按id排序(保证行的顺序符合需求中的“第N行/第N+1行”关系)。 - 遍历组内每一行:
- 如果下一行的
duration < Cond:将当前行与下一行合并,更新当前行的End为下一行的End,直接跳过下一行。 - 如果下一行的
duration >= Cond:保留当前行,将下一行的Start设置为当前行End的次日,然后保留这两行。
- 如果下一行的
- 对每个
- 结果整合:将每个组处理后的结果合并成最终的数据框。
完整代码
# 加载所需工具包 library(dplyr) library(lubridate) # 你的原始数据 df <- as.data.frame(cbind(key = c(30, 30, 40, 40, 50, 50, 50, 60, 60, 60, 70, 70, 70, 80, 80, 80, 90, 90, 90, 90), id = c(1, 2, 1, 2, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4), value = c("A", "B", "C", "D", "A", "C", "D", "B", "C", "D", "A", "C", "D","A", "C", "D", "A", "B", "C", "D"), Class = c("A,B", "B", "C,D", "D", "A,C,D", "C,D", "D", "B,C,D", "C,D", "D", "A,C,D", "C,D", "D", "A,C,D", "C,D", "D", "A,B,C,D", "B,C,D", "C,D", "D"), duration = c(NA, 19, NA, 168, NA, 16, 28, NA, 49, 47, NA, 60, 17, NA, 2, 2, NA, 21, 23, 299), Cond = c(NA, 20, NA, 30, NA, 30, 20, NA, 20, 30, NA, 5, 28, NA, 20, 30, NA, 30, 20, 28), Start = c("2018-02-27", "2018-02-27", "2018-12-17", "2018-12-17", "2018-04-10", "2018-04-10", "2018-04-10", "2016-05-13", "2016-05-13", "2016-05-13", "2017-01-09", "2017-01-09", "2017-01-09", "2020-09-08", "2019-09-18", "2019-09-18", "2017-01-17", "2017-01-17", "2017-01-17", "2017-01-17"), End = c("2018-03-07", "2018-03-26", "2018-12-25", "2019-06-11", "2018-06-21", "2018-07-07", "2018-08-04", "2016-05-18", "2016-07-06", "2016-08-22", "2017-11-01", "2017-12-31", "2018-01-17", "2020-01-07", "2020-01-09", "2020-01-11", "2017-02-15", "2017-03-08", "2017-03-31", "2018-01-24") )) # 预处理:转换日期列和数值列类型 df <- df %>% mutate(Start = ymd(Start), End = ymd(End), duration = as.numeric(duration), Cond = as.numeric(Cond)) # 定义处理单个分组的函数 process_group <- function(group_df) { result <- list() i <- 1 n <- nrow(group_df) while(i <= n) { current_row <- group_df[i, ] if(i < n) { next_row <- group_df[i+1, ] # 跳过duration为NA的情况,只判断有数值的行 if(!is.na(next_row$duration) && next_row$duration < next_row$Cond) { # 合并行:更新当前行的End为下一行的End current_row$End <- next_row$End result[[length(result)+1]] <- current_row i <- i + 2 # 跳过下一行,避免重复处理 } else { # 保留当前行,调整下一行的Start为当前行End的次日 result[[length(result)+1]] <- current_row next_row$Start <- current_row$End + days(1) result[[length(result)+1]] <- next_row i <- i + 2 } } else { # 最后一行直接加入结果 result[[length(result)+1]] <- current_row i <- i + 1 } } bind_rows(result) } # 应用分组处理逻辑 processed_df <- df %>% arrange(key, id) %>% group_by(key) %>% group_modify(~ process_group(.x)) %>% ungroup() # 查看处理后的完整结果 print(processed_df, n = nrow(processed_df))
结果说明
- 对于
key=30的组:id=2的duration(19) < Cond(20),所以合并两行,最终只有一行,End更新为2018-03-26。 - 对于
key=40的组:id=2的duration(168) >= Cond(30),所以保留两行,id=2的Start调整为2018-12-26(原id=1的End+1天)。 - 多id的组(比如
key=90)会逐行依次判断处理,完全符合你的需求规则。
内容的提问来源于stack exchange,提问作者Bernice
相关产品推荐
相关产品推荐

