You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 21:57:03