R语言中nls()返回负标准差的原因探究
问题:nls()拟合正态曲线返回负标准差的原因及解决办法
我尝试在R语言中将数据建模为正态曲线,使用的方程形式为正态分布函数,以下是计算方程参数的代码:
filtered_sp14 <- c(549.778714, 259.835892, 992.874178, 75.267324, 53.014376, 128.281700, 10.471976, 58.904862, 88.357293, 102.756260, 201.585529, 29.452431, 1130.973355, 198.967535, 233.001455, 106.028752, 962.112750, 75.921822, 858.047494, 82.466807, 198.967535, 70.685835, 68.722339, 130.899694, 52.359878, 41.233404, 53.014376, 187.186562, 10.471976, 26.179939, 39.269908, 7.853982, 26.179939, 47.123890, 311.541271, 157.734131, 111.919238, 53.014376, 392.699082, 58.904862, 294.524311, 141.371669, 52.359878, 114.537232, 15.707963, 47.123890, 147.262156, 23.561945, 16.755161, 26.179939) filtered_osf <- c(22.885584, 24.905062, 8.816039, 6.877041, 8.782836, 5.853161, 4.088499, 11.792189, 17.533123, 7.043904, 9.189750, 11.216450, 22.821028, 27.308823, 10.652498, 18.590091, 5.973716, 4.387657, 5.091982, 5.973609, 5.012901, 22.547434, 11.238273, 19.235493, 6.206930, 3.276575, 3.791221, 3.460380, 5.404704, 12.278297, 4.604634, 10.614706, 5.425239, 3.450711, 2.214432, 2.573192, 5.037149, 40.996842, 26.001749, 6.615399, 8.947295, 3.335943, 48.198579, 10.110514, 9.286836, 7.668401, 17.463995, 14.653925, 10.574502, 8.403515) A_initial <- max(filtered_sp14) mean_initial <- mean(filtered_osf) sd_initial <- sd(filtered_osf) # Set up the non-linear least squares model nls_model <- nls(filtered_sp14 ~ A * exp(-((filtered_osf - mean)^2) / (2 * sd^2)), start = list(A=A_initial, mean=mean_initial, sd=sd_initial), control = nls.control(maxiter = 1000)) plot(filtered_osf, filtered_sp14, main="Non-linear Regression", xlab="X", ylab="Y", pch=19, col="blue")
运行后得到模型系数:
> coefficients(nls_model) A mean sd 284.14143 25.33275 -16.82272
其中均值符合预期,但标准差应为正数,请问为何nls()会返回负标准差?
解答
这是因为你用的正态曲线方程里,标准差s是以平方项s²的形式出现的——不管s是正还是负,s²的结果都是正数,对拟合的曲线形状没有任何影响。nls()做非线性最小二乘拟合时,只是找到能最小化残差平方和的参数值,它不会自动考虑标准差必须为正的统计意义,所以如果迭代过程中找到负的s能达到局部最优解,就会直接返回这个值。
解决办法
有几种方式可以强制标准差为正:
拟合方差参数而非标准差
修改模型,把sd²作为待拟合的参数(比如命名为var),最后再开平方得到标准差:nls_model <- nls(filtered_sp14 ~ A * exp(-((filtered_osf - mean)^2) / (2 * var)), start = list(A=A_initial, mean=mean_initial, var=sd_initial^2), control = nls.control(maxiter = 1000)) # 计算标准差 sd_estimate <- sqrt(coef(nls_model)["var"])在模型中使用绝对值约束
直接在方程里用abs(sd)代替sd,确保平方项始终为正:nls_model <- nls(filtered_sp14 ~ A * exp(-((filtered_osf - mean)^2) / (2 * abs(sd)^2)), start = list(A=A_initial, mean=mean_initial, sd=sd_initial), control = nls.control(maxiter = 1000))使用带参数约束的优化方法
可以用nlsLM()(来自minpack.lm包),它支持设置参数的上下限:library(minpack.lm) nls_model <- nlsLM(filtered_sp14 ~ A * exp(-((filtered_osf - mean)^2) / (2 * sd^2)), start = list(A=A_initial, mean=mean_initial, sd=sd_initial), lower = c(A=0, mean=-Inf, sd=0.0001), # 限制sd大于0 control = nls.control(maxiter = 1000))
内容的提问来源于stack exchange,提问作者fre1990
相关产品推荐
相关产品推荐

