R语言处理时间向量时if条件出现NA值报错的原因咨询
首先,咱们先搞清楚你遇到的报错根源:error in if missing value where true/false needed 这个错误,本质是if条件判断里出现了NA值,而if语句只能接受TRUE/FALSE的逻辑值,NA会直接触发报错。
为什么会出现NA?
看你代码里的dayafterday循环:
dayafterday <- for (time_idx in 2:taille) { if (time_trunc[time_idx] != time_trunc[time_idx-1]) { row_to_keep[time_idx-1] <- TRUE if (time_idx > 2) { time_trunc[time_idx-1] <- time_trunc[time_idx-1] + 1 } # 这里修改了time_trunc的长度! time_trunc <- time_trunc[row_to_keep] duree<- length(time_trunc) epidemies_time[epid_idx]<-duree } }
问题出在循环过程中你修改了time_trunc的长度:当你执行time_trunc <- time_trunc[row_to_keep]后,time_trunc的长度会变短,但你的循环依然在按2:taille的范围执行。当time_idx超过新的time_trunc长度时,time_trunc[time_idx]就会返回NA,这时候time_trunc[time_idx] != time_trunc[time_idx-1]的结果就是NA,直接导致if报错。
另外还有一个潜在问题:在modele_epid循环中,如果infect[ind_idx] == 0,time[ind_idx+1]不会被重新赋值,会保持初始的0,这可能导致time_trunc里出现不符合预期的0值,但这不是本次报错的直接原因。
怎么修复这个问题?
方案1:修复原循环逻辑,避免在循环中修改向量长度
我们可以先完整标记所有需要保留的行,再一次性筛选,而不是在循环中动态修改time_trunc:
# 替换原来的dayafterday循环部分 time_trunc <- trunc(time) row_to_keep <- rep(FALSE, taille) row_to_keep[1] <- TRUE # 保留第一个元素 for (time_idx in 2:taille) { if (!is.na(time_trunc[time_idx]) && time_trunc[time_idx] != time_trunc[time_idx-1]) { row_to_keep[time_idx] <- TRUE # 标记当前不同的元素,而不是前一个 } } # 一次性筛选出不重复的整数对应的行 unique_time_trunc <- time_trunc[row_to_keep] duree <- length(unique_time_trunc) epidemies_time[epid_idx] <- duree
这里做了两个关键调整:
- 不在循环内修改
time_trunc的长度,先遍历完所有元素标记需要保留的行 - 增加
!is.na(time_trunc[time_idx])的判断,提前过滤NA值,避免条件里出现NA
方案2:用R的内置函数简化需求(更高效)
其实你的核心需求是对time向量取整后,获取不重复的整数,再计算这个唯一值集合的长度,完全不需要复杂的for循环,用R的内置函数一行就能搞定:
duree <- length(unique(trunc(time))) epidemies_time[epid_idx] <- duree
unique(trunc(time))会直接返回取整后的所有唯一值,length()就能得到你要的长度,代码更简洁,运行效率也更高。
完整修改后的代码片段
把方案2整合到你的完整代码里,替换原来的时间处理部分:
suscept<-rep(0,taille) infect<-rep(0,taille) remov<-rep(0,taille) time<-rep(0,taille) nvcas<-rep(0,taille) pop_susc <- 0.1 infect[1]<-5 suscept[1]<- pop_susc*taille - infect[1] remov[1]<- taille - infect[1]+suscept[1] beta<-0.0000524 alpha<-0.4 epidemies_nb <- 60 epidemies_time <-c(1:epidemies_nb) time_code <- for (epid_idx in 1:epidemies_nb) { modele_epid <- for(ind_idx in 1:(taille-1)) { if(infect[ind_idx]!=0) { s<--log(runif(1))/(beta*suscept[ind_idx]*infect[ind_idx]+alpha*infect[ind_idx]) time[ind_idx+1]<-time[ind_idx]+s rand<-runif(1) proba<-beta*suscept[ind_idx]*infect[ind_idx]/(beta*suscept[ind_idx]*infect[ind_idx]+alpha*infect[ind_idx]) if (rand<=proba) { suscept[ind_idx+1]<-suscept[ind_idx]-1 infect[ind_idx+1]<-infect[ind_idx]+1 remov[ind_idx+1]<-remov[ind_idx] nvcas[ind_idx+1]<-1 } else { suscept[ind_idx+1]<-suscept[ind_idx] infect[ind_idx+1]<-infect[ind_idx]-1 remov[ind_idx+1]<-remov[ind_idx]+1 nvcas[ind_idx+1]<-0 } } } # 用内置函数直接实现需求,避免循环报错 duree <- length(unique(trunc(time))) epidemies_time[epid_idx] <- duree # 注意:每次循环后最好重置time向量,避免下一次迭代使用上一次的结果 time <- rep(0, taille) } epidemies_time
另外加了一个小细节:每次迭代后重置time向量,避免下一次循环使用上一次的time值,保证每个epid_idx对应的time都是独立计算的。
内容的提问来源于stack exchange,提问作者Virgile Korsec

