Search code examples
rterra

R function or approach for calculating a mean raster layer from a list of rasters?


I have a list of multilayer rasters (e.g., stacks) with matching extents and layer names, and I need to average them to create a single stack retaining the appropriate layers. This can easily be achieved by manually removing each raster from the list and simply using terra::mean(stack.1, stack.2, na.rm = T).

Unfortunately, I have to do this repeatedly with numerous files and need an omnibus solution. I am also aware that I can use terra::rast() on a list of rasters to create a single stack, and could take the mean of this object, but this approach averages all layers resulting in only a single layer, rather than a stack of averaged layers. Similarly, lapply() and do.call() are not helpful because these apply functions to each element in the list, not all elements collectively. I would greatly appreciate any suggestions.

Code sample:

# Structure of stacks
stack.1
class       : SpatRaster 
dimensions  : 776, 720, 6  (nrow, ncol, nlyr)
resolution  : 0.6, 0.6  (x, y)
extent      : 278110.2, 278542.2, 4752927, 4753393  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / UTM zone 16N (EPSG:32616) 
source      : pepr.2022.100.tif 
names       : preds~_temp, preds~_temp, preds~_temp, preds~vapor, preds~vapor, preds~vapor 
min values  :   -2.074884,    29.46503,    7.464921,   -118.1709,    2325.729,    984.7896 
max values  :    1.352281,    43.14127,   11.517185,    128.4751,    2929.794,   1289.9479

# Listed
stack.list <- list(stack.1, stack.2, stack.3)

# Desired result, a stack containing the same layers that have been averaged
mean(stack.1, stack.2, stack.3, na.rm =T)
class       : SpatRaster 
dimensions  : 776, 720, 6  (nrow, ncol, nlyr)
resolution  : 0.6, 0.6  (x, y)
extent      : 278110.2, 278542.2, 4752927, 4753393  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / UTM zone 16N (EPSG:32616) 
source(s)   : memory
names       : preds~_temp, preds~_temp, preds~_temp, preds~vapor, preds~vapor, preds~vapor 
min values  :   -1.928547,    29.14394,    5.955294,   -115.4321,    2044.692,    941.3278 
max values  :    1.215450,    38.19327,    9.235113,    127.4777,    2525.456,   1166.1364
  

Solution

  • You can create a SpatRasterDataset and then use terra::app

    Example data

    r <- rast(system.file("ex/logo.tif", package="terra"))   
    x <- list(r, r*10, r*100)
    

    Solution

    s <- sds(x)
    app(s, mean)
    #class       : SpatRaster 
    #dimensions  : 77, 101, 3  (nrow, ncol, nlyr)
    #resolution  : 1, 1  (x, y)
    #extent      : 0, 101, 0, 77  (xmin, xmax, ymin, ymax)
    #coord. ref. : Cartesian (Meter) 
    #source(s)   : memory
    #names       :  red, green, blue 
    #min values  :    0,     0,    0 
    #max values  : 9435,  9435, 9435 
    

    "manual approach" for comparison

    minmax(mean(r, r*10, r*100))
    #     red green blue
    #min    0     0    0
    #max 9435  9435 9435