从Stata转R:为复发事件时长生成月度虚拟变量求助
从Stata转R:生成治疗月份哑变量的高效解决方案
需求说明
基于治疗阶段时长(dur_t1首次治疗月数、dur_t2第二次治疗月数)和阶段间隔时长(dur_nt1),为每个月份生成哑变量:1代表当月接受治疗,0代表无治疗,超出总时长或因NA中断的月份标记为NA。数据集规模为85000条观测,需保证处理效率。
解决方案
方法一:向量化列操作(高效适配大数据)
通过向量运算直接生成每个月份的哑变量,避免逐行遍历,处理85000条数据速度极快。
library(dplyr) # 确定需要生成的最大月份数(基于数据中各时长的最大值) max_month <- max(df$dur_t1, na.rm = TRUE) + max(df$dur_nt1, na.rm = TRUE) + max(df$dur_t2, na.rm = TRUE) # 循环生成每个month列 for (m in 1:max_month) { df[[paste0("month", m)]] <- case_when( # 首次治疗期:月份<=首次治疗时长 m <= df$dur_t1 ~ 1L, # 间隔期:存在间隔时长,且月份处于首次治疗结束后到间隔结束前 !is.na(df$dur_nt1) & m > df$dur_t1 & m <= df$dur_t1 + df$dur_nt1 ~ 0L, # 第二次治疗期:存在第二次治疗时长,且月份处于间隔结束后到第二次治疗结束前 !is.na(df$dur_t2) & m > df$dur_t1 + df$dur_nt1 & m <= df$dur_t1 + df$dur_nt1 + df$dur_t2 ~ 1L, # 其他情况(如间隔时长为NA导致后续无数据、超出总时长) TRUE ~ NA_integer_ ) }
方法二:长表转宽表(逻辑清晰易理解)
若更关注逻辑可读性,可先将每个id的月份序列展开为长表,标记状态后再转回宽表。tidyr函数经过优化,处理大数据也能保持较好性能。
library(dplyr) library(tidyr) df_processed <- df %>% rowwise(id) %>% mutate( # 计算每个id的总有效月份数 total_months = case_when( is.na(dur_nt1) ~ dur_t1, TRUE ~ dur_t1 + dur_nt1 + (dur_t2 %||% 0L) ), # 生成1到总月份的序列 month = list(1:total_months), # 标记每个月份的治疗状态 status = case_when( month <= dur_t1 ~ 1L, !is.na(dur_nt1) & month > dur_t1 & month <= dur_t1 + dur_nt1 ~ 0L, !is.na(dur_t2) & month > dur_t1 + dur_nt1 ~ 1L, TRUE ~ NA_integer_ ) ) %>% unnest_longer(c(month, status)) %>% # 转换为宽表格式 pivot_wider( id_cols = c(id, dur_t1, dur_nt1, dur_t2), names_from = month, names_prefix = "month", values_from = status ) %>% # 填充未覆盖的月份为NA mutate(across(starts_with("month"), ~replace_na(.x, NA_integer_)))
结果验证
两种方法均可生成符合预期的输出:
- 对于
id=2:dur_t1=3、dur_nt1=3、dur_t2=2,month1-3=1、month4-6=0、month7-8=1 - 对于
id=3:dur_nt1=NA,仅month1=1,其余月份为NA - 对于
id=1:dur_nt1=0,month1-6=1,后续月份为NA
内容的提问来源于stack exchange,提问作者idborquez
相关产品推荐
相关产品推荐

