R语言:日期区间分类并补全enrollment/non-enrollment时段行
生成指定时间范围内的 Enrollment 状态区间解决方案
针对你需要处理的5万条id的enrollment数据集,我用R来给你一套可落地的实现方案,既能应对大规模数据(只要内存足够),又能精准生成指定时间范围内的状态区间和分类标签:
步骤1:加载依赖包
我们需要用到dplyr做数据分组和操作,lubridate处理日期类型:
library(dplyr) library(lubridate)
步骤2:准备数据
先把你的示例数据转换成标准的日期格式数据框,实际使用时替换成你的真实数据集即可:
# 示例数据(替换为你的真实数据集) df <- tibble( id = c(1,3,3,3,5,5), entry_date = c(NA, '1996-05-09', '2005-12-12', '2013-12-19', '2011-11-05','2012-12-10'), exit_date = c(NA, '2005-12-10', '2008-12-10', '2016-01-01', '2016-09-01', '2013-02-20') ) %>% # 将字符型日期转换为lubridate日期类型,NA值保留 mutate( entry_date = ymd(entry_date), exit_date = ymd(exit_date) )
步骤3:定义时间范围
按照你的需求设置目标时间范围,这里可以根据实际情况调整:
# 指定目标时间范围 start_range <- ymd('2001-06-01') end_range <- ymd('2015-01-01') # 若要匹配你示例中的2016结束日期,改为ymd('2016-01-01')即可
步骤4:生成状态区间和分类
核心逻辑是对每个id整理关键时间点,生成连续区间后判断每个区间的状态:
# 处理每个id,生成最终的状态区间结果 result <- df %>% group_by(id) %>% # 调整enrollment的起止日期,确保落在目标时间范围内 mutate( # 若entry_date早于起始范围,调整为起始范围;NA值保留 entry_adj = ifelse(is.na(entry_date), NA, pmax(entry_date, start_range)), # 若exit_date晚于结束范围,调整为结束范围;NA值保留 exit_adj = ifelse(is.na(exit_date), NA, pmin(exit_date, end_range)) ) %>% # 过滤掉完全在目标范围之外的无效enrollment记录 filter(!(entry_adj > end_range | exit_adj < start_range)) %>% # 收集当前id的所有关键时间点:范围起止、调整后的entry/exit日期,去重排序 summarise( time_points = c(start_range, entry_adj, exit_adj, end_range) %>% na.omit() %>% unique() %>% sort() ) %>% # 从排序后的时间点生成连续的日期区间 mutate( entry_date = lag(time_points), exit_date = time_points ) %>% # 移除第一个无效的区间(entry_date为NA的行) filter(!is.na(entry_date)) %>% # 为每个区间判断对应的分类标签 mutate( category = case_when( # 从未注册:该id没有有效enrollment记录,区间覆盖整个目标范围 n_distinct(time_points) == 2 & !id %in% df$id[!is.na(df$entry_date)] ~ 'Never enrolled', # 注册前:区间在该id第一次注册的起始日期之前 exit_date <= df$entry_adj[df$id == id][1] ~ 'Prior to enrollment', # 注册中:区间完全被某段enrollment时间段覆盖 map2_lgl(entry_date, exit_date, function(e, x) { any(df$entry_adj[df$id == id] <= e & df$exit_adj[df$id == id] >= x) }) ~ 'Enrolled', # 注册间隔:其他非注册状态的区间(两次注册之间、最后一次注册结束到范围结束) TRUE ~ 'Between enrollment' ) ) %>% # 确保日期格式正确 mutate( entry_date = ymd(entry_date), exit_date = ymd(exit_date) ) %>% ungroup() # 查看结果 print(result)
逻辑说明
- 日期调整:把超出目标范围的enrollment起止日期截断到范围边界,避免无效区间。
- 关键时间点收集:把目标范围的起止、所有调整后的注册起止日期放在一起,排序后生成连续的无重叠区间。
- 分类判断:通过
case_when依次判断每个区间的状态,确保每个标签的逻辑精准对应你的需求。
内容的提问来源于stack exchange,提问作者Jules.Sanchez
相关产品推荐
相关产品推荐

