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

在R语言中创建连续无间隔的时间周期

合并重叠/连续日期区间的解决方案

原始数据

首先定义输入的数据框:

library(tidyverse)
library(lubridate)

df <- tribble(
  ~person, ~start, ~end,
  '1', '2000-01-01', '2000-12-31',
  '1', '2001-01-01', '2002-07-31',
  '1', '2001-04-01', '2001-06-30',
  '1', '2001-08-01', '2001-12-31',
  '1', '2002-01-01', '2002-12-31',
  '2', '2000-01-01', '2000-11-30',
  '2', '2001-01-01', '2001-12-31') |> 
  mutate(start = lubridate::as_date(start),
         end   = lubridate::as_date(end))

需求目标

需要将每个person的重叠或连续无间隔的日期区间合并,得到如下输出:

person     start         end
1          2000-01-01    2002-12-31
2          2000-01-01    2001-11-30
2          2001-01-01    2001-12-31

原代码问题

你之前的代码直接取了每个person的最早开始和最晚结束,忽略了区间间的实际间隔(比如person 2的两个区间存在间隔,不能合并):

df |> 
  distinct() |>
  arrange(person, start, end) |> 
  mutate(
    gap = start - lag(end, default = min(start))
  ) |>
  group_by(person) |> 
  summarise(
    MIN_START = min(start),
    MAX_END   = max(end)
  )

正确解决方案

核心思路是:按person分组后,先排序日期,标记出所有独立的区间(当前行start晚于上一行end时,视为新区间),最后按标记的区间聚合最小start和最大end。

代码如下:

df |>
  distinct() |>
  arrange(person, start) |>
  group_by(person) |>
  # 生成区间组ID:当前start > 上一行end时,触发新组
  mutate(
    group_id = cumsum(start > lag(end, default = start[1] - days(1)))
  ) |>
  # 按person和区间组聚合,取每组的起止日期
  group_by(person, group_id) |>
  summarise(
    start = min(start),
    end = max(end),
    .groups = "drop"
  ) |>
  select(-group_id) # 移除临时组ID列

代码解释

  1. distinct():去重,避免重复区间干扰计算
  2. arrange(person, start):确保每个用户的日期按开始时间排序
  3. group_by(person):按用户单独处理日期区间
  4. cumsum(start > lag(end, default = start[1] - days(1))):通过累加判断生成区间ID,当当前行开始日期晚于上一行结束日期时,生成新组;默认值设为start[1]-days(1),保证第一行的组ID从1开始
  5. 再次分组聚合:按用户和区间ID取每组的最小开始日期和最大结束日期,最后移除临时的组ID列

运行这段代码即可得到预期的合并结果。


内容的提问来源于stack exchange,提问作者cowboy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 04:32:37