【问题标题】:Is there a more efficient method than while loops for something that requires conditional checking?对于需要条件检查的东西,有没有比 while 循环更有效的方法?
【发布时间】:2012-05-02 08:59:09
【问题描述】:

我有一个问题,涉及我在一段代码周围包裹一个 while 循环,我认为这些代码可以有效地向量化。但是,在每一步,我的停止条件都依赖于该阶段的值。将此示例视为我的问题的代表性模型:
使用 rnorm() 生成 N(0,1) 个随机变量,直到您对大于任意值 k 的值进行采样。

编辑:我在 cmets 中讨论的问题的一个警告是,我无法先验地知道在我的停止条件之前要采集多少个样本的良好近似值。

一种方法:

  1. 使用 while 循环,对大小合适的正态随机向量进行采样(例如,rnorm(50) 一次采样 50 个标准法线,或者 rnorm(1) 如果 k 接近于零)。检查此向量以查看是否有任何观察值大于 k。

  2. 如果是,则停止并返回所有前面的值。否则,将第 1 步中的向量与通过重复第 1 步创建的新向量合并。

另一种方法是为给定的 k 指定一个完全过大的随机抽奖次数。这可能意味着如果 k=2,则使用 rnorm(1000) 对 1,000 个正态随机变量进行抽样。

在第二种情况下利用 R 提供的矢量化比循环版本更快的结果是在过度杀伤数字不是比必要大太多的情况下,但在我的问题中,我对有多少没有很好的直觉我需要跑步,所以我需要保守一点。

问题如下:有没有办法像方法 2 那样进行高度矢量化的过程,但像方法 1 那样使用条件检查?考虑到高度向量化的方法是逐个元素的速度更快,但更浪费时,执行像rnorm(50) 这样的小型向量化操作是“最快”的方式吗?

【问题讨论】:

  • 我不确定任何人都能回答这个问题,因为矢量化 R 代码通常需要相当详细地了解您要改进的整个代码块。
  • 代码本身是矢量化的,但我的停止条件涉及检查每个元素,因此我失去了将代码完全矢量化的很多好处。我希望有一个巧妙的 R 技巧,它可以提供apply 套件的速度,但一旦我达到我的状态,我就可以停下来。
  • 使用第三种方法。您不需要“矫枉过正”的抽奖次数。您知道分布和想要大于的值,因此您知道对该数字进行抽样的概率。例如。如果k=3,那么如果你运行rnorm(1e3),你应该得到比k大3个数字。 which(rnorm(1e3)) 告诉你第一个匹配的元素。
  • 我正在实施一个随机优化程序,在我的停止标准之前我不确定发生的概率。
  • 也许一个很好的折衷方案,在你的两种方法之间,是在每次循环迭代之间增加新样本的数量。例如,不要一次取 50 个,而是做 50、100、200、400 等。

标签: r loops


【解决方案1】:

这是我之前建议的一个实现:使用您的第一种方法,但在每次迭代之间增加新样本的数量,例如,在每次迭代之间而不是 50 新样本,在每次迭代之间将该数字乘以 2:@ 987654322@,然后是100200400

由于您的样本量遵循不同的几何级数,您可以保证在“少数”迭代中退出。

sample.until.thresh <- function(FUN, exit.thresh,
                                sample.start = 50,
                                sample.growth = 2) {

   sample.size    <- sample.start
   all.values     <- list()
   num.iterations <- 0L

   repeat {
      num.iterations <- num.iterations + 1L
      sample.values  <- FUN(sample.size)
      all.values[[num.iterations]] <- sample.values

      above.thresh <- sample.values > exit.thresh
      if (any(above.thresh)) {
         first.above <- match(TRUE, above.thresh)
         all.values[[num.iterations]] <- sample.values[1:first.above]
         break
      }

      sample.size <- sample.size * sample.growth
   }

   all.values <- unlist(all.values)

   return(list(num.iterations = num.iterations,
               sample.size    = length(all.values),
               sample.values  = all.values))
}

set.seed(123456L)
res <- sample.until.thresh(rnorm, 5)
res$num.iterations
# [1] 16
res$sample.size
# [1] 2747703

【讨论】:

  • 这实际上是一个非常好的方法。当我不知道需要多少样本时,逐渐增加向量化的数量效果很好。谢谢!
猜你喜欢
  • 2012-09-14
  • 1970-01-01
  • 2016-04-15
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多