R中的Uniroot解决方案

sha*_*any 8 r

我想找到以下函数的根:

       x=0.5
       f <- function(y) ((1-pbeta(1-exp(-0.002926543
        *( 107.2592+y)^1.082618 *exp(0.04097536*(107.2592+y))),shape1=0.2640229,shape2=0.1595841)) -
(1-pbeta(1-exp(-0.002926543*(x)^1.082618 *exp(0.04097536*(x))),shape1=0.2640229,shape2=0.1595841))^2)

sroot=uniroot(f, lower=0, upper=1000)$root
Run Code Online (Sandbox Code Playgroud)

uniroot错误(f,lower = 0,upper = 1000):端点处的f()值不是符号相反

我该如何解决错误?

李哲源*_*李哲源 21

uniroot() 并谨慎使用它

uniroot正在实施原油二分法.这种方法比(准)牛顿方法简单得多,但需要更强的假设来确保根的存在:f(lower) * f(upper) < 0.

这可能会非常痛苦,因为这种假设是一个充分条件,但不是必要条件.在实践中,如果f(lower) * f(upper) > 0仍然存在根,但由于这不是百分之百肯定,因此二分法不能冒风险.

考虑这个例子:

# a quadratic polynomial with root: -2 and 2
f <- function (x) x ^ 2 - 4
Run Code Online (Sandbox Code Playgroud)

显然,有根源[-5, 5].但

uniroot(f, lower = -5, upper = 5)
#Error in uniroot(f, lower = -5, upper = 5) : 
#  f() values at end points not of opposite sign
Run Code Online (Sandbox Code Playgroud)

实际上,二分法的使用需要观察/检查f,以便可以提出根所在的合理区间.在R中,我们可以使用curve():

curve(f, from = -5, to = 5); abline(h = 0, lty = 3)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

从图中,我们观察到根[-5, 0]或存在根[0, 5].所以这些工作正常:

uniroot(f, lower = -5, upper = 0)
uniroot(f, lower = 0, upper = 5)
Run Code Online (Sandbox Code Playgroud)

你的问题

现在让我们试试你的功能(为了便于阅读,我将它分成了几行;用这种方式检查正确性也很容易):

f <- function(y) {
  g <- function (u) 1 - exp(-0.002926543 * u^1.082618 * exp(0.04097536 * u))
  a <- 1 - pbeta(g(107.2592+y), 0.2640229, 0.1595841)
  b <- 1 - pbeta(g(x), 0.2640229, 0.1595841)
  a - b^2
  }

x <- 0.5
curve(f, from = 0, to = 1000)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这个函数怎么可能是一条水平线呢?它不能有根!

  1. 检查f以上内容,它是否真的做你想要的正确的事情?我怀疑有什么不对劲g; 你可能把括号放在错误的地方?
  2. 一旦你弄清楚了f,curve用来检查存在根的适当间隔.然后用uniroot.

  • uniroot 使用二分法是不正确的。它使用布伦特算法。在 uniroot 的 R 帮助文件中,它指出:“基于 http://www.netlib.org/c/brent.shar 中的‘zeroin.c’”。阅读 netlib.org/c 上的文档,我们发现以下信息:“文件 brent.shar for Brent 的单变量最小化器和零查找器。作者:Oleg Keselyov &lt;oleg@ponder.csci.unt.edu, oleg@unt.edu&gt; 23, 1991 参考 G.Forsythe、M.Malcolm、C.Moler,数学计算的计算机方法。 (2认同)

小智 5

尝试使用较小的间隔,但允许 uniroot() 延长间隔:

uniroot(f, lower=0, upper=1, extendInt = "yes")$root
[1] -102.9519
Run Code Online (Sandbox Code Playgroud)

  • 只是想告诉人们“extendInt”并不总是有效,所以不要相信它有魔力。以我的答案中的二次多项式示例为例,添加 `extendInt = "yes"` 会产生另一个“迭代达到限制”错误。因为无论您将间隔延长多少,符号都不会发生变化。 (4认同)