何时在R中使用for循环

10

您刚学完 R 语言的介绍,可能学习了 for 循环的语法,但随即被告知在 R 中要避免使用 for 循环!

R 是一种矢量化语言,因此您被告知永远不要像以下示例那样编写代码:

x = 1:10
y = 2:11
z = rep(NA, 10)
for i in 1:10{    
    z[i] = x[i] + y[i]    
}

而应该做的是替换为。
z = x + y

您还被告知使用*ply函数族进行迭代循环。

我的问题是,除了潜在的代码可读性场景外,在R中是否有适合使用for循环的好时机?


2
假设您想为每次运行分配一个值并在随后的运行中使用该值,可以使用 for 循环。虽然 Reduce 具有类似的潜力,但我认为 for 循环更好。 - akrun
1
参考Patrick Burns的《R地狱》。只要你预分配对象,循环就没问题。如果你想要超级快速度,最好采用一些专业技巧,比如使用data.table或利用Rcpp的威力。 - Roman Luštrik
1
这种类型的问题以前已经被问过了。@germcd已经为您找到了链接。http://chat.stackoverflow.com/transcript/message/29792007#29792007 - Roman Luštrik
这个问题也与此相关:https://dev59.com/73E95IYBdhLWcg3wheNR“apply”系列函数是否仅仅是语法糖? - germcd
当我无法进行向量化时,我会使用 *ply。 - NewNameStat
显示剩余2条评论
2个回答

10

Advanced R提到了三种循环情况:就地修改、递归函数和while循环。由于您要求使用for循环,因此以下是前两种情况的内容:

就地修改

如果需要修改现有数据框的部分内容,则通常最好使用for循环。例如,以下代码通过将函数列表的名称与数据框中变量的名称进行匹配,对变量进行逐个转换。

trans <- list(
  disp = function(x) x * 0.0163871,
  am = function(x) factor(x, levels = c("auto", "manual"))
)
for(var in names(trans)) {
  mtcars[[var]] <- trans[[var]](mtcars[[var]])
}

我们通常不会直接使用lapply()来替换这个循环,但这是可能的。

递归关系

当元素之间的关系不独立或通过递归定义时,很难将for循环转化为函数式。例如,指数平滑通过对当前和前一个数据点加权平均来工作。下面的exp()函数使用for循环实现指数平滑。

exps <- function(x, alpha) {
  s <- numeric(length(x) + 1)
  for (i in seq_along(s)) {
    if (i == 1) {
      s[i] <- x[i]
    } else {
      s[i] <- alpha * x[i - 1] + (1 - alpha) * s[i - 1]
    }
  }
  s
}
x <- runif(6)
exps(x, 0.5)
#> [1] 0.6622163 0.6622163 0.4758159 0.2703593 0.1896377 0.5506731 0.7300305

我们无法消除for循环,因为我们所见过的函数式编程方法都不允许位置i处的输出依赖于位置i-1处的输入和输出。

1
Advanced R 只是指在可读性方面 for 循环更好的情况,这不是他所问的。 - adaien

5

创建一个多页的图形PDF。或者是任何在每个迭代中需要很长时间的事情,比如绘制图形。如果循环不是瓶颈,对我来说这样做通常更易读,所以我会这么做。

pdf("file.pdf", onefile=TRUE)
for(var in unique(df$some_var)){
  p <- ggplot(df[df$some_var==var, ], aes(x=x, y=y)) + geom_line()
  print(p)
}
dev.off()

这实际上是我提问的确切动机!我确实这样做了,并对自己说:“嗯,我上次在R中写for循环是什么时候?” - NewNameStat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接