我有一个同时评估梯度和输出的函数。我想根据目标函数对其进行优化。如何将目标和梯度作为列表传递给optimx?下面的例子说明了这个问题:
假设我想找到多项式 的最小非负根x^4 - 3*x^2 + 2*x + 3。其梯度为4*x^3 - 6*x + 2. 我用的方法nlminb是optimx,如下图。
optimx(par = 100, method = "nlminb", fn = function(x) x^4 - 3*x^2 + 2*x + 3,
gr=function(x) 4*x^3 - 6*x + 2, lower = 0)
Run Code Online (Sandbox Code Playgroud)
这工作正常,我得到以下输出:
p1 value fevals gevals niter convcode kkt1 kkt2 xtimes
nlminb 1 3 27 24 23 0 TRUE TRUE 0
Run Code Online (Sandbox Code Playgroud)
现在假设我定义了函数fngr,它将目标和梯度作为列表返回:
fngr <- function(x) {
fn <- x^4 - 3*x^2 + 2*x + 3
gr <- 4*x^3 - 6*x + 2
return (list(fn = fn, gr = gr))
}
Run Code Online (Sandbox Code Playgroud)
我尝试optimx按如下方式调用:
do.call(optimx, c(list(par = 100, lower = 0, method="nlminb"), fngr))
Run Code Online (Sandbox Code Playgroud)
这返回了以下错误:
Error in optimx.check(par, optcfg$ufn, optcfg$ugr, optcfg$uhess, lower, :
Function provided is not returning a scalar number
Run Code Online (Sandbox Code Playgroud)
当我想将目标和梯度作为列表传递时,定义fngr和调用的正确方法是什么?optimx
谢谢。
定义一个无参数函数,它可以在调用时传递具有合适名称的两个函数......
> fngr <- function() {
+ fn <- function(x) {x^4 - 3*x^2 + 2*x + 3}
+ gr <- function(x) {4*x^3 - 6*x + 2}
+ return (list(fn = fn, gr = gr))
+ }
> do.call(optimx, c(list(par = 100, lower = 0, method="nlminb"), fngr() ))
notice the need to call it ------^^
p1 value fevals gevals niter convcode kkt1 kkt2 xtimes
nlminb 1 3 27 24 23 0 TRUE TRUE 0.002
Run Code Online (Sandbox Code Playgroud)
5年后再看这个,我完全能理解当时的困惑。@ user3294195 的做法更为典型。这不是 R 中传递函数对象的典型方式。
其工作方式: -fngr函数返回两个未计算表达式的列表,而不是返回函数本身。当遇到形成 fngr 函数参数的对列表中每个项目的 RHS 时,将使用最容易访问的值来计算表达式x。这可以通过更简单的测试更清楚地证明:
fnc <- function( x = x, y = x^2){print(x);print(y)}
fnc(x=2:11)
[1] 2 3 4 5 6 7 8 9 10 11
[1] 4 9 16 25 36 49 64 81 100 121
Run Code Online (Sandbox Code Playgroud)
在调用之前:中fnc(x=2:11)恰好有一个x向量globalenv()不是 == 2:11。因此,该函数没有“看到”该值,而是看到在调用中分配给形式的值,然后当解释器尝试评估形式中的x表达式时,该值可用。x^2