R语言构建Enddate变量失败:多层if_else嵌套无响应求解
R语言构建Enddate变量的解决方案
需求说明
- 从数据集的25组
DiaGP(1=重症、2=轻症、3=健康)与对应DateGP变量中构建Enddate变量:Enddate为研究Startdate之后首次确诊(DiaGP=1或2)的GP就诊日期;- 若从未确诊,则为最后一次GP就诊日期;
- 确诊日期早于
Startdate的忽略。
示例数据
| ID | Startdate | DiaGP1 | DateGP1 | DiaGP2 | DateGP2 | DiaGP3 | DateGP3 |
|---|---|---|---|---|---|---|---|
| 1 | 02-04-2006 | 3 | 05-03-2006 | 1 | 07-09-2007 | 1 | 29-01-2009 |
| 2 | 05-07-2008 | 1 | 11-04-2006 | 3 | 17-02-2010 | 1 | 15-01-2011 |
| 3 | 05-07-2008 | 3 | 05-03-2009 | 1 | 09-02-2010 | 3 | 14-12-2012 |
| 4 | 31-04-2007 | 3 | 16-11-2010 | NA | NA | NA | NA |
现有问题
尝试用多层if_else嵌套代码时,运行后出现+提示符无结果:
Data$enddate <- if_else(Data$DiaGP1 == 1 & Data$DateGP1 > Data$Startdate, Data$DateGP1, if_else(Data$DiaGP1 == 2 & Data$DateGP1 > Data$Startdate, Data$DateGP1, if_else(Data$DiaGP2 == 1 & Data$DateGP2 > Data$Startdate, Data$DateGP2, if_else(Data$DiaGP2 == 2 & Data$DateGP2 > Data$Startdate, Data$DateGP2, if_else(Data$DiaGP3 == 1 & Data$DateGP3 > Data$Startdate, Data$DateGP3, if_else(Data$DiaGP3 == 2 & Data$DateGP3 > Data$Startdate, Data$DateGP3, NA))))))
修复方案与优化解法
1. 修复现有嵌套代码
出现+提示符是因为代码括号不匹配——最后少一个闭合括号。补全后代码可运行,但多层嵌套可读性极差,后续维护困难,不建议使用。
2. 推荐:tidyverse长格式处理法(适配25组变量场景)
先将宽格式数据转为长格式,逻辑更清晰,扩展性更强:
library(tidyverse) library(lubridate) # 统一转换日期为Date类型 Data <- Data %>% mutate(across(c(Startdate, starts_with("DateGP")), dmy)) # 宽转长,拆分DiaGP和DateGP分组 Data_long <- Data %>% pivot_longer( cols = -c(ID, Startdate), names_to = c(".value", "GP_num"), names_pattern = "(DiaGP|DateGP)(\\d+)" ) %>% drop_na(DateGP) # 移除无就诊记录的行 # 计算每个ID的Enddate Data_final <- Data_long %>% group_by(ID) %>% summarise( Startdate = first(Startdate), # 筛选符合条件的确诊日期,取最早的;无则取最后一次就诊日期 Enddate = case_when( any(DiaGP %in% c(1,2) & DateGP > Startdate) ~ min(DateGP[DiaGP %in% c(1,2) & DateGP > Startdate]), TRUE ~ max(DateGP) ) ) %>% left_join(Data, by = c("ID", "Startdate")) %>% select(ID, Startdate, Enddate, everything()) # 保留原变量顺序 # 查看结果 Data_final
3. 基础R解法(无第三方包依赖)
如果不想用tidyverse,可通过循环处理每个ID:
# 转换日期格式为Date类型 Data$Startdate <- as.Date(Data$Startdate, format = "%d-%m-%Y") for (i in 1:25) { Data[, paste0("DateGP", i)] <- as.Date(Data[, paste0("DateGP", i)], format = "%d-%m-%Y") } # 定义计算单个ID Enddate的函数 get_enddate <- function(row) { start_date <- row["Startdate"] dates <- c() dia_status <- c() # 收集所有有效就诊记录 for (i in 1:25) { date_col <- paste0("DateGP", i) dia_col <- paste0("DiaGP", i) if (!is.na(row[date_col])) { dates <- c(dates, row[date_col]) dia_status <- c(dia_status, row[dia_col]) } } # 计算Enddate valid_diagnosis <- dates[dia_status %in% c(1,2) & dates > start_date] if (length(valid_diagnosis) > 0) { return(min(valid_diagnosis)) } else { return(max(dates)) } } # 应用函数到每一行 Data$Enddate <- apply(Data, 1, get_enddate)
结果验证
示例数据运行后得到的Enddate应为:
- ID1:2007-09-07(首次在Startdate后确诊)
- ID2:2011-01-15(首次有效确诊)
- ID3:2010-02-09(首次有效确诊)
- ID4:2010-11-16(无确诊,取最后就诊日期)
内容的提问来源于stack exchange,提问作者Willeke
相关产品推荐
相关产品推荐

