我需要针对目标函数优化一组变量。我有函数的分析梯度,并希望在优化例程中使用它。目标和梯度有一些共同的计算,我想以最有效的方式定义函数。以下示例演示了此问题。
让f_obj
,f_grad
和f_common
分别作为目标,渐变和通用计算的函数。优化位于向量x
之上。以下代码查找多项式y^3 - 3*y^2 + 6*y + 1
的根,其中y
是c(x[1], x[2])
的函数。请注意,f_common
和f_obj
都会调用函数f_grad
。在我的实际问题中,常见的计算时间要长得多,所以我正在寻找一种方法来定义f_obj
和f_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
提供了将目标函数及其渐变作为列表输入的功能。有没有办法以类似的方式定义其他优化器(optim
,optimx
,nlminb
等)?
感谢。
答案 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)。