如何在R的dplyr中为连续两年的数据创建分组ID?
为连续年份区间创建分组ID的dplyr解决方案
首先,你的示例数据集可以用以下代码复现:
library(tibble) df <- tribble( ~cell, ~year, ~month, ~day_of_month, ~day_of_year, ~preliq_q, ~tsup_h_q, ~tinf_h_q, ~t_q, 4, 2002, 2, 26, 57, 5.7, 12.1, 8.6, 10.2, 4, 2002, 2, 27, 58, 5.1, 9.3, 5.3, 6.7, 4, 2002, 2, 28, 59, 6.7, 8.7, 4.8, 6.2, 4, 2003, 2, 26, 57, 0, 13.2, 3.7, 7.9, 4, 2003, 2, 27, 58, 0, 16.4, 7.5, 10.7, 4, 2003, 2, 28, 59, 5.6, 10, 7.2, 8.6, 4, 2004, 2, 26, 57, 0.2, 2.8, 1, 1.5, 4, 2004, 2, 27, 58, 1.2, 2.8, 0.5, 1.8, 4, 2004, 2, 28, 59, 3.2, 3.5, 2.3, 2.9, 4, 2004, 2, 29, 60, 0.2, 3.7, 0.2, 2, 4, 2005, 2, 26, 57, 0.8, 4.3, 0.6, 2.1, 4, 2005, 2, 27, 58, 0, 0.5, -0.5, -0.2, 4, 2005, 2, 28, 59, 0, 0.2, -4.7, -2.1 )
方案1:生成重叠的连续两年区间分组ID(如2002-2003、2003-2004)
如果需要每个年份的数据同时属于当前年与下一年的区间、以及当前年与上一年的区间(存在的话),可以先构造所有连续年份区间,再通过连接匹配到每个数据行:
library(dplyr) # 第一步:生成所有连续年份区间及对应的分组ID year_intervals <- df %>% distinct(year) %>% arrange(year) %>% # 获取每个年份的下一个连续年份 mutate(next_year = lead(year)) %>% # 过滤掉没有下一年的最后一个年份 filter(!is.na(next_year)) %>% # 创建区间名称和分组ID mutate( year_interval = paste(year, next_year, sep = "-"), group_id = row_number() ) # 第二步:将原数据与区间连接,匹配每个数据行所属的区间 df_grouped <- df %>% left_join( year_intervals, # 匹配条件:数据行的年份属于区间的起始年或结束年 by = join_by(year >= year, year <= next_year) ) %>% # 整理列名 rename(data_year = year.x) %>% select(cell, data_year, year_interval, group_id, everything(), -year.y, -next_year)
运行后,2003年的数据会同时出现在2002-2003(group_id=1)和2003-2004(group_id=2)两个分组中,符合“连续年份区间”的需求。
方案2:用rleid生成非重叠的连续年份分组ID
如果你的需求是将连续的年份划分为非重叠的块(比如2002-2003为一组,2004-2005为另一组),可以结合rleid和年份分组逻辑实现:
library(dplyr) library(data.table) df_grouped <- df %>% group_by(cell) %>% mutate( # 计算每个年份所属的非重叠两年块的起始年 block_start = min(year) + 2 * floor((year - min(year)) / 2), # 用rleid对块起始年生成分组ID group_id = rleid(block_start), # 生成区间名称 year_interval = paste(block_start, block_start + 1, sep = "-") ) %>% ungroup()
这里rleid会为每个唯一的block_start生成连续的ID,实现非重叠年份块的分组。
方案3:纯dplyr实现(不依赖data.table)
如果不想使用data.table的rleid,可以用dplyr::dense_rank替代:
library(dplyr) df_grouped <- df %>% group_by(cell) %>% mutate( block_start = min(year) + 2 * floor((year - min(year)) / 2), year_interval = paste(block_start, block_start + 1, sep = "-"), group_id = dense_rank(block_start) ) %>% ungroup()
这个方案和方案2效果一致,只是用dense_rank替代了rleid。
内容的提问来源于stack exchange,提问作者Renan le roux
相关产品推荐
相关产品推荐

