R - 有效计算物镜和梯度的优化

时间:2016-03-25 17:13:14

标签: r optimization

我需要针对目标函数优化一组变量。我有函数的分析梯度,并希望在优化例程中使用它。目标和梯度有一些共同的计算,我想以最有效的方式定义函数。以下示例演示了此问题。

f_objf_gradf_common分别作为目标,渐变和通用计算的函数。优化位于向量x之上。以下代码查找多项式y^3 - 3*y^2 + 6*y + 1的根,其中yc(x[1], x[2])的函数。请注意,f_commonf_obj都会调用函数f_grad。在我的实际问题中,常见的计算时间要长得多,所以我正在寻找一种方法来定义f_objf_grad,以便最小化对f_common的调用次数。

f_common <- function(x) x[1]^3*x[2]^3 - x[2]

f_obj <- function(x) {
  y <- f_common(x)
  return ( (y^3 - 3*y^2 + 6*y + 1)^2 )
}

f_grad <- function(x) {
  y <- f_common(x)
  return ( 2 * (y^3 - 3*y^2 + 6*y + 1) * (3*y^2 - 6*y + 6)* c(3*x[1]^2*x[2]^3, 3*x[1]^3*x[2]^2 - 1) )
}

optim(par = c(100,100), fn = f_obj, gr = f_grad, method = "BFGS")

更新

我发现包nloptr提供了将目标函数及其渐变作为列表输入的功能。有没有办法以类似的方式定义其他优化器(optimoptimxnlminb等)?

感谢。

1 个答案:

答案 0 :(得分:1)

将公共函数的值存储在全局变量中,以使其可用于后续函数调用,如下所示:

f_common <- function(x) x[1]^3*x[2]^3 - x[2]

f_obj <- function(x) {
  y <<- f_common(x)   # <<- operator stores in parent scope
  return ( (y^3 - 3*y^2 + 6*y + 1)^2 )
}

f_grad <- function(x) {
  return ( 2 * (y^3 - 3*y^2 + 6*y + 1) * (3*y^2 - 6*y + 6)* c(3*x[1]^2*x[2]^3, 3*x[1]^3*x[2]^2 - 1) )
}

y<<-0

optim(par = c(100,100), fn = f_obj, gr = f_grad, method = "BFGS")

有关此解决方案的一些注意事项值得补充。

1)首先,使用&lt;&lt; - 运算符,并不严格地说是分配给全局变量,而是分配给函数的父范围中的一个(即调用它的范围)。通常,这通常是全球范围的。这在这里工作正常,是更好的方法。也可以使用assign()函数显式使用全局范围,但这里不需要它。

2)还应注意,通常不建议使用全局变量,因为如果在其他地方使用相同的变量名,它们可能会产生意外的副作用。为了避免任何可能的副作用,我建议使用一个变量名,例如global.f_common,它永远不会在别处使用,也没有副作用的危险。我只是在示例中使用名称y来与原始问题中的命名法一致。这是极少数情况下,在其功能之外给出可变范围可能是合理的,因为很难以另一种方式实现所需的行为。请确保谨慎使用,并使用上面建议的唯一名称(例如global.f_common)。