R语言nls非线性拟合Matlab优化函数报singular gradient错误求助
R
stat_smooth() nls拟合梯度奇异问题解决方案 报错核心原因
- 初始值量级差过大:你设置的初始值
k1=0.006999、k2=849.6相差6个数量级,计算k2-k1时会出现数值精度损失,且exp(-k2*x)在x≥1时直接下溢为0,导致参数求导的梯度矩阵奇异 - 公式括号逻辑错误:你写的公式括号位置不符合双相指数增长模型的标准形式,模型逻辑和你Matlab中优化的目标函数不一致
修复方案
方案1:调整初始值+使用默认nls(无需额外安装包)
直接把k2的初始值下调到合理区间,修正公式括号即可运行,修改后代码如下:
library(tidyverse) # 导入数据集 df <- tibble( x = c(1,3,5,10,20,30,40,50,60,90,120,180,240,360,1440), y = c(0.0342,0.0502,0.07,0.123,0.154,0.203,0.257,0.287,0.345,0.442,0.569,0.726,0.824,0.868,0.89), SEM = c(0.00532,0.00639,0.0118,0.0269,0.0125,0.019,0.0255,0.0266,0.0347,0.0398,0.057,0.0406,0.015,0.00821,0.0246) ) df %>% ggplot(aes(x, y)) + geom_point()+ geom_errorbar(aes(ymin=y-SEM, ymax=y+SEM), width=25)+ geom_ribbon(aes(ymin = y-2.575*SEM, ymax = y+2.575*SEM), alpha = 0.1)+ geom_smooth(method="nls", # 修正括号逻辑,匹配标准双相指数累积模型 formula= y ~ 1 - (k2/(k2-k1)*exp(-k1*x) - k1/(k2-k1)*exp(-k2*x)), se=F, # 调整k2初始值到合理量级 method.args = list(start=list(k1=0.006999, k2=0.08)))
方案2:使用更稳定的LM算法(推荐,抗初始值扰动能力更强)
如果初始值波动大,建议安装minpack.lm包,用Levenberg-Marquardt算法替代默认的高斯牛顿算法,彻底避免奇异梯度问题:
# 首次运行先安装依赖包:install.packages("minpack.lm") library(minpack.lm) df %>% ggplot(aes(x, y)) + geom_point()+ geom_errorbar(aes(ymin=y-SEM, ymax=y+SEM), width=25)+ geom_ribbon(aes(ymin = y-2.575*SEM, ymax = y+2.575*SEM), alpha = 0.1)+ geom_smooth(method="nlsLM", formula= y ~ 1 - (k2/(k2-k1)*exp(-k1*x) - k1/(k2-k1)*exp(-k2*x)), se=F, method.args = list(start=list(k1=0.006999, k2=0.08)))
两种方案都可以正常拟合得到和Matlab优化结果一致的参数,拟合优度R²可达0.99以上。
内容的提问来源于stack exchange,提问作者David N.F.
相关产品推荐
相关产品推荐

