R语言for循环中动态生成mutate变量失败,求正确实现方案
动态生成R数据框变量的循环修正方案
问题背景
需要基于给定年龄值(20、30、40、50)动态生成对应的日期变量和暴露年数变量,手动编写mutate语句可得到正确结果,但循环代码仅输出最后一次迭代结果且目标列全为NA。
模拟数据框dfhave
structure(list(ID = 1:10, DOB = structure(c(-3704, -7119, -7375, -8217, -8504, -4886, -6899, -3027, -5546, -4512), class = "Date"), date1 = structure(c(7284, 9182, 4609, 6370, 5796, 9004, 8215, 5391, 8778, 6724), class = "Date"), date2 = structure(c(12429, 10203, 10764, 14487, 11367, 14495, 14845, 12190, 10216, 13144 ), class = "Date"), age.date1 = c(30.0835044490075, 44.6297056810404, 32.8104038329911, 39.937029431896, 39.1512662559891, 38.0287474332649, 41.3798767967146, 23.047227926078, 39.2169746748802, 30.7624914442163 ), age.date2 = c(44.1697467488022, 47.4250513347023, 49.6618754277892, 62.1601642710472, 54.403832991102, 53.0622861054073, 59.5318275154004, 41.6618754277892, 43.1540041067762, 48.3394934976044)), row.names = c(NA, 10L), class = "data.frame")
手动实现的正确代码(生成dfwant)
dfwant <- dfhave %>% mutate(age20day = DOB %m+% years(20), age30day = DOB %m+% years(30), age40day = DOB %m+% years(40), age50day = DOB %m+% years(50), expyrs.20 = case_when(age.date1<=20 & age.date2<=20 ~ as.duration(date1 %--% date2)/dyears(1), age.date1<=20 & age.date2>20 ~ as.duration(date1 %--% age20day)/dyears(1), age.date1>20 ~ 0), expyrs.30 = case_when(age.date1<=30 & age.date2<=30 ~ as.duration(date1 %--% date2)/dyears(1), age.date1<=30 & age.date2>30 ~ as.duration(date1 %--% age30day)/dyears(1), age.date1>30 ~ 0), expyrs.40 = case_when(age.date1<=40 & age.date2<=40 ~ as.duration(date1 %--% date2)/dyears(1), age.date1<=40 & age.date2>40 ~ as.duration(date1 %--% age40day)/dyears(1), age.date1>40 ~ 0), expyrs.50 = case_when(age.date1<=50 & age.date2<=50 ~ as.duration(date1 %--% date2)/dyears(1), age.date1<=50 & age.date2>50 ~ as.duration(date1 %--% age50day)/dyears(1), age.date1>50 ~ 0) )
错误的循环代码
ages <- c(20,30,40,50) for (i in ages) { ageday = paste0("age", i, "day") expyrs = paste0("expyrs.", i) df2 <- dfhave %>% mutate(!!ageday := DOB %m+% years(i), !!expyrs := case_when(age.date1<=ages[i] & age.date2<=ages[i] ~ as.duration(date1 %--% date2)/dyears(1), age.date1<=ages[i] & age.date2>ages[i] ~ as.duration(date1 %--% as.Date(!!sym(ageday)))/dyears(1), age.date1>ages[i] ~ 0 ) ) }
错误表现
运行后仅保留最后一次迭代的age50day和expyrs.50,且expyrs.50列全为NA。
错误原因分析
- 数据框覆盖问题:每次循环都从原始
dfhave重新生成df2,未基于上一次循环的结果累加变量,导致之前生成的变量被丢弃。 - 索引逻辑错误:
ages[i]用法有误,i是ages中的元素值(如20、30)而非索引位置,ages[i]实际取的是ages[20]这类不存在的位置,返回NA,导致case_when条件全不满足,结果为NA。 - 变量引用冗余:
case_when中无需用as.Date(!!sym(ageday)),直接使用刚生成的!!sym(ageday)即可,多余的类型转换可能引发问题。
修正后的循环代码
library(lubridate) library(dplyr) ages <- c(20, 30, 40, 50) # 初始化df2为原始数据框,确保变量逐步累加 df2 <- dfhave for (i in ages) { ageday <- paste0("age", i, "day") expyrs <- paste0("expyrs.", i) df2 <- df2 %>% mutate( !!ageday := DOB %m+% years(i), !!expyrs := case_when( age.date1 <= i & age.date2 <= i ~ as.duration(date1 %--% date2)/dyears(1), age.date1 <= i & age.date2 > i ~ as.duration(date1 %--% !!sym(ageday))/dyears(1), age.date1 > i ~ 0 ) ) }
验证结果
修正后的代码会逐步累加生成age20day到age50day以及expyrs.20到expyrs.50变量,与手动编写的dfwant结果完全一致。
内容的提问来源于stack exchange,提问作者TJ87
相关产品推荐
相关产品推荐

