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

如何在R/dplyr中按日期序列间隔拆分分组(Gaps and Islands问题)

R语言处理季度连续的Gaps and Islands问题

问题场景

我要解决SQL中常提及的「缺口与岛屿(Gaps and Islands)」问题,不过是用R语言实现核心逻辑:按id分组,为季度连续的日期数据块添加专属分组标签(另有一个场景是年度连续的处理)。

模拟测试数据

使用tidyverse和zoo包构造的测试数据集:

library(tidyverse)
library(zoo)
df <- tibble('id' = c('A','A','A', 'B', 'B'), 
             'year' = as.yearqtr(c("01/01/2001","01/04/2001","01/10/2002", "01/09/2001","01/12/2001"),"%d/%m/%Y"), 
             'var1' = c(1,3,2,5,3), 
             'var2' = c(10,20,5,8,9))

对应的数据表展示:

id    year       var1  var2
  <chr> <yearqtr> <dbl> <dbl>
1 A     2001 Q1       1    10
2 A     2001 Q2       3    20
3 A     2002 Q4       2     5
4 B     2001 Q3       5     8
5 B     2001 Q4       3     9

需求说明

按id分组后,为连续的季度数据块分配唯一分组标签:

  • ID为A的前两行是连续季度(2001 Q1→2001 Q2),归为分组1;第三行2002 Q4和前一行间隔多个季度,归为分组2。
  • ID为B的两行是连续季度(2001 Q3→2001 Q4),归为分组1。

期望输出结果:

id    year       var1  var2 group
  <chr> <yearqtr> <dbl> <dbl> <dbl>
1 A     2001 Q1       1    10     1
2 A     2001 Q2       3    20     1
3 A     2002 Q4       2     5     2
4 B     2001 Q3       5     8     1
5 B     2001 Q4       3     9     1

最终解决方案

通过dplyr分组后,利用diff()计算季度间隔,结合cumsum()生成分组标签:

df %>% 
  group_by(id) %>% 
  mutate(group = cumsum(c(TRUE, 4 * diff(year) > 1)))

代码逻辑解释

  • group_by(id):按ID分组处理每个个体的日期序列
  • diff(year):计算相邻行yearqtr类型的日期差,yearqtr的数值格式为「年份+季度/4」(比如2001 Q1是2001.0,2001 Q2是2001.25)
  • 4 * diff(year):将差值转换为季度数,连续季度的差值为1,若间隔超过1个季度则结果大于1
  • c(TRUE, ...):为第一行添加初始值,保证分组从1开始计数
  • cumsum():累计求和,每次遇到间隔超过1的情况就生成新的分组编号

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 04:20:14