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

如何按日期间隔拆分分组并合并个体地点的连续时间区间?

合并个体在同一地点的连续时间区间

我正在处理日期相关数据,每行代表一个个体在某地点的一个时间区间,数据示例如下:

# 示例数据
library(tidyverse)
library(lubridate)

df <- tibble(
  ind = c(1,1,1,1,1,1,2,2,3,3,3,3),
  place = c(1,1,1,4,4,4,2,2,3,3,3,3),
  start_date = ymd(c("2011-01-04", "2011-01-05", "2011-01-10", "2010-12-30", "2010-12-31", "2011-01-01", "2018-02-17", "2018-02-19", "2018-02-08", "2018-02-13", "2018-02-16", "2018-03-27")),
  end_date = ymd(c("2011-01-05", "2011-01-06", "2011-01-11", "2010-12-31", "2011-01-01", "2011-01-03", "2018-02-19", "2018-02-23", "2018-02-13", "2018-02-16", "2018-02-20", "2018-03-29"))
)

可以看到,部分行的start_date与上一行的end_date相同,属于连续的时间区间;但有些行和上一行之间存在间隔,需要先将这些组拆分为多个子组,再合并同一子组内的时间区间。

我需要先生成分组标识(group列),得到中间结果:

# 中间结果
#      ind place start_date end_date   group
#    <int> <int> <date>     <date>     <int>
#  1     1     1 2011-01-04 2011-01-05   1
#  2     1     1 2011-01-05 2011-01-06   1
#  3     1     1 2011-01-10 2011-01-11   2
#  4     1     4 2010-12-30 2010-12-31   3
#  5     1     4 2010-12-31 2011-01-01   3
#  6     1     4 2011-01-01 2011-01-03   3
#  7     2     2 2018-02-17 2018-02-19   4
#  8     2     2 2018-02-19 2018-02-23   4
#  9     3     3 2018-02-08 2018-02-13   5
# 10     3     3 2018-02-13 2018-02-16   5
# 11     3     3 2018-02-16 2018-02-20   5
# 12     3     3 2018-03-27 2018-03-29   6

最终合并后得到:

# 最终结果
#      ind place start_date end_date  
#    <int> <int> <date>     <date>    
#  1     1     1 2011-01-04 2011-01-06
#  2     1     1 2011-01-10 2011-01-11
#  3     1     4 2010-12-30 2011-01-03
#  4     2     2 2018-02-17 2018-02-23
#  5     3     3 2018-02-08 2018-02-20
#  6     3     3 2018-03-27 2018-03-29

请问该如何实现?


解决方案(使用tidyverse)

可以通过分组后标记连续区间,再按新的分组合并时间:

步骤1:生成连续区间的分组标识

先按ind和place分组,然后判断当前行的start_date是否等于上一行的end_date,如果不等则标记为新组,最后累计求和生成唯一的group值:

df_with_group <- df %>%
  arrange(ind, place, start_date) %>%  # 确保数据按个体、地点、时间排序
  group_by(ind, place) %>%
  mutate(
    # 标记是否为新组:第一行或当前start_date不等于上一行end_date
    is_new_group = ifelse(row_number() == 1 | start_date != lag(end_date), 1, 0),
    # 组内累计求和生成组ID
    group = cumsum(is_new_group)
  ) %>%
  ungroup() %>%
  # 全局统一group编号(和示例中的全局group一致)
  mutate(group = cumsum(is_new_group))

步骤2:按新分组合并时间区间

按ind、place和group分组,取每组的最小start_date和最大end_date:

final_df <- df_with_group %>%
  group_by(ind, place, group) %>%
  summarise(
    start_date = min(start_date),
    end_date = max(end_date),
    .groups = "drop"
  ) %>%
  select(-group)  # 移除临时分组列

运行后就能得到你需要的最终结果。

说明

  • 必须先确保数据按ind、place、start_date排序,否则判断连续区间会出错;
  • is_new_group列用来标记每个新的连续区间的起始行,cumsum会把连续的行归为同一个组;
  • 若不需要全局唯一的group编号(仅在ind+place内唯一即可),可以去掉最后一行的mutate(group = cumsum(is_new_group))。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:44:52