如何在data.table中标记同一ID下30天内存在前置记录的观测值
实现思路与修正代码
现有代码问题
你当前的非等值连接仅配置了readmit_date > index_date的判断条件,缺少30天的时间窗口限制,同时未将匹配结果回写到原数据框生成标记字段,因此无法得到预期输出。
可行实现方案
以下提供两种适用于大型数据框的data.table实现方案,性能均远优于fuzzyjoin:
方案1:非等值连接+回写标记(逻辑直观,易调整)
适合需要保留所有匹配明细的场景:
library(data.table) # 生成示例数据,固定随机种子方便复现 set.seed(123) df <- data.table( date = sample(seq(as.Date('1999/01/01'), as.Date('1999/06/01'), by="day"), 300, replace=T), id = sample(1:3, 300, replace=T), claim_id = 1:300 ) # 计算每条记录30天窗口的左边界 df[, date_low := date - 30] # 非等值连接匹配同id下、30天内的更早记录 match_res <- df[df, .(claim_id = x.claim_id, has_prev_30d = .N > 0), on = .(id, date < i.date, date >= i.date_low), by = .EACHI, nomatch = 0] # 将标记回写到原表 df[match_res, has_prev_30d := i.has_prev_30d, on = "claim_id"] # 无匹配记录标记为FALSE df[is.na(has_prev_30d), has_prev_30d := FALSE] # 清理临时字段 df[, date_low := NULL]
方案2:偏移匹配(性能最优,适合超大数据量)
利用排序后分组偏移取最近前置记录的特性,时间复杂度极低:
library(data.table) set.seed(123) df <- data.table( date = sample(seq(as.Date('1999/01/01'), as.Date('1999/06/01'), by="day"), 300, replace=T), id = sample(1:3, 300, replace=T), claim_id = 1:300 ) # 按id、日期排序,若同一天有多条记录可追加claim_id作为次排序键 setkey(df, id, date, claim_id) # 取同id下最近一条前置记录的日期 df[, prev_date := shift(date, n=1, type="lag"), by = id] # 生成标记:存在最近前置记录且间隔不超过30天 df[, has_prev_30d := !is.na(prev_date) & (date - prev_date <= 30)] # 可按需清理临时字段 df[, prev_date := NULL]
如果需求要求观测记录严格早于当前记录日期(同一天的不算),可以将标记逻辑修改为:
df[, has_prev_30d := !is.na(prev_date) & (date > prev_date) & (date - prev_date <= 30)]
内容的提问来源于stack exchange,提问作者EconMatt
相关产品推荐
相关产品推荐

