使用nlme和自定义函数构建随机截距模型时遇错误
nlmer随机截距模型语法与收敛问题解决
1. 随机截距模型语法说明
你使用的1 | ID在lme4包的nlmer函数中是合法的线性模型随机截距语法,但在你的非线性模型场景下存在理解偏差:
- 在非线性混合模型中,随机效应是针对你自定义的固定参数(如
y0、x0B等)而非通用截距。你前三个模型都是指定x0B/y100B这些参数的随机变异,而1 | ID会试图给模型隐含的全局截距加随机效应,这与你自定义logistic函数中的y0参数(实际承担截距作用)产生冲突,导致模型无法识别,进而收敛失败。 - 如果你想让logistic函数的截距(即
y0)具有随机效应,正确的语法应该是(y0 | ID),而非(1 | ID)。
2. 报错原因分析
Error in fitted.model[[i]] : subscript out of bounds是因为循环逻辑存在漏洞:
当随机截距模型拟合失败(tol超过10仍未收敛)时,fitted.model[[i]]未被赋值,后续执行args.start <- fixef(fitted.model[[i]])时,因索引位置为空触发报错。
3. 解决方案
3.1 修正随机效应定义
将你代码中的label <- c(label, "1")替换为:
label <- c(label, "y0")
这样循环生成的随机效应部分会变为(y0 | ID),对应自定义logistic函数的截距随机变异,符合你的模型需求。
3.2 修复循环错误处理
修改循环中的拟合逻辑,避免空索引报错:
fitted.model <- list() frm <- list() frm.fixed <- "ptlt_logit ~ logistic.model (visibility, y0, y100B, dy100.F, a, x0B, dx0.F, isF_num)" args.start <- c (y0 = y0, y100B = y100, dy100.F = 0, a = a, x0B = 0.30, dx0.F = 0) for (i in seq (1, length (label))) { frm[[i]] <- sprintf("%s ~ %s", frm.fixed, paste (sapply (strsplit (label [i], "[.]") [[1]], function (x) sprintf("(%s|ID)", x), USE.NAMES = FALSE), collapse = " + ")) cat (sprintf("Model: %s\n", frm[[i]])) tol <- .0001 current_model <- NULL while (TRUE) { if (tol > 10) { warning(sprintf("模型 %d 调整tol至%.4f后仍无法收敛", i, tol)) break } tryCatch ({ current_model <- nlmer (as.formula (frm[[i]]), data = looking_times, start = args.start, control = nlmerControl (tolPwrss = tol, maxIter = 1000)) break }, error = function (cond) { tol <<- 1.1 * tol cat (sprintf("Tolerance调整为: %.6f\n", tol)) }) } fitted.model[[i]] <- current_model # 仅当模型拟合成功时更新start参数 if (!is.null(current_model)) { args.start <- fixef(current_model) } else { cat(sprintf("模型 %d 未拟合成功,保留原有初始参数\n", i)) } }
3.3 优化收敛策略
如果仍存在收敛问题,可尝试:
- 更换优化器:添加
optimizer = "bobyqa"至nlmerControl中,该优化器更适合非线性模型 - 单独设置初始值:针对
y0随机效应模型,手动设置更合理的y0初始值,而非沿用前一个模型的固定效应结果 - 增大迭代次数:在
nlmerControl中设置maxIter = 2000、maxEval = 2000
内容的提问来源于stack exchange,提问作者olowman
相关产品推荐
相关产品推荐

