将嵌套的for循环转换为foreach

时间:2020-08-06 02:11:43

标签: r loops foreach parallel-processing

我正在尝试将嵌套的for循环转换为foreach,以便可以使用并行处理。该循环根据指定要提取的netCDF中元素位置的向量列表从netCDF文件中提取信息。这是我的示例:

加载必要的程序包

# devtools::install_github("BigelowLab/fvcom", force = T)

library(fvcom)
library(ncdf4)
library(raster)
library(rgdal)

我已将netCDF文件保存到硬盘驱动器,但可以在这里使用:https://www.glerl.noaa.gov/data/chrp/Rowe_etal_2019_data/20170530-2/ 对于此示例,我使用了此页面上的前3个文件。

setwd("D:/FADR81 netCDF files/example for parallel processing")

file_list <- list.files(pattern = "*.nc")

创建一个向量列表,指示我要从每个netCDF文件中提取的元素的位置。这些是在此处任意分配的,但实际上与来自另一个数据集的观察结果保持一致。

k1 <- 1:10
k2 <- c(1:5, 12:20, 45:51)
k3 <- 200:213

keep <- list(k1, k2, k3)

运行循环以提取时间并创建温度和溶解氧的栅格。

system.time({

  times.all <- character(length(keep[[1]]))
  temp.all <- list()
  do.all <- list ()

  for(i in 1:length(keep)) {
    nc <- nc_open(file_list[[i]])
    mesh <- get_mesh_geometry(nc, what = 'lonlat')
    times <- character(length = length(keep[[i]]))
    temp <- list()
    do <- list()

    for(j in 1:length(keep[[i]])) {
      times[j] <- as.character(as.POSIXct(ncvar_get(nc, "Times", start=c(1, keep[[i]][j]), count=c(-1, 1)),
                                      format = "%Y-%m-%dT%H:%M:%S", tz = "UTC"))
  
      temp[[j]] <- get_mesh(nc, vars = "temp", mesh = mesh, time = keep[[i]][j], y = 20)
      temp[[j]] <- raster::stack(sapply('temp', function(f) fvcom::rasterize(temp[[j]], field = f), simplify = FALSE))
  
      do[[j]] <- get_mesh(nc, vars = "Dissolved_oxygen", mesh = mesh, time = keep[[i]][j], y = 20)
      do[[j]] <- raster::stack(sapply('Dissolved_oxygen', function(f) fvcom::rasterize(do[[j]], field = f), simplify = FALSE))
  
    }

    nc_close(nc)

    times.all <- c(times.all, times)
    temp.all <- c(temp.all, temp)
    do.all <- c(do.all, do)

  }

  times.all2 <- times.all[-which(times.all == '')]

})

我需要循环访问数百个netCDF文件,并从每个文件中提取不同的元素。我希望我可以使用foreach来并行化此循环并提高处理速度,但是我没有太多运气来弄清楚如何做到这一点。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

根据Roland的建议,我更加仔细地研究了apply函数,并能够将for循环重写为函数,并使用mapply()复制了我以前的结果。从那里开始,在并行包中很容易过渡到mcmapply()。这是我的函数以及我用来通过使用file_list的mcmapply()运行此代码的代码,并避免出现原始问题。

get_dat <- function(x, z){
  nc <- nc_open(x)
  times <- as.character(as.POSIXct(ncvar_get(nc, "Times"), format = "%Y-%m-%dT%H:%M:%S", tz = "UTC"))
  times2 <- times[z]

  mesh <- get_mesh_geometry(nc, what = 'lonlat')
  temp <- list()
  do <- list()

  for(i in 1:length(z)) {

    temp[[i]] <- get_mesh(nc, vars = "temp", mesh = mesh, time = z[[i]], y = 20)
    temp[[i]] <- raster::stack(sapply('temp', function(f) fvcom::rasterize(temp[[i]], field = f), simplify = FALSE))

    do[[i]] <- get_mesh(nc, vars = "Dissolved_oxygen", mesh = mesh, time = z[[i]], y = 20)
    do[[i]] <- raster::stack(sapply('Dissolved_oxygen', function(f) fvcom::rasterize(do[[i]], field = f), simplify = FALSE))

  }


  nc_close(nc)

  exp.dat <- list(times2, temp, do)

  return(exp.dat)
}



system.time({

  new.dat <- mcmapply(get_dat, file_list, keep, mc.cores = 3)

  new.time <- list()
  new.temp <- list()
  new.do <- list()

  for(i in 1:length(file_list)){
    new.time[[i]] <- new.dat[1, i]
    new.temp[[i]] <- new.dat[2, i]
    new.do[[i]] <- new.dat[3, i]

  }

  new.time2 <- unlist(new.time, use.names = F)
  new.temp2 <- unlist(new.temp, use.names = F)
  new.do2 <- unlist(new.do, use.names = F)

})

您可以通过从原始问题中提供的链接下载netCDF文件来重现此示例。

相关问题