R - 循环
R - 控制流:循环及其现代替代方案
Section titled “R - 控制流:循环及其现代替代方案”在编程中,我们经常需要多次重复一项任务。循环允许我们重复执行一段代码块。虽然 R 拥有与其他语言类似的传统循环,但它也提供了更高效、更易读的替代方案,如向量化和函数式编程,这些方法通常更受青睐。
本教程将介绍标准循环 (for, while, repeat),然后引入处理重复任务的现代“R 原生”方式。
传统循环结构
Section titled “传统循环结构”1. for 循环
Section titled “1. for 循环”一个 for 循环会遍历序列(如向量或列表)中的每个项。当您确切知道需要迭代多少次时,它非常有用。
# A for loop that iterates through a vector of numbersfor (i in 1:5) { # The code inside the curly braces is the 'loop body' print(paste("The current number is:", i))}
# Output:# [1] "The current number is: 1"# [1] "The current number is: 2"# ... and so on up to 52. while 循环
Section titled “2. while 循环”只要指定的条件为 TRUE,while 循环就会重复执行。当您事先不知道确切的迭代次数时,它很有用。
counter <- 1
while (counter <= 5) { print(paste("Counter is at:", counter)) counter <- counter + 1 # CRITICAL: You must change the condition variable inside the loop!}
# Output:# [1] "Counter is at: 1"# [1] "Counter is at: 2"# ... and so on up to 5常见错误: 忘记更新 while 条件中的变量(例如 counter <- counter + 1)将导致无限循环,这会使您的 R 会话崩溃。
3. repeat 循环
Section titled “3. repeat 循环”一个 repeat 循环默认会创建无限循环。您必须提供一个显式的 break 语句来退出它。它不太常见,但当退出条件复杂且最好在循环中间检查时,它会很有用。
counter <- 1
repeat { print(paste("Repeat loop counter:", counter)) if (counter >= 5) { break # Exit the loop } counter <- counter + 1}循环控制语句
Section titled “循环控制语句”break:立即终止整个循环。next:跳过当前迭代的剩余部分,并进入下一次迭代。
# Example of 'next' and 'break'for (i in 1:10) { if (i %% 2 != 0) { next # Skip odd numbers } if (i > 8) { break # Stop if the number is greater than 8 } print(i)}
# Output:# [1] 2# [1] 4# [1] 6# [1] 8“R 方式”:循环的现代替代方案
Section titled ““R 方式”:循环的现代替代方案”在 R 中,循环可能会很慢,尤其是处理大型数据集时。R 的优势在于向量化和函数式编程,它们更快,而且通常更简洁。
1. 向量化:最快的方法
Section titled “1. 向量化:最快的方法”向量化意味着一次性对整个向量应用操作,而不是逐个元素地应用。R 对此进行了高度优化。
my_numbers <- c(10, 20, 30, 40, 50)
# The slow, loop-based wayresult_loop <- numeric(length(my_numbers))for (i in 1:length(my_numbers)) { result_loop[i] <- my_numbers[i] * 2}
# The fast, vectorized R wayresult_vectorized <- my_numbers * 2
# Both produce the same result, but the vectorized way is far superior.# result_vectorized is c(20, 40, 60, 80, 100)2. 函数式编程:purrr::map 函数族
Section titled “2. 函数式编程:purrr::map 函数族”当您需要对列表或向量的每个元素应用更复杂的函数时,purrr 包(tidyverse 的一部分)中的 map() 函数是现代标准。它们比基础 R 的 apply 函数族更一致且可预测。
library(purrr)
my_list <- list(a = 1:5, b = c(10, 20), c = 100)
# Use map() to get the mean of each element. The result is a list.list_of_means <- map(my_list, mean)# Result: list(a = 3, b = 15, c = 100)
# Use map_dbl() to get the mean and return a numeric vector.vector_of_means <- map_dbl(my_list, mean)# Result: c(a = 3, b = 15, c = 100)结论:何时应该使用循环?
Section titled “结论:何时应该使用循环?”尽可能努力使用向量化操作或 purrr::map 函数。然而,在某些情况下,for 循环仍然完全适用且必要:
- 顺序依赖: 当一次迭代的结果依赖于前一次迭代的结果时(例如,在某些模拟中)。
- 副作用: 当循环的主要目的是产生副作用时,例如打印到控制台、绘制图表或保存文件。
- 复杂逻辑: 当逻辑过于复杂而无法整齐地适配向量化或函数式形式时,循环可能更具可读性。