我查看了uniroot和optimize的描述,但它们有些不同,但书籍参考是一样的,我想知道是否有理由选择一个而不是另一个?
至于理由选择一个而不是另一个.在(可能)大多数情况下,一个人会更自然.正如@shadow所说,optimise是用于最小化(或最大化)并且uniroot用于寻找零点.
但在某些情况下,您可以使用其中任何一种来解决问题.这通常是因为你可以采取衍生工具,但可能还有另一种方法来重构你的问题.本答案的其余部分将讨论这些情况,您实际上可以选择并需要在两种情况之间进行选择.
举个简单的例子,我们可能想找到函数的最小值:
Func = function(x) {
(2*x-pi)^2 + exp(1)*x - 18
}
Run Code Online (Sandbox Code Playgroud)
一种方法是使用optimizeas:
OResult = optimize(Func, lower = 0, upper = 5)
OResult
$minimum
[1] 1.231011
$objective
[1] -14.19195
Run Code Online (Sandbox Code Playgroud)
另一种方法是通过采用导数来转换函数.由于最佳点是当导数为零时,我们需要像uniroot这样的寻根算法.所以功能变成:
DerivFunction = function(x) {
4*(2*x-pi) + exp(1)
}
Run Code Online (Sandbox Code Playgroud)
哪个优化了:
UResult = uniroot(DerivFunction , interval = c(0,5))
UResult
$root
[1] 1.231011
$f.root
[1] 4.440892e-16
$iter
[1] 2
$init.it
[1] NA
$estim.prec
[1] 6.103516e-05
Run Code Online (Sandbox Code Playgroud)
如果您在上述方法之间做出选择,那么您可能会optimize为了简单而选择.uniroot然而,有些情况可能会更快.
使用上面的例子,optimize函数调用函数7次,而uniroot只调用导数函数5次.(这可以通过将计数器放在上面的函数中找到).这是合乎逻辑的,优化不知道最小值有多低,而uniroot确实知道目标函数值为零.因此,uniroot通常会知道x轴的方向,而优化则需要更多地查看.
如果我们做基准测试,那么优化速度要快得多.所以一般来说(如果你正在考虑速度)使用优化,除非它是一个非常密集的函数,其中函数调用比优化算法正在做的更昂贵(当然在这些情况下,通常很难得到一种形式的要使用的问题uniroot).
library(microbenchmark)
microbenchmark(
optimize(Func, lower = 0, upper = 5),
uniroot(DerivFunction, interval = c(0,5))
)
Unit: microseconds
expr min lq mean median uq max neval
optimize(Func, lower = 0, upper = 5) 18.264 19.785 23.50664 20.7370 23.781 129.365 100
uniroot(DerivFunction, interval = c(0, 5)) 63.161 67.346 74.10322 69.8195 76.858 143.062 100
Run Code Online (Sandbox Code Playgroud)
优化函数可能找不到全局最优,而只是局部最优.同样如此uniroot,可以找到局部零但不存在其他零.uniroot不同于optimize然而由于同时设置优化找到最大或最小值,uniroot会发现,相交y轴的点.如果你uniroot是一个导数,那么这一点可能是最小值或最大值.
例如,如果我们有以下功能和衍生物:
TwoMinFunction = function(x){
((x)^4)/4 + x^3 - 3*x^2 - 8*x + 16
}
TwoZeroDerivFunction = function(x){
(x^3 + 3*x^2 ? 6*x ? 8)
}
Run Code Online (Sandbox Code Playgroud)
此功能如下图所示:

OResult = optimize(TwoMinFunction, lower = -6, upper = 4)
OResult
$minimum
[1] -4.000001
$objective
[1] 8.007817e-12
UResult = uniroot(TwoZeroDerivFunction , interval = c(-6,4))
UResult
$root
[1] -1
$f.root
[1] 0
$iter
[1] 1
$init.it
[1] NA
$estim.prec
[1] 5
Run Code Online (Sandbox Code Playgroud)
这里发生的是优化发现两个最小值之一.另一方面,uniroot功能发现了一个最大值(因为uniroot无法区分最小值和最大值).