我需要针对目标函数优化一组变量.我有函数的分析梯度,并希望在优化例程中使用它.目标和梯度有一些共同的计算,我想以最有效的方式定义函数.以下示例演示了此问题.
设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")
UPDATE
我发现包nloptr提供了输入目标函数及其梯度作为列表的工具.有没有办法以类似的方式定义其他优化器(optim,optimx,nlminb等)?
谢谢.
最佳答案 将公共函数的值存储在全局变量中,以使其可用于后续函数调用,如下所示:
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)首先,使用<< – 运算符,并不严格地说,分配给全局变量,而是分配给函数的父范围中的一个(即调用它的范围).通常,这通常是全球范围的.这在这里工作正常,是更好的方法.也可以使用assign()函数显式使用全局范围,但这里不需要它. 2)还应注意,通常不建议使用全局变量,因为如果在其他地方使用相同的变量名,它们可能会产生意外的副作用.为了避免任何可能的副作用,我建议使用一个变量名,例如global.f_common,它永远不会在别处使用,也没有副作用的危险.我只是在示例中使用名称y来与原始问题中的命名法一致.这是极少数情况下,在其功能之外给出可变范围可能是合理的,因为很难以另一种方式实现所需的行为.请确保谨慎使用,并使用上面建议的唯一名称(例如global.f_common).