多级栅格列表 - 在 R 中执行代数

Multi-level list of rasters - performing algebra in R

我有一个多级栅格列表,如何有效地对此类结构进行操作总是让我头疼。我想根据索引从列表第三层的栅格中取平均值。例如:

# make some dummy rasters
a <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
a[] <- sample(1:5,25,replace=T)
b <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
b[] <- sample(1:5,25,replace=T)
c <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
c[] <- sample(1:5,25,replace=T)
d <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
d[] <- sample(1:5,25,replace=T)
e <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
e[] <- sample(1:5,25,replace=T)
f <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
f[] <- sample(1:5,25,replace=T)
g <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
g[] <- sample(1:5,25,replace=T)
h <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
h[] <- sample(1:5,25,replace=T)
i <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
i[] <- sample(1:5,25,replace=T)
j <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
j[] <- sample(1:5,25,replace=T)
k <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
k[] <- sample(1:5,25,replace=T)
l <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
l[] <- sample(1:5,25,replace=T)

)

list_abcd <- list(a,b,c,d)
list_efgh <- list(e,f,g,h)
list_ijkl <- list(i,j,k,l)

list_all <- list(list_abcd,list_efgh,list_ijkl)

我想对栅格执行计算以获得列表中各个第一个栅格的平均值(a,e and i 的平均值), 第二 (b,f and j)、第三 (c,g,k) 和第四 (d, h and l)。

结果将是一个包含 4 个栅格的列表。

实际上,我有一个这样结构的列表,包含 10 个组,每个组有 100 多个栅格,因此解决方案需要可扩展。


其他信息 我使用 NetCDF 文件,它们的结构如下所示(如下)。我创建了多级列表来处理它,但后来很头疼如何在没有太多费力的 for 循环的情况下很好地处理它。

3 variables:
    double var1[lon,lat,years,irr]
    double var2[lon,lat,years,irr]
    double var3[lon,lat,years,irr]
 4 dimensions:
    lon  Size:720
        units: degrees_east
        long_name: lon
    lat  Size:360
        units: degrees_north
        long_name: lat
    years  Size:100
        units: mapping
        long_name: years
    irr  Size:2
        units: mapping
        long_name: rainfed/irrigated

您的示例数据

library(raster)
r <- raster(xmn=0,xmx=5,ymn=0,ymx=5,res=1)
set.seed(123)
list_abcd <- replicate(4, setValues(r, sample(1:5,25,replace=T)))
list_efgh <- replicate(4, setValues(r, sample(1:5,25,replace=T)))
list_ijkl <- replicate(4, setValues(r, sample(1:5,25,replace=T)))   
list_all <- list(list_abcd,list_efgh,list_ijkl)
names(list_all) <- c("abcd", "efgh", "ijkl")

解决方案,创建单个 RasterStack 并使用 stackApply

x <- stack(unlist(list_all))
i <- rep(1:4, 3)
s <- stackApply(x, i, mean)
s
#class      : RasterBrick 
#dimensions : 5, 5, 25, 4  (nrow, ncol, ncell, nlayers)
#resolution : 1, 1  (x, y)
#extent     : 0, 5, 0, 5  (xmin, xmax, ymin, ymax)
#crs        : +proj=longlat +datum=WGS84 +no_defs 
#source     : memory
#names      :  index_1,  index_2,  index_3,  index_4 
#min values : 1.333333, 2.000000, 1.000000, 1.666667 
#max values : 4.666667, 5.000000, 4.666667, 4.333333 

现在让我们用 terraraster 的替换)来做这件事。我们从三个 SpatRaster 开始(类似于 RasterStack)

library(terra)
rr <- rast(xmin=0,xmax=5,ymin=0,ymax=5,res=1)
set.seed(123)
abcd <- replicate(4, setValues(rr, sample(1:5,25,replace=T))) |> rast()
efgh <- replicate(4, setValues(rr, sample(1:5,25,replace=T))) |> rast()
ijkl <- replicate(4, setValues(rr, sample(1:5,25,replace=T))) |> rast()
# the above is equivalent to: abcd <- c(a,b,c,d)

解决方案 1:合并为一个 SpatRaster 并使用 tapp

rall <- c(abcd, efgh, ijkl) 
z1 <- tapp(rall, rep(1:4, 3), "mean")

解决方案 2:组合成 SpatRasterDataset 并使用 app

rsd <- sds(abcd, efgh, ijkl) 
z2 <- app(rsd, "mean")

方案三:直接使用mean

z3 <- mean(abcd, efgh, ijkl) 

稍后:从你的评论中我了解到你犯的错误确实是在创建这些列表时。如果我理解你的话,你有 n 个代表模型的文件,每个文件有 2*100 层;并且您想要跨模型平均每一层的值(年份和水状况);这样您最终会得到一个包含 200 个图层的栅格数据集(或 2 个包含 100 个图层的数据集)。你可以通过这样的方式实现:

 library(terra)
 ff <- list.files(pattern="nc$")  
 sd <- sds(ff)
 x <- app(sd, mean)

或者,如果 irrigated/rainfed 是分开的 sub-datasets,比如

 library(terra)
 ff <- list.files(pattern="nc$")  
 sd <- lapply(ff, \(i) rast(i, "irrigated")) |> sds()
 # or sd <- lapply(ff, \(i) rast(i, 1)) |> sds()
 x <- app(sd, mean)

一些示例数据

f <- system.file("ex/logo.tif", package="terra")
sd <- sds(c(f,f,f))
x <- app(sd, mean)