R 中具有多个变量的 nlm

nlm with multiple variables in R

我正在尝试使用 nlm() 来最小化函数中的 SSE。我在使用它们的语法和获取 nlm() 来提供两个变量的估计时遇到了问题。最终 t_1t_2t_3 将是从 data.frame 中提取的值,但我只是给它们分配了数字,直到我可以让 nlm() 工作。我尝试了这些线程的解决方案 and there,但没有成功:

t_1 <- 1.91
t_2 <- 3.23
t_3 <- 4.20

fun <- function(s,y){
  (10 - s*(t_1-y + y*exp(-t_1/y)))^2+
    (20 - s*(t_2-y + y*exp(-t_2/y)))^2+
    (30 - s*(t_3-y + y*exp(-t_3/y)))^2
}

## Testing the function
fun(9.57,1.13)
[1] 0.9342627

我已经为我的 nlm 语法尝试了多种方法。对于 2 个变量,我相信我必须为 p 插入一个数组,但是当我尝试它时它没有用。 None 以下解决方案有效:

# Attempt 1
p = array(c( 1,0), dim=c(2,1) ) 
ans <- nlm(fun, p)

# Attempt 2
ans <- nlm(fun, c( 0.1, 0.1))

# The first two return a "Error in f(x, ...) : argument "y" is missing, with no default"
# Attempt 3 returns a "invalid function value in 'nlm' optimizer" error

ans <- nlm(fun, c( 0.1, 0.1), y = c(1,1))

我确定我的代码中有几个错误,但我不确定在哪里。这个任务比我以前尝试过的要复杂,因为我对 R 还比较陌生。

如果您仔细观察 nlm 函数。它只要求一个参数。一种解决方案是:

fun <- function(x){
  s <- x[1]
  y <- x[2]
  (10 - s*(t_1-y + y*exp(-t_1/y)))^2+
    (20 - s*(t_2-y + y*exp(-t_2/y)))^2+
    (30 - s*(t_3-y + y*exp(-t_3/y)))^2
}

p <- array(c(0.4, 0.4), dim = c(2, 1))
# p <- c(0.4, 0.4)
ans <- nlm(f = fun, p = p)

vectorarray 都有效,但是您不能像您那样给出两个参数。

编辑

在数值优化中,初始点非常重要。我建议你使用 optim 函数,它对初始点的错误指定不太敏感。

一个想法是这样做,你制作一个由许多初始点组成的网格,然后 select 给你最好的结果:

initialisation <- expand.grid(seq(1, 3, 0.5),
                              seq(1, 3, 0.5))
res <- data.frame(optim = rep(0, nrow(initialisation)),
                  nlm = rep(0, nrow(initialisation)))

for(i in 1:nrow(initialisation)){
  res[i, 1] <- optim(as.numeric(initialisation[i, ]), fun)$value
  res[i, 2] <- try(nlm(f = fun, p = as.numeric(initialisation[i, ]))$minimum, silent = T)
}
res

我坚持认为上面的例子 optim 函数确实更稳定。如果你没有其他限制,我建议你使用它。

由于 ?nlm,您可以检查函数参数。

希望对您有所帮助。

编辑 2

fun <- function(x){
  s <- x[1]
  y <- x[2]
  (10 - s*(t_1-y + y*exp (-t_1/y)))^2+
    (20 - s*(t_2-y + y*exp(-t_2/y)))^2+
    (30 - s*(t_3-y + y*exp(-t_3/y)))^2
}

我选择这个初始点,因为它看起来更接近最佳点。

p <- c(10, 1)

ans <- nlm(f = fun, p = p)

您可以像这样获取两个参数: 小号是:

s <- ans$estimate[1]

y 是:

y <- ans$estimate[2]

您还有最佳值:

ans$minimum :
0.9337047
fun(c(s, y)) :
0.9337047

我的第二个 post,编辑只是为了说明使用 nlm 函数进行优化有点棘手,因为您需要仔细选择初始值。

optim 也是 R 的优化函数,在我给出的带有许多初始化点的示例中更稳定。

expand.grid 函数对于获得这样的网格很有用:

initialisation <- expand.grid(s = seq(2, 3, 0.5),
                                y = seq(2, 3, 0.5))

initialisation :

   s   y
1 2.0 2.0
2 2.5 2.0
3 3.0 2.0
4 2.0 2.5
5 2.5 2.5
6 3.0 2.5
7 2.0 3.0
8 2.5 3.0
9 3.0 3.0

res data.frame 给出不同初始值的最小值。 您会看到第一个初始值给 nlm 没有好的结果,但 optim.

的结果相对稳定
res <- data.frame(optim = rep(0, nrow(initialisation)),
                  nlm = rep(0, nrow(initialisation)))

for(i in 1:nrow(initialisation)){
  res[i, 1] <- optim(as.numeric(initialisation[i, ]), fun)$value
  res[i, 2] <- if(is.numeric(try(nlm(f = fun, p = as.numeric(initialisation[i, ]))$minimum, silent = T)) == T){
    round(nlm(f = fun, p = as.numeric(initialisation[i, ]))$minimum, 8)
  }else{
    NA
  }
}

try 函数只是为了避免循环中断。 if是把NA放在正确的位置。

res :
optim         nlm
1 0.9337094        <NA>
2 0.9337058  0.93370468
3 0.9337054        <NA>
4 0.9337101  0.93370468
5 0.9337125 61.18166446
6 0.9337057  0.93370468
7 0.9337120  0.93370468
8 0.9337080  0.93370468
9 0.9337114  0.93370468

当有 NA 值时,这意味着 nlm 由于初始化而无法正常工作。我建议你选择optim,如果你不需要非常精确的优化,因为它的稳定性。

关于 optimnlm 的广泛讨论,你可以看看 their。在您的特定情况下, optim 似乎是更好的选择。我不知道我们是否可以概括一下。