【问题标题】:How to loop through input variables for a function in R?如何遍历R中函数的输入变量?
【发布时间】:2018-02-12 18:26:02
【问题描述】:

我有一个函数,biovars(prec,tmin,tmax),输入三个变量。 prec,tmin,tmax 是多频段GeoTiff。但是有几个 Tiff 存储在不同的目录中,需要在将它们传递给函数之前对其进行堆叠:

stack("/path1/to/file/prec1.tif") 
stack("/path2/to/file/tmin1.tif") 
stack("/path3/to/file/tmax1.tif")

如何循环遍历每个目录,堆叠第一个文件并将循环结果用作函数的输入:

biovars(prec1,tmin1,tmax1)
biovars(prec2,tmin2,tmax2)
...
biovars(precn,tminn,tmaxn)

有没有一种简单的方法可以做到这一点?我认为三个 for 循环是不可能的......

【问题讨论】:

  • 这是一个有 12 个波段的 GeoTiff
  • 根据您的数据,看起来您只需要一个循环,因为prec、tmin 和tmax 都使用 1:n 的相同值。如果不是这种情况,请随时纠正我。但在这种情况下,for (i in 1:n) { biovars(get(paste0(prec, i)), get(paste0(tmin, i)), get(paste0(tmax, i))) }
  • 那是什么数据类型? CSV、TAB、XML?每个文件一列?
  • @Punintended:所以看起来似乎是合理的。我不知道这是可能的。我会试试这个。 @Parfait:数据类型为栅格(GeoTiff)

标签: r function loops directory


【解决方案1】:

根据您的描述,我认为您可以这样做:

library(dismo)
# setwd(root of data files")
fprec <- list.files(".", pattern="prec", recursive=TRUE, full.names=TRUE)
ftmin <- gsub("prec", "tmin", fprec)
ftmax <- gsub("prec", "tmax", fprec)
fbio <-  gsub("prec", "bio", fprec)   

for (i in 1:length(fprec)) {
   prec <- brick(fprec[i])
   tmin <- brick(ftmin[i])
   tmax <- brick(ftmax[i])
   b <- biovars(prec, tmin, tmax, filename=fbio[i])

}

【讨论】:

  • 您好 RobertH,您的示例对我有用。我不得不稍微调整输入文件,但循环完成了工作!谢谢
【解决方案2】:

我总是更喜欢使用*apply 函数并避免使用get。它还导致易于阅读的代码 (IMO)。

prec_files = c("/path/prec1.tif", "/path/prec2.tif", ..., "/path/precn.tif")
tmin_files = c("/path/tmin1.tif", "/path/tmin2.tif", ..., "/path/tminn.tif")
tmax_files = c("/path/tmax1.tif", "/path/tmax2.tif", ..., "/path/tmaxn.tif")

prec_stacks <- lapply(prec_files, stack)
tmin_stacks <- lapply(tmin_files, stack)
tmax_stacks <- lapply(tmax_files, stack)

results <- mapply(FUN = biovar, prec_stacks, tmin_stacks, tmax_stacks)

如果biovars 返回一个有用的对象,您可以存储mapply 调用的结果。如果您通过(我假设)一次加载所有栅格而达到内存限制,您可以将加载和 biovar 调用包装到一个函数中:

stack_and_biovar <- function(prec_path, tmin_path, tmax_path) {
  prec <- stack(prec_path)
  tmin <- stack(tmin_path)
  tmax <- stack(tmax_path)
  biovar(prec, tmin, tmax)
}


mapply(FUN = stack_and_biovar, prec_files, tmin_files, tmax_files)

【讨论】:

    【解决方案3】:

    如果我理解正确,那么有一个简单的方法可以使用 pmap or pwalk 中的 purrr 包。

    基本上,您列出所有具有给定模式的文件,然后使用pmap/pwalk 循环该列表并将相应的文件名传递给raster::stack 和biovars 函数。

        library(tidyverse)
    
        pathGIS <- "/path1/to/file/"
        filePattern <- list("^prec*", "^tmax*", "^tmin*")
    
        # List files and sort them numerically using mixedsort from gtools
        fileList <- map(filePattern, ~ gtools::mixedsort(list.files(path = pathGIS, recursive = TRUE,
                                                        pattern = .x, full.names = TRUE)))
        head(fileList)
    
        # ..1, ..2, etc. correspond to the sublist order within fileList
        pwalk(fileList, ~ biovars(raster::stack(..1), raster::stack(..2), raster::stack(..3)))
        pmap(fileList, ~ biovars(raster::stack(..1), raster::stack(..2), raster::stack(..3)))
    

    简单示例

        fileList <- list(c("./GIS/prec1.tif", "./GIS/prec2.tif"), 
                         c("./GIS/tmax1.tif", "./GIS/tmax2.tif"), 
                         c("./GIS/tmin1.tif", "./GIS/tmin2.tif"))
    
        dummy_function <- function(precFile, tmaxFile, tminFile) {
          cat("\n-----\n")
          print(precFile)
          print(tmaxFile)
          print(tminFile)
          cat("-----\n")
        }
    
        pwalk(fileList, ~ dummy_function(..1, ..2, ..3))        
    
        -----
        [1] "./GIS/prec1.tif"
        [1] "./GIS/tmax1.tif"
        [1] "./GIS/tmin1.tif"
        -----
    
        -----
        [1] "./GIS/prec2.tif"
        [1] "./GIS/tmax2.tif"
        [1] "./GIS/tmin2.tif"
        -----
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 2018-03-07
      相关资源
      最近更新 更多