Использование функции sapp() для нанесения terra::focal на каждый слой шпателя

#r #geospatial #terra

Вопрос:

Я недавно начал использовать terra и должен поблагодарить разработчиков, это значительно облегчило мою жизнь при работе со многими большими растрами в R. Однако я столкнулся с незначительной проблемой, я sapp пытаюсь применить focal функцию к каждому слою в распылителе, focal которую можно применять только к одному слою за раз.

С помощью небольшого воспроизводимого растрового изображения я могу запустить следующее в качестве примера желаемого результата:

 library(terra)
packageVersion("terra")
>[1] ‘1.2.10’
    
s <- rast(system.file("ex/logo.tif", package="terra"))
s <- ifel(s == 255, 1, NA)

r1 <- terra::focal(s[[1]], w=3, fun = "any", na.only=TRUE)
r2 <- terra::focal(s[[2]], w=3, fun = "any", na.only=TRUE)
r3 <- terra::focal(s[[3]], w=3, fun = "any", na.only=TRUE)
r <- c(r1,r2,r3)
r

#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. :  proj=merc  lon_0=0  k=1  x_0=0  y_0=0  datum=WGS84  units=m  no_defs 
#sources     : memory  
#              memory  
#              memory  
#names       : red, green, blue 
#min values  :   0,     0,    0 
#max values  :   1,     1,    1 
 

Когда я бегу sapp за вышеуказанными воспроизводимыми данными, используя ту же грамматику, что и sapply :

 f1 <- sapp(s, fun = function(x){terra::focal(x = x, w = 3, fun = "any", na.only = TRUE)})
 

Я получаю:

Ошибка в h(simpleError(msg, вызов)) : ошибка при вычислении аргумента » x «при выборе метода для функции «rast»: неиспользуемый аргумент (wopt = wopt)

Если я попытаюсь:

 f <- sapp(s,  terra::focal, c(w= 3, fun = "any", na.only = TRUE))
f
 

Я получаю следующее:

 #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. :  proj=merc  lon_0=0  k=1  x_0=0  y_0=0  datum=WGS84  units=m  no_defs 
#source      : memory 
#names       : red, green, blue 
#min values  :   0,     0,    0 
#max values  :   9,     9,    9 
 

Обратите внимание на максимальные значения слоев. Как я могу настроить свой код, чтобы приложение работало по желанию?

Я могу получить желаемый результат с помощью sapply, но я предполагаю, что sapp будет гораздо эффективнее для больших данных, если я смогу заставить его работать.

 f2 <- sapply(as.list(s), function(x){terra::focal(x = x, w= 3, fun = "any", na.only = TRUE)})
f2 <- rast(f2)
f2
#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. :  proj=merc  lon_0=0  k=1  x_0=0  y_0=0  datum=WGS84  units=m  no_defs 
#sources     : memory  
               memory  
               memory  
#names       : red, green, blue 
#min values  :   0,     0,    0 
#max values  :   1,     1,    1 
 

Если кто-нибудь может оказать некоторую помощь, мы будем очень признательны 🙂

Ответ №1:

Я решил свою проблему.

Оказывается, вам нужно включить ... аргумент в функцию, отправленную fun таким образом:

 s <- sapp(s, fun = function(x, ...) {focal(x, fun = "any", w = 3)})
 

Тогда это работает

Как выясняется sapp , вызывает sapply внутренне и еще не реализовал распараллеливание, и несколько ядер не могут быть выделены, поэтому не так много улучшений в скорости по сравнению с app тем, что реализует распараллеливание vs apply .

Вот некоторые ориентиры, если какой-либо орган заинтересован…

 terra::terraOptions(todisk = TRUE)
s <- rast(system.file("ex/logo.tif", package="terra"))
s <- terra::extend(s, c(500, 500))
s <- disaggregate(s, 10)
s <- terra::ifel(s == 255, 1, 0)

a <- function() {
    s <- sapply(as.list(s), function(x){terra::focal(x = x, w= 3, fun = "any")})
    s <- rast(s)}

b <- function(){
    s <- sapp(s, fun = function(x,...) {focal(x, fun = "any", w = 3)})}


race <- microbenchmark::microbenchmark(
    a(),
    b(),
    times = 5)
 

Результаты:

 race
Unit: seconds
 expr      min       lq     mean   median       uq      max neval cld
  a() 63.32553 63.93399 65.03783 65.61699 65.73256 66.58011     5   a
  b() 62.88114 63.85961 64.34571 64.16861 65.22703 65.59215     5   a