R语言dplyr管道中重叠日期区间标记与重叠行拆分方法
问题原因
初始代码无法得到预期结果的核心原因是case_when按书写顺序逐行判断,只要命中第一个满足的条件就会直接返回对应值、终止后续判断,因此两个区间重叠的2019-05-01~2019-06-01时段只会被标记为Period_1,既无法同时标记两个所属区间,也不会自动生成重复行。
实现方案
使用「列表列存储所有匹配标记+行展开」的思路实现,需要搭配dplyr和tidyr两个包,代码如下:
library(dplyr) library(tidyr) # 构造测试数据集 dummy <- data.frame( dates = seq(as.Date("2019-01-01"), as.Date("2021-01-01"), by = "days"), people = runif(732, min = 100, max = 15000) ) # 标记逻辑 result <- dummy %>% rowwise() %>% mutate( # 逐行判断当前日期符合哪些区间,把匹配的标记存入列表 periods = list( c( ifelse(dates >= as.Date("2019-01-30") & dates <= as.Date("2019-06-01"), "Period_1", NA_character_), ifelse(dates >= as.Date("2019-05-01") & dates <= as.Date("2019-07-01"), "Period_2", NA_character_) ) %>% na.omit() %>% as.character() ) ) %>% ungroup() %>% # 无任何匹配的日期,标记为No_period mutate( periods = ifelse(lengths(periods) == 0, list("No_period"), periods) ) %>% # 把列表列拆分为普通列,列表有几个值就复制为几行 unnest_longer(periods)
逻辑说明
rowwise():开启逐行处理模式,保证每个日期单独执行区间判断- 列表列生成:分别判断日期是否符合每个区间的规则,将所有符合的标记存入当前行的列表,过滤掉不匹配产生的NA值;空列表代表当前日期不属于任何指定区间
- 空值替换:将无匹配的行的列表值替换为仅包含
"No_period"的列表,避免展开时丢失这部分数据 unnest_longer(periods):将列表列展开为普通字符列,自动实现「重叠区间复制为两行分别标记、非重叠/无匹配区间保留单行」的效果- 如果后续需要新增更多标记区间,直接在
c()内新增对应的ifelse判断语句即可,扩展性强。
结果验证
可以通过筛选典型日期验证结果正确性:
# 重叠区间日期2019-05-15,返回2行,periods分别为Period_1、Period_2 result %>% filter(dates == as.Date("2019-05-15")) # Period_1独有区间日期2019-02-01,返回1行,periods为Period_1 result %>% filter(dates == as.Date("2019-02-01")) # Period_2独有区间日期2019-06-15,返回1行,periods为Period_2 result %>% filter(dates == as.Date("2019-06-15")) # 无匹配区间日期2019-01-10,返回1行,periods为No_period result %>% filter(dates == as.Date("2019-01-10"))
内容的提问来源于stack exchange,提问作者anorlondo
相关产品推荐
相关产品推荐

