【问题标题】:Reduce memory usage for mosaic on large list of rasters减少大型栅格列表上马赛克的内存使用量
【发布时间】:2018-03-10 23:21:31
【问题描述】:

我正在使用 @RobertH here 建议的方法,使用 raster 包中的 mosaic 函数来组合一长串(11,000 个文件)栅格。

rlist <- sapply(list_names)
rlist$fun <- mean
rlist$na.rm <- TRUE
x <- do.call(mosaic, rlist)

正如您可能想象的那样,这最终会超出我的可用内存(在几台不同的机器和计算集群上)。我的问题是:有没有办法减少mosaicdo.call 的内存使用量?我尝试在rasterOptions() 中更改maxmemory,但这似乎没有帮助。以较小的批次处理栅格似乎有问题,因为栅格可能在空间上是不相交的(即,连续的栅格文件可能彼此相距很远)。提前感谢您提供的任何帮助。

【问题讨论】:

  • 你可以在地理上连续的批次中这样做吗?
  • @RobertH,我想是的(假设我可以使用范围对象对rlist 进行排序)。那是否还需要我将这些中间栅格拼接在一起(并继续我的记忆问题)?
  • 我从未尝试过使用这么多文件,但也许您可以尝试使用gdalUtils::gdalbuildvrt 构建一个 gdal vrt 文件,然后从那里开始工作。 rdocumentation.org/packages/gdalUtils/versions/2.0.1.7/topics/….
  • 我不知道分步执行此操作是否会有所帮助。一开始不应该有内存问题......你也试过rasterOptions(todisk=TRUE)
  • 虚拟文件的想法很有趣。您可以制作一个 vrt,然后使用 writeRaster(除了这将等效于 merge,而不是 mosaic

标签: r r-raster


【解决方案1】:

您可以一次处理一个,而不是一次将所有栅格加载到内存中(在mosaic() 调用中)?这样一来,您的马赛克会在您每次将更多栅格带入内存时更新,但随后您可以摆脱新栅格并保持不断更新的马赛克栅格。

假设您的 rlist 对象是栅格列表,我正在考虑类似:

伪代码

  1. updating_raster 对象初始化为列表中的第一个栅格
  2. 从第二个栅格开始依次循环遍历列表中的每个栅格
  3. 将第 i 个栅格读入名为 next_raster 的内存中
  4. 更新updating_raster 对象,使用其自身的马赛克和使用加权平均值的下一个栅格覆盖它

R代码

使用mosaic() 帮助文件示例中的代码进行测试...

首先生成一些栅格并使用标准的镶嵌方法。

library(raster)

r <- raster(ncol=100, nrow=100)
r1 <- crop(r, extent(-10, 11, -10, 11))
r2 <- crop(r, extent(0, 20, 0, 20))
r3 <- crop(r, extent(9, 30, 9, 30))

r1[] <- 1:ncell(r1)
r2[] <- 1:ncell(r2)
r3[] <- 1:ncell(r3)

m1 <- mosaic(r1, r2, r3, fun=mean)

将栅格放在一个列表中,以便它们的格式与我认为的相似。

rlist <- list(r1, r2, r3)

由于 NA 处理 weighted.mean() 函数,我选择通过将求和和除法分解为不同的步骤来创建相同的效果...

首先初始化求和栅格:

updating_sum_raster <- rlist[[1]]

然后初始化“计数器”栅格。这将表示在每个像素处进行镶嵌的栅格数。它在所有不是NA 的单元格中以1 开头。它应该正确处理NAs,以便只有在将非NA 值添加到更新总和时它才会增加给定像素。

updating_counter_raster <- updating_sum_raster
updating_counter_raster[!is.na(updating_counter_raster)] <- 1

这是不需要所有栅格一次都在内存中的循环。添加到马赛克的栅格的反栅格仅在不是 NA 的像元中的值为 1。通过对当前计数器光栅和更新计数器光栅求和来更新计数器。通过对当前栅格值和更新栅格值求和来更新总和。

for (i in 2:length(rlist)) {

  next_sum_raster <- rlist[[i]]
  next_counter_raster <- next_sum_raster
  next_counter_raster[!is.na(next_counter_raster)] <- 1

  updating_sum_raster <- mosaic(x = updating_sum_raster, y = next_sum_raster, fun = sum)
  updating_counter_raster <- mosaic(updating_counter_raster, next_counter_raster, fun = sum)

}

m2 <- updating_sum_raster / updating_counter_raster

这里的值似乎与mosaic() 函数的使用相匹配

identical(values(m1), values(m2))
> TRUE

但栅格本身并不相同:

identical(m1, m2)
> FALSE

不完全确定为什么,但也许这会让你更接近?

也许compareRaster() 是更好的检查方式:

compareRaster(m1, m2)
> TRUE

万岁!

这是一个情节!

plot(m1)
text(m1, digits = 2)
plot(m2)
text(m2, digits = 2)

再挖一点杂草......

来自mosaic.R 文件:

看起来mosaic() 函数初始化了一个名为v 的矩阵,以填充列表中所有栅格中所有单元格的值。矩阵v 中的行数是输出栅格中的像元数(基于完整的镶嵌范围和分辨率),列数是在您的情况下要镶嵌的栅格数(11,000)。也许您遇到了 R 中矩阵创建的限制?

对于 1000 x 1000 栅格(1e6 像素),v 矩阵 NAs 占用 41 GB。您希望最终的镶嵌栅格有多大?

r <- raster(ncol=1e3, nrow=1e3)
x <- 11000
v <- matrix(NA, nrow=ncell(r), ncol=x)
format(object.size(v), units = "GB")
[1] "41 Gb"

【讨论】:

  • 这行得通!诀窍似乎是:a)一次只读取 1 个栅格,而不将 rlist 中的每个栅格保存在内存中,b)限制添加到马赛克中的 NA 数量,以及 c)使用 rasterOptions(todisk=TRUE)。可以通过创建自定义函数并使用lapply 来加速它,但在这一点上,我会坚持使用有效的方法。感谢@mikoontz 提供非常彻底的答案。
猜你喜欢
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多