如何在R中循环执行完整脚本并存储多次运行结果
问题描述
我有一个包含大量数据处理的长R脚本,无法完整分享,但会展示部分内容说明需求。脚本中有randomPoints函数用于生成随机点,导致每次运行得到的最终对象都不同。我希望将整个脚本循环执行100次,并将每次生成的结果存入列表。
脚本初始化部分
area <- read_sf("area_erase.shp") # 栅格列表 agrilist <- sprintf('p%s_agriprop.tif', 1:6) results_agri <- lapply(agrilist, raster) results_agri <- setNames(results_agri, agrilist) # 第二组栅格列表 poplist <- sprintf('p%s_pop.tif', 1:6) results_pop <- lapply(poplist, raster) results_pop <- setNames(results_pop, poplist) # 重采样其中一个栅格 results_agri[[6]] <- resample(results_agri[[6]],results_agri[[5]],method="bilinear") # 合并栅格 allrasters <- mapply(raster::stack,results_agri,results_pop) # 加载已有点数据 pointslist <- sprintf('p%s_utm_n.csv', 1:6) results_points <- lapply(pointslist, read.csv) results_points <- setNames(results_points, pointslist) # 提取经纬度列 extr <- function(xts.obj){xts.obj[,c(2:3)]} points_xy <- lapply(results_points, extr)
随机点生成逻辑(结果差异来源)
# 生成随机点 pas[[1]] <- randomPoints(results_agri[[1]],n=1082,p=points_xy[[1]],ext=area) pas[[2]] <- randomPoints(results_agri[[1]],n=2506,p=points_xy[[2]],ext=area) pas[[3]] <- randomPoints(results_agri[[1]],n=2326,p=points_xy[[3]],ext=area) pas[[4]] <- randomPoints(results_agri[[1]],n=3168,p=points_xy[[4]],ext=area) pas[[5]] <- randomPoints(results_agri[[1]],n=3216,p=points_xy[[5]],ext=area) pas[[6]] <- randomPoints(results_agri[[1]],n=3176,p=points_xy[[6]],ext=area)
最终输出部分
每次迭代会生成6个单数值结果:
# 最终计算结果 st1 <- cellStats(prediction1>tr1,sum) st2 <- cellStats(prediction2>tr2,sum) st3 <- cellStats(prediction3>tr3,sum) st4 <- cellStats(prediction4>tr4,sum) st5 <- cellStats(prediction5>tr5,sum) st6 <- cellStats(prediction6>tr6,sum)
我希望将上述流程循环执行100次,每次的st1到st6都存入列表。之前考虑过repeat循环,但不确定怎么存储结果,也不知道如何在100次迭代后终止循环。
解决方案
方法1:用for循环(最直观易读)
把核心计算逻辑封装成函数,用for循环执行100次,同时将非重复的初始化代码放在循环外提升效率:
# 1. 初始化代码(只执行一次) area <- read_sf("area_erase.shp") agrilist <- sprintf('p%s_agriprop.tif', 1:6) results_agri <- lapply(agrilist, raster) results_agri <- setNames(results_agri, agrilist) poplist <- sprintf('p%s_pop.tif', 1:6) results_pop <- lapply(poplist, raster) results_pop <- setNames(results_pop, poplist) results_agri[[6]] <- resample(results_agri[[6]],results_agri[[5]],method="bilinear") allrasters <- mapply(raster::stack,results_agri,results_pop) pointslist <- sprintf('p%s_utm_n.csv', 1:6) results_points <- lapply(pointslist, read.csv) results_points <- setNames(results_points, pointslist) extr <- function(xts.obj){xts.obj[,c(2:3)]} points_xy <- lapply(results_points, extr) # 2. 创建空列表存储100次结果 final_results <- vector("list", 100) # 3. 封装核心计算逻辑为函数 run_single_analysis <- function() { # 生成随机点 pas <- vector("list", 6) pas[[1]] <- randomPoints(results_agri[[1]],n=1082,p=points_xy[[1]],ext=area) pas[[2]] <- randomPoints(results_agri[[1]],n=2506,p=points_xy[[2]],ext=area) pas[[3]] <- randomPoints(results_agri[[1]],n=2326,p=points_xy[[3]],ext=area) pas[[4]] <- randomPoints(results_agri[[1]],n=3168,p=points_xy[[4]],ext=area) pas[[5]] <- randomPoints(results_agri[[1]],n=3216,p=points_xy[[5]],ext=area) pas[[6]] <- randomPoints(results_agri[[1]],n=3176,p=points_xy[[6]],ext=area) # 补充你中间的处理逻辑(比如生成prediction1~6、tr1~6的代码) # 计算最终6个数值 st1 <- cellStats(prediction1>tr1,sum) st2 <- cellStats(prediction2>tr2,sum) st3 <- cellStats(prediction3>tr3,sum) st4 <- cellStats(prediction4>tr4,sum) st5 <- cellStats(prediction5>tr5,sum) st6 <- cellStats(prediction6>tr6,sum) # 返回命名向量,方便后续处理 c(st1=st1, st2=st2, st3=st3, st4=st4, st5=st5, st6=st6) } # 4. 执行100次循环 for (i in 1:100) { final_results[[i]] <- run_single_analysis() # 可选:打印进度 if (i %% 10 == 0) cat("完成第", i, "次迭代\n") }
方法2:用lapply(函数式写法更简洁)
如果习惯函数式编程,可直接用lapply生成结果列表:
# 初始化代码同方法1,省略... # 生成100次结果 final_results <- lapply(1:100, function(x) { pas <- vector("list", 6) pas[[1]] <- randomPoints(results_agri[[1]],n=1082,p=points_xy[[1]],ext=area) # 其他pas赋值逻辑同前 # 中间处理逻辑... st1 <- cellStats(prediction1>tr1,sum) # 其他st计算逻辑同前 c(st1=st1, st2=st2, st3=st3, st4=st4, st5=st5, st6=st6) }) # 可选:给列表命名,方便识别迭代次数 names(final_results) <- paste0("iteration_", 1:100)
方法3:用repeat循环(按你的初始思路实现)
# 初始化代码同方法1,省略... final_results <- vector("list", 100) count <- 1 repeat { # 达到100次则终止循环 if (count > 100) break pas <- vector("list", 6) pas[[1]] <- randomPoints(results_agri[[1]],n=1082,p=points_xy[[1]],ext=area) # 其他pas赋值逻辑同前 # 中间处理逻辑... st1 <- cellStats(prediction1>tr1,sum) # 其他st计算逻辑同前 final_results[[count]] <- c(st1=st1, st2=st2, st3=st3, st4=st4, st5=st5, st6=st6) count <- count + 1 }
关键注意事项
- 初始化代码放循环外:读取shp、栅格、csv等操作只执行一次,避免重复IO浪费时间。
- 结果格式:返回命名向量后,可通过
do.call(rbind, final_results)将列表转成数据框,方便后续统计分析。 - 随机种子(可选):如果需要复现结果,可在每次循环前设置种子,比如
set.seed(i)(i为迭代次数)。
内容的提问来源于stack exchange,提问作者Beardedant
相关产品推荐
相关产品推荐

