【问题标题】:How to avoid coding first iteration outside while loop如何避免在while循环外编码第一次迭代
【发布时间】:2018-12-06 20:00:57
【问题描述】:

我经常遇到适合 while 循环的问题,但结果很丑,我在这里问是否有一个优雅的解决方案,或者是否所有可能的解决方案都很丑陋。有吗?

这是一个简化的示例:假设我们试图找到函数f <- function(x){x^2} 的最小值,以及找到它的位置。假设我们选择通过初始猜测x 并评估f(x) 来找到最小值。然后我们评估f(x-0.1)f(x+0.1)。如果这些值中的任何一个低于f(x),我们的新猜测就是argmin。我们重复,直到这种转变不再减少价值。

我想出的最佳解决方案是在循环之外运行算法的第一次迭代的一部分。但这需要我从循环中复制代码,即用!!!!!!! 括起来的代码部分。

# function to minimize
f <- function(x){x^2}

# initial guess
x.current <- 1
f.current <- f(x.current)

# !!!!!!!!!!!!
#  part of first iteration
x.guess <- c(x.current - 0.1, x.current + 0.1)
f.guess <- sapply(x.guess, f)
best.ind <- which.min(f.guess)
x.new <- x.guess[best.ind]
f.new <- f.guess[best.ind]
# !!!!!!!!!!!!

# part of first iteration and later iterations
while (f.new < f.current){
  x.current <- x.new
  f.current <- f.new

  x.guess <- c(x.current - 0.1, x.current + 0.1)
  f.guess <- sapply(x.guess, f)
  best.ind <- which.min(f.guess)
  x.new <- x.guess[best.ind]
  f.new <- f.guess[best.ind]
}

print("best guess = ")
print(x.current)

有没有“更好”的方式来做到这一点?

【问题讨论】:

  • 如果你能解释你想用这些值做什么会更有帮助。
  • 我认为关于什么是“丑陋”的问题将作为题外话关闭(取决于意见)。一些选项:1)将重复的代码放入自己的函数中,并在循环之前和循环中用一行调用它; 2)使用迭代计数器,并在循环中只为它执行一些代码>1
  • 丑陋地试图重新编程一个更好的内置 R 函数。请参阅nlm 函数。内置函数使用牛顿法,应该只需几步即可找到最小值,而不是缓慢的逐步方法。如果您确实需要一个while循环,那么只需将变量设置为将失败的条件。在上面的例子中设置f.new &lt;- f.current+1(在循环之外)并且循环总是至少执行一次。
  • @strboul 我对这个函数完全不感兴趣。我尝试用最少的例子来写我的问题,以便它们对网站上的其他人有用。我偶尔会遇到这个问题,我想做点什么。
  • @Dave2e 见上面的评论。该网站不允许我在一条评论中引用你们两个。

标签: r while-loop


【解决方案1】:

正如dww 所指出的,有几种选择。第三个是初始化在循环的第一次迭代和循环的测试条件中引用的变量:

# function to minimize
f <- function(x){x^2}

# initialize values
x.new <- 1
f.new <- f(x.new)
f.current <- f.new + 0.1 # just to fulfill test condition

# part of first iteration and later iterations
while (f.new < f.current){
  x.current <- x.new
  f.current <- f.new

  x.guess <- c(x.current - 0.1, x.current + 0.1)
  f.guess <- sapply(x.guess, f)
  best.ind <- which.min(f.guess)
  x.new <- x.guess[best.ind]
  f.new <- f.guess[best.ind]
}

print("best guess = ")
print(x.current)

【讨论】:

    【解决方案2】:

    有多种方法可以处理这种情况。一个人是“丑”还是“漂亮”是一个见仁见智的问题,因此对于 StackOverflow 来说是无关紧要的。尽管如此,我们可以对一些不同的选项进行一些概括:

    选项 1:将重复的行包裹在自己的函数中

    一个常见的经验法则是应该避免重复代码段。每当您在程序的不同位置看到一系列重复的行时,应强烈考虑将这些行放入自己的函数中并重复调用此函数。

    这有助于提高整体代码的可读性,使其更加简洁,并且要求维护者只通读并理解该部分一次。

    也许更重要的是,它还有助于代码的可维护性,因为对该 sn-p 的任何更改都会自动传播到整个程序。必须追查和更改重复代码 sn-p 的每个实例不仅在编辑代码时令人沮丧,而且也是一个潜在的容易出错的过程。

    您可以在这里应用此原则的一种方式,使用将函数调用放置在循环条件表达式中的附加技巧,这样我们只需要在此处调用它一次(尽管代码 inside while 循环不能保证执行,其条件中的代码必须始终至少执行一次:

    # initial guess
    x <- 1
    fx <- f(x)
    
    find.new = function(x){
      x.new <- c(x - 0.1, x + 0.1)
      f.new <- sapply(x.new, f)
      best.ind <- which.min(f.new)
      x.new <- x.new[best.ind]
      f.new <- f.new[best.ind]
      return(list(x=x.new, fx=f.new))
    }
    
    while ((new <- find.new(x))$fx < fx){
      x <- new$x
      fx <- new$fx
    }
    

    2 使用重复循环代替

    如果在这种情况下,循环中有一些代码我们总是希望至少执行一次,那么请考虑使用重复循环而不是 while。然后我们可以测试退出条件以更新值或中断循环。如果你原来的重复代码 sn-p 不需要在程序的其他任何地方执行,这比将它包装在自己的函数中更简洁

    repeat {
      x.new <- c(x - 0.1, x + 0.1)
      f.new <- sapply(x.new, f)
      best.ind <- which.min(f.new)
      x.new <- x.new[best.ind]
      f.new <- f.new[best.ind]
      if (f.new < fx) {
        x <- x.new
        fx <- f.new
      } else {
        break
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-10-20
      • 2011-08-20
      • 2018-05-14
      • 2015-03-23
      • 1970-01-01
      • 1970-01-01
      • 2016-06-19
      • 2012-05-28
      • 2017-10-28
      相关资源
      最近更新 更多