nls()与nls2()拟合结果差异排查:我的配置哪里出错了?
问题:nls2暴力拟合无法复刻nls结果的原因及解决办法
我希望在nls()拟合有效的情况下,用nls2()的暴力拟合方法复刻其拟合结果,作为nls()失效时的备选方案。但目前nls2()的输出结果完全不符合预期,请问我的配置哪里出错了?是不是网格值设置的问题?
nls()拟合输出
Formula: y ~ C0 * exp(-lambda1 * x) + C1 * exp(-lambda2 * x) Parameters: Estimate Std. Error t value Pr(>|t|) C0.intercept_initial -0.108025 0.012703 -8.504 0.00105 ** lambda1.log_slope_initial 0.438553 0.072185 6.075 0.00371 ** C1.intercept_terminal 0.107742 0.012531 8.598 0.00101 ** lambda2.log_slope_terminal 0.057911 0.008045 7.199 0.00197 **
nls2()拟合输出
Formula: y ~ C0 * exp(-lambda1 * x) + C1 * exp(-lambda2 * x) Parameters: Estimate Std. Error t value Pr(>|t|) C0 1.000e+01 2.043e+14 0 1 C1 -1.000e+01 5.285e+11 0 1 lambda1 0.000e+00 2.043e+14 0 1 lambda2 0.000e+00 5.285e+11 0 1
相关代码
# Data dat <- data.frame(x = c(0,2,4,8,12,24,48,72), y = c(0.000,0.05,0.0671,0.068,0.05,0.0250,0.0103,0.0043)) # Get initial parameters from SSbiexp params <- getInitial(y ~ SSbiexp(x, intercept_initial, log_slope_initial, intercept_terminal, log_slope_terminal), data = dat) # Fit nls model nls_mod_bi <- nls(y ~ C0*exp(-lambda1*x) + C1*exp(-lambda2*x), start = list(C0 = params[1], lambda1 = exp(params[2]), C1 = params[3], lambda2 = exp(params[4])), data = dat) summary(nls_mod_bi) xNew <- seq(0, 240, length.out = 100) # new grid of times yNew <- predict(nls_mod_bi, list(x = xNew)) # predict activity dfNew <- data.frame(x = xNew, y = yNew) dfNew <- dfNew |> slice(-1) # remove first row which contains -ve prediction for time 0 ggplot(dfNew, aes(x = x, y = y)) + geom_line() + geom_point(data = dat, aes(x = x, y = y), size = 3) + xlab("x") + ylab("y") + theme_bw(base_size = 20) # Now fit nls2 model by brute-force fo <- y ~ C0*exp(-lambda1*x) + C1*exp(-lambda2*x) grd <- data.frame(C0 = c(-10, 10), C1 = c(-10, 10), lambda1 = c(0, 1), lambda2 = c(0, 1)) nls_mod_bi2 <- nls2(fo, data = dat, start = grd, algorithm = "brute-force") summary(nls_mod_bi2)
问题原因与解决办法
你的问题核心确实是网格设置的问题,具体有两点:
- 网格采样点过少:你设置的
grd仅提供了每个参数的上下限,nls2的brute-force算法只会生成4个顶点的组合(每个参数取上下限),而真实最优参数不在这些顶点中,自然无法找到正确解。 - 网格范围与真实参数空间不匹配:C0、C1的最优值在-0.2到0.2之间,但你设置的范围是-10到10,过宽的范围导致搜索顶点完全偏离真实参数区间。
修正方案1:基于nls结果缩小网格并增加采样点
利用已知的nls最优参数,将网格范围缩小到参数附近,并生成足够多的采样点:
# 提取nls的最优参数 nls_params <- coef(nls_mod_bi) # 生成每个参数在最优值±50%范围内的10个采样点组合 grd <- expand.grid( C0 = seq(nls_params["C0"]*0.5, nls_params["C0"]*1.5, length.out = 10), C1 = seq(nls_params["C1"]*0.5, nls_params["C1"]*1.5, length.out = 10), lambda1 = seq(nls_params["lambda1"]*0.5, nls_params["lambda1"]*1.5, length.out = 10), lambda2 = seq(nls_params["lambda2"]*0.5, nls_params["lambda2"]*1.5, length.out = 10) ) # 重新拟合nls2 nls_mod_bi2 <- nls2(fo, data = dat, start = grd, algorithm = "brute-force") summary(nls_mod_bi2)
修正方案2:nls失效时的分阶段搜索
如果nls无法拟合(无参考参数),可以先设置合理的初始宽网格找到近似解,再缩小范围二次搜索:
# 第一阶段:初始宽网格(基于数据特征设置) grd1 <- expand.grid( C0 = seq(-0.5, 0.5, length.out = 5), C1 = seq(-0.5, 0.5, length.out = 5), lambda1 = seq(0.1, 0.8, length.out = 5), lambda2 = seq(0.01, 0.1, length.out = 5) ) nls_mod_bi2_stage1 <- nls2(fo, data = dat, start = grd1, algorithm = "brute-force") # 第二阶段:基于第一阶段结果缩小网格 stage1_params <- coef(nls_mod_bi2_stage1) grd2 <- expand.grid( C0 = seq(stage1_params["C0"]*0.8, stage1_params["C0"]*1.2, length.out = 10), C1 = seq(stage1_params["C1"]*0.8, stage1_params["C1"]*1.2, length.out = 10), lambda1 = seq(stage1_params["lambda1"]*0.8, stage1_params["lambda1"]*1.2, length.out = 10), lambda2 = seq(stage1_params["lambda2"]*0.8, stage1_params["lambda2"]*1.2, length.out = 10) ) nls_mod_bi2_stage2 <- nls2(fo, data = dat, start = grd2, algorithm = "brute-force") summary(nls_mod_bi2_stage2)
修正后,nls2的参数估计会与nls结果基本一致,拟合效果匹配预期。
内容的提问来源于stack exchange,提问作者LucaS
相关产品推荐
相关产品推荐

