Я хочу умножить изображение Landsat с разрешением 30 м на растр ERA5 с разрешением около 25 км. Я могу уменьшить масштаб ERA5 до 30 м, но это увеличит обработку. Мне просто интересно, возможно ли, что какие бы 30-метровые ячейки ни пересекались с ячейкой 25 км, эти 30-метровые ячейки умножаются на одно значение из ячейки 25 км.
library(terra)
### 1st raster
ETrF <- rast(ncols=4, nrows=4, xmin=73, xmax=75, ymin=31, ymax=33)
### 2nd raster
ET0 <- rast(ncols=2, nrows=2, xmin=73, xmax=75, ymin=31, ymax=33)
### Random values assigned to both rasters
values(ETrF) <- c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8)
values(ET0) <- c(5,1,2,4)
### Now 1st cell of ET0 (value: 5) will overlap with 1st,2nd,5th and 6th cells (values: 0.1,0.2,0.5,0.6)
### of ETrF.Is it possible that 5 gets multiplied with 0.1,0.2,0.5 and 0.6 and final output
### keeps ETrFs resolution.
ETa <- ETrF*ET0.....?
Я считаю, что resample
— это правильный путь, возможно, использование аргумента threads
может повысить эффективность.
Альтернативным решением было бы извлечение значений из ET0
с использованием центроидов из ETrF
, но трудно сказать, насколько это повысит эффективность. Мне пришлось бы сравнить его с большим набором данных.
Вот возможный подход с использованием данных вашего примера.
library(terra)
library(sf)
library(dplyr)
ETrF_c <- st_as_sf(as.points(ETrF, values = TRUE)) # ETrF centroids
ETrF_new <- st_as_sf(extract(ET0, ETrF_c, bind = TRUE)) %>%
mutate(value = lyr.1*lyr.1.1) %>%
rasterize(., ETrF, field = 'value')
plot(ETrF_new)
И тебе спасибо. Ваше решение работает очень хорошо. Я высоко ценю быстрый ответ и ваши усилия.
Поскольку все согласны с resample()
, с моей точки зрения, это должно быть частью ответа, поэтому вот небольшой демонстратор, использующий {terra}
:
ET0_resampled <- resample(ET0, ETrF)
ET0_resampled
#> class : SpatRaster
#> dimensions : 4, 4, 1 (nrow, ncol, nlyr)
#> resolution : 0.5, 0.5 (x, y)
#> extent : 73, 75, 31, 33 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (CRS84) (OGC:CRS84)
#> source(s) : memory
#> name : lyr.1
#> min value : 1
#> max value : 5
ET0_resampled * ETrF
#> class : SpatRaster
#> dimensions : 4, 4, 1 (nrow, ncol, nlyr)
#> resolution : 0.5, 0.5 (x, y)
#> extent : 73, 75, 31, 33 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (CRS84) (OGC:CRS84)
#> source(s) : memory
#> name : lyr.1
#> min value : 0.275
#> max value : 3.200
С точки зрения производительности я не могу рекомендовать использовать подход «извлечение-мутация-растрирование» — каким бы креативным он ни был:
extract_mutate_rasterize <- function(coarse, fine) {
# centroids
fine_c <- as.points(fine, values = TRUE) %>% st_as_sf()
res <- extract(coarse, fine_c, bind = TRUE) %>%
st_as_sf() %>%
mutate(value = lyr.1 * lyr.1.1) %>%
rasterize(., fine, field = 'value')
res
}
microbenchmark::microbenchmark("terra::resample(threads = TRUE)" = terra::resample(ET0, ETrF, threads = TRUE) * ETrF,
"extract_mutate_rasterize @ FAmorim" = extract_mutate_rasterize(ET0, ETrF),
times = 500)
#> Unit: milliseconds
#> expr min lq mean median uq
#> terra::resample(threads = TRUE) 5.9338 6.40875 7.625009 7.1113 8.21190
#> extract_mutate_rasterize @ FAmorim 36.2193 41.15560 47.067254 45.7299 50.00195
#> max neval
#> 21.1489 500
#> 157.1793 500
... и я действительно не могу себе представить, чтобы это хорошо масштабировалось с увеличением количества ячеек.
Причина, по которой это не реализовано, заключается в том, что вам нужно выбрать способ повторной выборки данных; x * y
не могу это уловить.
В вашем случае билинейная интерполяция по умолчанию, вероятно, является наиболее разумным вариантом при использовании повторной выборки (если вам не нужны более сложные методы, использующие возвышение и другие копеременные).
Но он не дает тех же результатов, что и метод извлечения. (для этого нужно использовать resample( , method = "near")
). С данными игрушки вы также можете использовать disagg
.
Если вы хотите использовать маршрут извлечения, это можно сделать намного эффективнее, избегая приведения к sf, по крайней мере, в этом игрушечном примере:
fastextr <- function(coarse, fine, method = "simple") {
xy <- crds(fine)
value <- extract(coarse, xy, method=method) * values(fine)
rasterize(xy, fine, value)
}
microbenchmark::microbenchmark(
"res" = terra::resample(ET0, ETrF, "near", threads = TRUE) * ETrF,
"mutat" = extract_mutate_rasterize(ET0, ETrF),
"disagg" = terra::disagg(ET0, 2) * ETrF,
"fextr" = fastextr(ET0, ETrF),
times = 50
)
#Unit: milliseconds
# expr min lq mean median uq max neval
# res 6.2586 6.4362 6.948614 6.67490 6.8020 21.1767 50
# mutat 38.6304 39.4301 40.627638 40.08070 41.1208 58.3876 50
# disagg 4.5824 4.6490 5.158002 4.77420 4.9126 21.7821 50
# fextr 7.9329 8.1154 8.468164 8.44225 8.6150 11.1409 50
Поэтому лучший вариант — использовать билинейную передискретизацию.
bres <- terra::resample(ET0, ETrF, "bilinear", threads = TRUE) * ETrF
Тот же результат можно получить с помощью билинейного экстракта
bextr <- fastextr(ET0, ETrF, "bilinear")
Этот подход извлечения не намного медленнее, чем подход повторной выборки в этом примере. Но я бы не стал использовать метод извлечения, поскольку он может вызвать проблемы с выделением памяти, если вы используете большие растровые данные.
Спасибо за указание, что method = "bilinear"
будет использоваться по умолчанию при использовании project()
здесь, и поэтому результат будет отличаться от extract_mutate_rasterize()
.
Спасибо, что указали на использование crds
, так как это намного эффективнее!
Большое спасибо. Я пытаюсь использовать ETrF модели METRIC в качестве коэффициента обрезки (Kc) и умножить его на эталонное ET, чтобы получить фактическое ET. Проблема: у меня нет доступа к данным наблюдений за погодой, поэтому я подумал вместо этого использовать данные климатических моделей. Да, вероятно, лучше всего использовать повторную выборку с использованием подхода ближайшего соседа, поскольку он сохраняет исходное значение ячейки для всех уменьшенных ячеек в этой области. Я избегаю дополнительной обработки, иначе я знаю, что могу уменьшить масштаб климатических данных в ArcGIS, используя криггинг и DEM в качестве копеременных.
Вы также можете сделать это в R. Смотри terra::interpolate
Не эксперт, но читали ли вы документацию
raster::resample
? Сделал бы(ET0v1 = raster::resample(ET0, ETrF)); ETa = ETrF * ET0v1; par(mfrow = c(1L, 3L)); X = lapply(list(ETrF, ET0, ETa), plot)
(или в другом порядке) то, что вам нужно?