You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 23:45:30