【问题标题】:Loops and variable scope in RR中的循环和变量范围
【发布时间】:2013-06-12 02:57:20
【问题描述】:

我在 R 中有以下 for 循环:

v = c(1,2,3,4)
s = create.some.complex.object()
for (i in v){
   print(i)
   s = some.complex.function.that.updates.s(s)
}
# s here has the right content.

不用说,这个循环在 R 中非常慢。 我试着用函数式来写它:

   lapply(v, function(i){
      print(i)
      s = some.complex.function.that.updates.s(s)
   })
   # s wasn't updated.

但这不起作用,因为s 是按值传递的,而不是按引用传递的。 我只需要最后一次迭代的结果,而不是所有的中间步骤。 如何用 R 风格制定第一个循环?

穆龙

【问题讨论】:

  • 尝试其他赋值运算符:s <<-
  • @Thomas 这会使他的代码更慢。为什么不直接将结果列表作为lapply 用于返回?
  • lapply 可能不会让你的循环更快。通常,当每次迭代没有副作用或避免必须预先分配对象时,您会使用lapply(和朋友);在这里你明确地有这样的副作用。
  • @Michele 我错过了关于速度的部分。我对 OP 真正想要的东西感到困惑:每次迭代或只是最后一次迭代的最终结果。
  • @Thomas 我也是。只是明白他需要决赛。大概for是最好的办法

标签: r variables for-loop functional-programming


【解决方案1】:

循环本身真的有问题吗?还是执行 some.complex.function.that.updates.s 需要的时间? 一些 R 程序员会跳过箍来避免循环,但看看这个例子:

f <- function(a) a/1.001
loop <- function(n) { s = (1/f(1)^n); for (i in 1:n) s <- f(s); s}
system.time(loop(1E7))
   user  system elapsed 
  7.011   0.030   7.008

这是 0.7 微秒(在 MacBook Pro 上)在循环中每次调用一个非常微不足道的函数。

【讨论】:

    【解决方案2】:

    如果您不能多次创建它,那么就没有太多选择了。如果没有看到您正在操作的对象,也很难说。如果对象正在增长/追加,您可以收集中间结果并在最后进行追加。如果它实际上正在变异,您应该尝试摆脱传递值并使用引用类 (http://www.inside-r.org/r-doc/methods/ReferenceClasses)。那么修改它的函数实际上就是你调用 n 次的方法。

    【讨论】:

      【解决方案3】:
         lapply(v, function(i){
            print(i)
            s = some.complex.function.that.updates.s(s)
            return(s)
         })
      

      结果将是为v 的每个值创建的对象s 的列表。即使它应该已经传递了 v 的值,因为它是函数执行的最后一个操作。

      【讨论】:

      • 这样就可以了,但是s对象可能很大,我保存不了很多次。我想处理对象的一个​​实例,就像我在 for 循环中所做的那样。
      • @Mulone 等一下,所以每个v 的值都不需要s 对象?但是每次都要重新计算?
      • @Mulone 如果是这样,可能for 是最快和最直接的解决方案。否则,您可以尝试Rcpp 包并为您编写c++ 代码for 循环。
      猜你喜欢
      • 2013-11-18
      • 2023-03-31
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多