This package provides a unified framework for numerical optimizers in R, particularly for inputs and outputs.
Look at the popular R optimizers nlm()
and optim()
:
The function argument in nlm()
is called f
, in
optim()
it is fn
. The argument for the initial
values is called p
in nlm()
, and
par
in optim()
. The optimal parameters and the
optimal function values in the output of nlm()
are labeled
estimate
and minimum
, respectively, in
optim()
it is par
and value
. And
all is different again with pracma::nelder_mead()
.
This inconsistency is painful, especially if one wants to apply or
compare different optimizers.
Simply specify optimizers with set_optimizer()
and
execute them with optimizeR()
. The outputs are in a
standardized format.
For demonstration, say we want to minimize the Ackley function…
<- function(x) {
f_ackley stopifnot(is.numeric(x), length(x) == 2)
-20 * exp(-0.2 * sqrt(0.5 * (x[1]^2 + x[2]^2))) -
exp(0.5 * (cos(2 * pi * x[1]) + cos(2 * pi * x[2]))) + exp(1) + 20
}
… and compare three optimizers: nlm()
,
optim()
, and pracma::nelder_mead()
. The first
two are pre-specified…
library("optimizeR")
<- set_optimizer_nlm()
opt_nlm <- set_optimizer_optim() opt_optim
… and for the latter we can use the general constructor:
<- set_optimizer(
opt_nelder_mead opt = pracma::nelder_mead,
f = "fn",
p = "x0",
v = "fmin",
z = "xmin"
)
Now optimize (with initial parameter vector
p = c(-1,1)
):
<- list(opt_nlm, opt_optim, opt_nelder_mead)
opt <- lapply(opt, optimizeR, f = f_ackley, p = c(-1,1)) res
In the optimization results, v
and z
consistently denote the optimal function values and the optimal
parameters, while optimizer-specific outputs are preserved:
str(res)
#> List of 3
#> $ :List of 6
#> ..$ v : num 1.66e-06
#> ..$ z : num [1:2] -2.91e-07 5.08e-07
#> ..$ time : 'difftime' num 0.000495195388793945
#> .. ..- attr(*, "units")= chr "secs"
#> ..$ gradient : num [1:2] -0.00824 0.0144
#> ..$ code : int 2
#> ..$ iterations: int 33
#> $ :List of 6
#> ..$ v : num 3.57
#> ..$ z : num [1:2] -0.969 0.969
#> ..$ time : 'difftime' num 0.000224828720092773
#> .. ..- attr(*, "units")= chr "secs"
#> ..$ counts : Named int [1:2] 45 NA
#> .. ..- attr(*, "names")= chr [1:2] "function" "gradient"
#> ..$ convergence: int 0
#> ..$ message : NULL
#> $ :List of 6
#> ..$ v : num 0
#> ..$ z : num [1:2] 0 0
#> ..$ time : 'difftime' num 0.00132107734680176
#> .. ..- attr(*, "units")= chr "secs"
#> ..$ count : num 111
#> ..$ convergence: num 0
#> ..$ info :List of 2
#> .. ..$ solver : chr "Nelder-Mead"
#> .. ..$ restarts: num 0
Are you surprised that the optim()
result is different
from the others? The optimizer got stuck in a local minimum.
You can install the released version of {optimizeR} from CRAN with:
install.packages("optimizeR")
…and the development version from GitHub with:
# install.packages("devtools")
::install_github("loelschlaeger/optimizeR") devtools