如何将多个Rasterstack聚合为一个

时间:2016-01-05 02:29:53

标签: r spatial raster

我有几个Rasterstacks从几个时间序列Netcdf文件创建。我想将这些汇总到平均值/中位数和相关的95%置信区间或标准偏差统计量。输出将是相同维度的单个Rasterstack,表示在所有Rasterstacks中采用的平均值/中值/ stdev。

我尝试使用overlay功能,但它似乎不起作用。这是一个可重复的例子:

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

r <- raster(ncol=10, nrow=10)
r1 <- init(r, fun=runif)
r2 <- init(r, fun=runif)
r3 <- overlay(r1, r2, fun=function(x,y){return(x+y)})
r4 <- overlay(r1, r2, fun=function(x,y){(x*y)} )
r5 <- overlay(r1, fun=sqrt)

#create rasterstacks
s1 <- stack(r1, r2,r3)
s2 <- stack(r3, r4,r5)
s3 <- stack(r4, r5, r2)
s4 <- stack(r1, r4, r3)

z<-overlay(s1, s2, s3, s4, fun=function(a,b,c,d){return(median(a,b,c,d))} )
Error in (function (x, fun, filename = "", recycle = TRUE, ...)  : 
cannot use this formula, probably because it is not vectorized

1 个答案:

答案 0 :(得分:1)

编辑:这篇文章提供了解决问题的三种方法。最快的大型RasterStacks是第三种方法,它将堆栈强制转换为数组并对其进行计算。

方法1:叠加

我假设你想要分层统计,也就是说,你希望你的结果是一个有三层的RasterStack,第一层是四层堆栈的中位数&#39;第一层(即栅格的中位数r1r3r4r1),第二层是四个堆栈的中位数&#39;第二层(中位数为r2,r4 , r5 , and r4`),等等。

您可Vectorize个函数meanmediansd来实现此目标:

overlay(s1, s2, s3, s4, fun=function(...) Vectorize(median, 'x')(list(...)))

## class       : RasterBrick 
## dimensions  : 10, 10, 100, 3  (nrow, ncol, ncell, nlayers)
## resolution  : 36, 18  (x, y)
## extent      : -180, 180, -90, 90  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0 
## data source : in memory
## names       :    layer.1,    layer.2,    layer.3 
## min values  : 0.01763912, 0.01018932, 0.24531431 
## max values  :  0.9933407,  0.9050321,  1.4268951

根据需要将median替换为meansd

方法2:uberlay

上面的方法似乎比较大的栅格减慢了很多。也许我做错了......另一种方法是更直接地致电mapply

uberlay <- function(..., fun) {
  fun <- match.fun(fun)
  L <- lapply(list(...), unstack)
  stack(do.call(mapply, c(FUN=function(...) calc(stack(...), fun), L)))
}

将RasterStack传递给...,将函数传递给fun

uberlay(s1, s2, s3, s4, fun='median')

## class       : RasterStack 
## dimensions  : 10, 10, 100, 3  (nrow, ncol, ncell, nlayers)
## resolution  : 36, 18  (x, y)
## extent      : -180, 180, -90, 90  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0 
## names       :    layer.1,    layer.2,    layer.3 
## min values  : 0.01763912, 0.01018932, 0.24531431 
## max values  :  0.9933407,  0.9050321,  1.4268951

方法3:superduperlay

@Joe mentioned uberlay方法需要大约一个小时的数据。对于大堆栈,可以更快地将堆栈强制转换为数组(或者,例如,data.table)并对其执行计算。

让我们使用@ Joe的维度创建一些假数据:

library(raster)
library(abind)

nc <- nr <- 17
nl <- 5829

s1 <- stack(replicate(nl, raster(matrix(runif(nr*nc), nr))))
s2 <- stack(replicate(nl, raster(matrix(runif(nr*nc), nr))))
s3 <- stack(replicate(nl, raster(matrix(runif(nr*nc), nr))))
s4 <- stack(replicate(nl, raster(matrix(runif(nr*nc), nr))))
s5 <- stack(replicate(nl, raster(matrix(runif(nr*nc), nr))))

首先,将堆栈强制转换为矩阵并绑定到三维数组。

A <- abind(as.matrix(s1), as.matrix(s2), as.matrix(s3), as.matrix(s4), as.matrix(s5), 
           along=3)

现在将您的函数应用于边距1:2,调整尺寸并进行转置,然后叠加回RasterBrick

z <- apply(A, c(1:2), median) # substitute median with desired function
dim(z) <- c(nr, nc, nl)
z <- apply(z, c(1, 3), t)
b <- brick(z)

整个过程(包括创建阵列)在我的系统上花费的时间仅为30秒({1}}和median。对于sd,您可以利用mean,加速时间不超过3秒。为方便起见,我们可以将这一切都包装成一个函数:

colMeans

每个对象都是superduperlay <- function(..., fun) { require(abind) require(raster) fun <- match.fun(fun) L <- list(...) A <- do.call(abind, c(lapply(L, as.matrix), along=3)) if(as.character(match.call()['fun'])=='mean') { A <- aperm(A, c(3, 1, 2)) z <- colMeans(A) } else { z <- apply(A, c(1:2), fun) } dim(z) <- c(nr, nc, nl) z <- apply(z, c(1, 3), t) b <- brick(z) } system.time(my_mean <- superduperlay(s1, s2, s3, s4, s5, fun='mean')) ## user system elapsed ## 2.68 0.04 2.72 system.time(my_median <- superduperlay(s1, s2, s3, s4, s5, fun='median')) ## user system elapsed ## 31.75 0.06 31.92 (如果需要可以强制为RasterBrickRasterStack),例如:

stack()