使用R

时间:2019-02-02 17:48:15

标签: r algorithm iterator numerical-methods convergence

我正在执行迭代计算,以检查y在R中x上的变化。我的目标是估计x截距。现在,每个迭代的计算量都很大,因此实现该迭代所需的迭代次数越少越好。

这里是yx相对的图像 Actual Problem 我通过定义一个渐近函数来创建一个工作示例,该函数可以充分捕捉问题所在

y <- (-1/x)+0.05

在绘制时会产生

x <- 1:100
y <- (-1/x)+0.05
DT <- data.frame(cbind(x=x,y=y))
ggplot(DT, aes(x, y)) + geom_point() + geom_hline(yintercept=0, color="red")

Working Example

我已经开发了两个迭代算法来近似x截距。

解决方案1 ​​x最初很小,被步进1...n次。步骤的大小是预先定义的,从大开始(增加10倍)。在每个步骤之后,将计算y.i。如果abs(y.i) < y[i-1],则重复该大步骤,除非y.i更改符号,这表示该步骤超出了x截距。如果算法超调,则我们回溯并采取较小的步骤(增加2倍)。每次超调时,步长都会从10 *,2 *,1.1 *,1.05 *,1.01 *,1.005 *,1.001 *减小。

x.i <- x <- runif(1,0.0001,0.001)
y.i <- y <- (-1/x.i)+0.05
i <- 2
while(abs(y.i)>0.0001){
  x.i <- x[i-1]*10
  y.i <- (-1/x.i)+0.05
  if(abs(y.i)<abs(y[i-1]) & sign(y.i)==sign(y[i-1])){
    x <- c(x,x.i); y <- c(y,y.i)
  } else {
    x.i <- x[i-1]*2
    y.i <- (-1/x.i)+0.05
    if(abs(y.i)<abs(y[i-1]) & sign(y.i)==sign(y[i-1])){
      x <- c(x,x.i); y <- c(y,y.i)
    } else {
      x.i <- x[i-1]*1.1
      y.i <- (-1/x.i)+0.05
      if(abs(y.i)<abs(y[i-1]) & sign(y.i)==sign(y[i-1])){
        x <- c(x,x.i); y <- c(y,y.i)
      } else {
        x.i <- x[i-1]*1.05
        y.i <- (-1/x.i)+0.05
        if(abs(y.i)<abs(y[i-1]) & sign(y.i)==sign(y[i-1])){
          x <- c(x,x.i); y <- c(y,y.i)
        } else {
          x.i <- x[i-1]*1.01
          y.i <- (-1/x.i)+0.05
          if(abs(y.i)<abs(y[i-1]) & sign(y.i)==sign(y[i-1])){
            x <- c(x,x.i); y <- c(y,y.i)
          } else {
            x.i <- x[i-1]*1.005
            y.i <- (-1/x.i)+0.05
            if(abs(y.i)<abs(y[i-1]) & sign(y.i)==sign(y[i-1])){
              x <- c(x,x.i); y <- c(y,y.i)
            } else {
              x.i <- x[i-1]*1.001
              y.i <- (-1/x.i)+0.05
            }
          }
        }
      }
    }
  }
  i <- i+1
}

解决方案2 :此算法基于Newton-Raphson方法的思想,其中步骤基于y中的变化率。变化越大,采取的步骤越小。

x.i <- x <- runif(1,0.0001,0.001)
y.i <- y <- (-1/x.i)+0.05
i <- 2
d.i <- d <- NULL
while(abs(y.i)>0.0001){
  if(is.null(d.i)){
    x.i <- x[i-1]*10
    y.i <- (-1/x.i)+0.05
    d.i <- (y.i-y[i-1])/(x.i-x[i-1])
    x <- c(x,x.i); y <- c(y,y.i); d <- c(d,d.i)
  } else {
    x.i <- x.i-(y.i/d.i)
    y.i <- (-1/x.i)+0.05
    d.i <- (y.i-y[i-1])/(x.i-x[i-1])
    x <- c(x,x.i); y <- c(y,y.i); d <- c(d,d.i)
  }
  i <- i+1
}

比较

  1. 解决方案1所需的迭代次数始终少于解决方案2(1/2的迭代次数,如果不是1/3的话)。
  2. 解决方案2更优雅,不需要任意减小步长。
  3. 我可以设想几种解决方案1卡住的情况(例如,即使在最小的步骤中,循环也无法收敛到y.i的足够小的值上)

问题

  1. 在这种情况下,是否存在更好的(减少迭代次数)近似x截距的方法?
  2. 谁能指出我一些解决此类问题的文献(最好是可理解地写给像我这样的初学者)?
  3. 欢迎提供任何代表此类问题/算法的术语或关键词建议。
  4. 我提出的解决方案可以改进吗?
  5. 欢迎任何有关如何使标题/问题更广泛的社区或具有潜在解决方案的专家访问的建议。

1 个答案:

答案 0 :(得分:1)

根据@Lyngbakr和@LutzL的阅读建议和建议,被称为Brent's Method的寻根算法被证明是有效的,并且比我的Newton-Raphson的实现要快得多(解决方案2)。该算法由uniroot中的R实现。

f <- function(x){(-1/x)+0.05}
uniroot(f, interval=c(0,100), maxiter=100)