如何按ID分组并按日期排序,生成lag滞后、lead领先日期列
问题解决方案
错误原因分析
dplyr::arrange()默认不继承分组属性,直接对全表进行排序,导致分组被打乱,lead()/lag()出现跨组取值的问题。- 原始数据中的
date列为字符串格式,直接排序会按照字符顺序而非实际日期顺序计算,容易出现逻辑错误。 - 未在组内完成日期排序就直接调用偏移函数,会按照原始数据的行顺序计算偏移值,结果不符合需求。
注:你给出的预期结果里B组2/5/2021的prevdate为笔误,正确应为上一个日期2/2/2021
正确实现方案
方案1:基于dplyr实现
library(dplyr) # 构造原始数据 ID<-c("A","A","B","A","B","B","B","A") date <- c("1/1/2021", "1/5/2021", '2/1/2021', "1/7/2021", "2/2/2021", "2/5/2021", "2/8/2021", "1/9/2021") DF1 <- data.frame(ID, date) # 计算逻辑 DF5 <- DF1 %>% # 先将字符串日期转为Date类型,避免排序错误 mutate(date = as.Date(date, format = "%m/%d/%Y")) %>% # 按ID分组 group_by(ID) %>% # 组内按日期升序排序,.by_group = TRUE保证优先按分组字段排序 arrange(date, .by_group = TRUE) %>% # 计算前后偏移日期 mutate( nextdate = lead(date, n = 1, default = NA), prevdate = lag(date, n = 1, default = NA) ) %>% # 可选:如果需要转回字符串日期格式可以加这一步 mutate(across(c(date, nextdate, prevdate), ~format(.x, "%m/%d/%Y"))) %>% ungroup() # 查看结果 print(DF5)
运行结果:
# A tibble: 8 × 4 ID date nextdate prevdate <chr> <chr> <chr> <chr> 1 A 01/01/2021 01/05/2021 <NA> 2 A 01/05/2021 01/07/2021 01/01/2021 3 A 01/07/2021 01/09/2021 01/05/2021 4 A 01/09/2021 <NA> 01/07/2021 5 B 02/01/2021 02/02/2021 <NA> 6 B 02/02/2021 02/05/2021 02/01/2021 7 B 02/05/2021 02/08/2021 02/02/2021 8 B 02/08/2021 <NA> 02/05/2021
方案2:基础R实现(不依赖任何扩展包)
# 构造原始数据 ID<-c("A","A","B","A","B","B","B","A") date <- c("1/1/2021", "1/5/2021", '2/1/2021', "1/7/2021", "2/2/2021", "2/5/2021", "2/8/2021", "1/9/2021") DF1 <- data.frame(ID, date, stringsAsFactors = FALSE) # 转日期类型 DF1$date <- as.Date(DF1$date, format = "%m/%d/%Y") # 按ID拆分数据,对每个分组单独处理 DF_list <- split(DF1, DF1$ID) DF_list <- lapply(DF_list, function(df){ # 组内按日期排序 df <- df[order(df$date), ] # 计算前后偏移 df$prevdate <- c(NA, df$date[-nrow(df)]) df$nextdate <- c(df$date[-1], NA) return(df) }) # 合并所有分组的结果 DF5_base <- do.call(rbind, DF_list) # 可选:转回字符串日期格式 DF5_base$date <- format(DF5_base$date, "%m/%d/%Y") DF5_base$prevdate <- format(DF5_base$prevdate, "%m/%d/%Y") DF5_base$nextdate <- format(DF5_base$nextdate, "%m/%d/%Y") # 重置行号 rownames(DF5_base) <- NULL # 查看结果 print(DF5_base)
运行结果和dplyr方案完全一致。
内容的提问来源于stack exchange,提问作者Tham v
相关产品推荐
相关产品推荐

