【问题标题】:Avoid memory increase in foreach loop in R避免在 R 中的 foreach 循环中增加内存
【发布时间】:2017-11-14 09:40:33
【问题描述】:

我尝试结合两个不同的空间数据集创建汇总统计数据:一个大栅格文件和一个多边形文件。这个想法是获取每个多边形内栅格值的汇总统计数据。

由于栅格太大而无法一次处理,我尝试创建子任务并并行处理它们,即一次处理来自SpatialPolgyonsDataframe 的每个多边形。

代码运行良好,但是在大约 100 次交互后,我遇到了内存问题。这是我的代码和我打算做什么:

# session setup
library("raster")
library("rgdal")

# multicore processing. 
library("foreach")
library("doSNOW")
# assign three clusters to be used for current R session
cluster = makeCluster(3, type = "SOCK",outfile="")
registerDoSNOW(cluster)
getDoParWorkers()# check if it worked

# load base data
r.terra.2008<-raster("~/terra.tif")
spodf.malha.2007<-readOGR("~/,"composed")

# bring both data-sets to a common CRS
proj4string(r.terra.2008)
proj4string(spodf.malha.2007)
spodf.malha.2007<-spTransform(spodf.malha.2007,CRSobj = CRS(projargs = proj4string(r.terra.2008)))
proj4string(r.terra.2008)==proj4string(spodf.malha.2007) # should be TRUE

# create a function to extract areas
function.landcover.sum<-function(r.landuse,spodf.pol){
  return(table(extract(r.landuse,spodf.pol)))}

# apply it one one subset to see if it is working
function.landcover.sum(r.terra.2008,spodf.malha.2007[1,])

## parallel loop
# define package(s) to be use in the parallel loop
l.packages<-c("raster","sp")

# try a parallel loop for the first 6 polygons
l.results<-foreach(i=1:6,
                   .packages = l.packages) %dopar% {
                     print(paste("Processing Polygon ",i, ".",sep=""))
                     return(function.landcover.sum(r.terra.2008,spodf.malha.2007[i,]))
                     }

这里的输出是一个看起来像这样的列表。

l.结果

[[1]]

9     10 
193159   2567 

[[2]]

7    9   10   12   14   16 
17  256 1084  494   67   15 

[[3]]

3      5      6      7      9     10     11     12 
2199   1327   8840   8579 194437   1061   1073   1834 
14     16 
222   1395 

[[4]]

3      6      7      9     10     12     16 
287    102    728 329057   1004   1057     31 

[[5]]

3      5      6      7      9     12     16 
21      6     20    495 184261   4765     28 

[[6]]

6    7    9   10   12   14 
161  161  386  943  205 1515 

所以结果相当小,不应该是内存分配问题的根源。因此,在具有 >32.000 行的整个多边形数据集上的以下循环会在大约 100 次迭代后创建超过 8GB 的​​内存分配。

# apply the parallel loop on the whole dataset
l.results<-foreach(i=1:nrow(spodf.malha.2007),
                   .packages = l.packages) %dopar% {
                     print(paste("Processing Polygon ",i, ".",sep=""))
                     return(function.landcover.sum(r.terra.2008,spodf.malha.2007[i,]))
                     # gc(reset=TRUE) # does not resolve the problem
                     # closeAllConnections()  # does not resolve the problem
                   }

我做错了什么?

编辑: 我尝试(如 cmets 中的建议)在内部循环中的每次迭代后删除对象,但它没有解决问题。我还尝试通过首先将对象传递给环境来解决多个数据导入的最终问题:

clusterExport(cl = cluster,
              varlist = c("r.terra.2008","function.landcover.sum","spodf.malha.2007"))

没有大的变化。我的 R 版本在 linux 平台上是 3.4,所以据说第一个评论中的链接补丁也应该已经包含在这个版本中。我还按照第一条评论中的建议尝试了 parallel 包,但没有出现任何差异。

【问题讨论】:

  • 我只能提供一些猜测/建议。猜测 1:foreach 在每次迭代时将数据 r.terra.2008spodf.malha.2007[i,] 导出到每个核心。建议 1:尝试删除每个核心上的 rm() 对象,然后垃圾收集 gc()。 (我不确定return 一个值是否会让你退出你的%dopar% 代码块。)建议2:看起来你还在使用doSNOW,我听说它没有得到很好的支持(传闻)。我会尝试最新版本的library(parallel)。也请查看此链接https://github.com/HenrikBengtsson/Wishlist-for-R/issues/27
  • 以上都不适合我(不幸的是)。见我上面的编辑。
  • 这个其实和raster包有关。如果有人遇到相关问题,这里有一些帮助:stackoverflow.com/questions/25426405/…

标签: r memory foreach parallel-processing raster


【解决方案1】:

您可以尝试exactextractr 包中的exact_extract。是从栅格中提取值的最快且内存更安全的函数。 main 函数是用 C++ 实现的,通常不需要并行化。由于您没有提供任何示例数据,因此我发布了一个带有真实数据的示例:

library(raster)
library(sf)
library(exactextractr)


# Pull municipal boundaries for Brazil
brazil <- st_as_sf(getData('GADM', country='BRA', level=2))

# Pull gridded precipitation data
prec <- getData('worldclim', var='prec', res=10)
#transform precipitation data in a dummy land use map
lu <- prec[[1]]
values(lu) <- sample(1:10,ncell(lu),replace = T)
plot(lu)

#extract land uses class for each pixel inside each polygon
ex <- exact_extract(lu, brazil)
#apply table to the resulting list. Here I use just the first 5 elements to avoid long output

lapply(ex[1:5],function(x){
  table(x[,1])#note that I use x[,1] because by default exact_extract provide in the second column the coverage fraction of each pixel by each polygon
})

这里是示例输出:

[[1]]

 1  2  4  6  7  9 10 
 1  1  1  2  3  1  1 

[[2]]

 2  3  4  5  6  7  8 10 
 2  4  3  2  1  2  2  2 

[[3]]

 1  2  4  6  7  8  9 10 
 4  5  1  1  4  2  5  5 

[[4]]

 1  2  3  4  5  6  7  8  9 10 
 2  2  4  2  2  4  1  4  1  2 

[[5]]

 3  4  5  6  8 10 
 2  3  1  1  2  3 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多