【问题标题】:Adding self starting values to an nls regression in R将自起始值添加到 R 中的 nls 回归
【发布时间】:2020-05-02 19:44:20
【问题描述】:

我有现有代码用于将 sigmoid 曲线拟合到 R 中的数据。如何使用 selfstart(或其他方法)自动查找回归的起始值?

sigmoid = function(params, x) {
  params[1] / (1 + exp(-params[2] * (x - params[3])))
}

dataset = data.frame("x" = 1:53, "y" =c(0,0,0,0,0,0,0,0,0,0,0,0,0,0.1,0.18,0.18,0.18,0.33,0.33,0.33,0.33,0.41,0.41,0.41,0.41,0.41,0.41,0.5,0.5,0.5,0.5,0.68,0.58,0.58,0.68,0.83,0.83,0.83,0.74,0.74,0.74,0.83,0.83,0.9,0.9,0.9,1,1,1,1,1,1,1) )

x = dataset$x
y = dataset$y

# fitting code
fitmodel <- nls(y~a/(1 + exp(-b * (x-c))), start=list(a=1,b=.5,c=25))

# visualization code
# get the coefficients using the coef function
params=coef(fitmodel)

y2 <- sigmoid(params,x)
plot(y2,type="l")
points(y)

【问题讨论】:

  • 一个简单的双参数反指数方程,“y = a * exp(b/x)”似乎可以很好地拟合数据,参数 a = 2.2757248107168646E+00 和 b = -4.1867657807394536E+01 产生 RMSE = 0.0504 和 R 平方 = 0.980。

标签: r regression sigmoid


【解决方案1】:

这是非线性曲线拟合中的一个常见(且有趣)问题。

背景

如果我们仔细查看函数sigmoid,我们可以找到合理的起始值

我们首先注意到

因此,对于较大的 x 值,函数会接近 a。换句话说,作为a 的起始值,我们可以选择y 的值作为x 的最大 值。 在 R 语言中,这转换为 y[which.max(x)]。

现在我们有了a 的起始值,我们需要确定b 和c 的起始值。为此,我们可以利用几何级数

并通过仅保留前两个术语来扩展 f(x) = y

我们现在设置a = 1(a 的起始值),重新排列方程并取两边的对数

我们现在可以拟合log(1 - y) ~ x 形式的线性模型来获得斜率和偏移的估计值,这反过来又提供了b 和c 的起始值。

R 实现

让我们定义一个函数,它将值 x 和 y 作为参数并返回参数起始值的 list

start_val_sigmoid <- function(x, y) {
    fit <- lm(log(y[which.max(x)] - y + 1e-6) ~ x)
    list(
        a = y[which.max(x)],
        b = unname(-coef(fit)[2]),
        c = unname(-coef(fit)[1] / coef(fit)[2]))
}

根据您提供的x和y的数据,我们得到以下起始值

start_val_sigmoid(x, y)
#$a
#[1] 1
#
#$b
#[1] 0.2027444
#
#$c
#[1] 15.01613

由于start_val_sigmoid 返回list,我们可以将其输出直接用作nls 中的start 参数

nls(y ~ a / ( 1 + exp(-b * (x - c))), start = start_val_sigmoid(x, y))
#Nonlinear regression model
#  model: y ~ a/(1 + exp(-b * (x - c)))
#   data: parent.frame()
#      a       b       c
# 1.0395  0.1254 29.1725
# residual sum-of-squares: 0.2119
#
#Number of iterations to convergence: 9
#Achieved convergence tolerance: 9.373e-06

样本数据

dataset = data.frame("x" = 1:53, "y" =c(0,0,0,0,0,0,0,0,0,0,0,0,0,0.1,0.18,0.18,0.18,0.33,0.33,0.33,0.33,0.41,0.41,0.41,0.41,0.41,0.41,0.5,0.5,0.5,0.5,0.68,0.58,0.58,0.68,0.83,0.83,0.83,0.74,0.74,0.74,0.83,0.83,0.9,0.9,0.9,1,1,1,1,1,1,1) )

x = dataset$x
y = dataset$y

【讨论】:

  • 不客气@Andrew;请注意,我修复了start_val_sigmoid 中的错字/错误,其中线性模型通常应为log(y[which.max(x)] - y + 1e-6) ~ x;它不会改变任何东西,因为在这个例子中 y[which.max(x)] 等于 1,所以我之前给出的代码是特定于 x、y 示例数据的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-19
  • 2013-05-05
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
相关资源
最近更新 更多