如何在R中正确裁剪()栅格数据范围

时间:2017-05-07 04:49:06

标签: r r-raster

我正在尝试裁剪一些raster data并进行一些计算(getting the mean sea surface temperature,具体而言)。

但是,在比较裁剪之前,在进行计算之前,栅格数据的范围与在裁剪结果数据之前进行计算的结果相同。

栅格数据的原始范围是-180, 180, -90, 90 (xmin, xmax, ymin, ymax),我需要将其裁剪到由纬度和经度坐标定义的任何所需区域。

这是我正在测试的脚本:

library(raster) # Crop raster data
library(stringr)

# hadsstR functions ----------------------------------------
load_hadsst <- function(file = "./HadISST_sst.nc") {
    b <- brick(file)
    NAvalue(b) <- -32768 # Land
    return(b)
}

# Transform basin coordinates into numbers
morph_coords <- function(coords){
    coords[1] = ifelse(str_extract(coords[1], "[A-Z]") == "W", - as.numeric(str_extract(coords[1], "[^A-Z]+")),
                                         as.numeric(str_extract(coords[1], "[^A-Z]+")) )
    coords[2] = ifelse(str_extract(coords[2], "[A-Z]") == "W", - as.numeric(str_extract(coords[2], "[^A-Z]+")),
                                         as.numeric(str_extract(coords[2], "[^A-Z]+")) )
    coords[3] = ifelse(str_extract(coords[3], "[A-Z]") == "S", - as.numeric(str_extract(coords[3], "[^A-Z]+")),
                                         as.numeric(str_extract(coords[3], "[^A-Z]+")) )
    coords[4] = ifelse(str_extract(coords[4], "[A-Z]") == "S", - as.numeric(str_extract(coords[2], "[^A-Z]+")),
                                         as.numeric(str_extract(coords[4], "[^A-Z]+")) )
    return(coords)
}

# Comparison test ------------------------------------------
hadsst.raster <- load_hadsst(file = "~/Hadley/HadISST_sst.nc")

x <- hadsst.raster
nms <- names(x)
months <- c("01","02","03","04","05","06","07","08","09","10","11","12")
coords <- c("85E", "90E", "5N", "10N")
coords <- morph_coords(coords)
years = 1970:1974
range = 5:12

# Crop before calculating mean
x <- crop(x, extent(as.numeric(coords[1]), as.numeric(coords[2]),
                                        as.numeric(coords[3]), as.numeric(coords[4])))
xMeans <- vector(length = length(years)-1,mode='list')
for (ix in seq_along(years[1:length(years)])){
    xMeans[[ix]] <- mean(x[[c(sapply(range,function(x) grep(paste0(years[ix],'.',months[x]),nms)))]], na.rm = T)
}
mean.brick1 <- do.call(brick,xMeans)

# Calculate mean before cropping
x <- hadsst.raster
xMeans <- vector(length = length(years)-1,mode='list')
for (ix in seq_along(years[1:length(years)])){
    xMeans[[ix]] <- mean(x[[c(sapply(range,function(x) grep(paste0(years[ix],'.',months[x]),nms)))]], na.rm = T)
}
mean.brick2 <- do.call(brick,xMeans)
mean.brick2 <- crop(mean.brick2, extent(as.numeric(coords[1]), as.numeric(coords[2]),
                                                                                as.numeric(coords[3]), as.numeric(coords[4])))

# Compare the two rasters
mean.brick1 - mean.brick2

这是mean.brick1 - mean.brick2

的输出
class       : RasterBrick 
dimensions  : 5, 5, 25, 5  (nrow, ncol, ncell, nlayers)
resolution  : 1, 1  (x, y)
extent      : 85, 90, 5, 10  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 
data source : in memory
names       : layer.1, layer.2, layer.3, layer.4, layer.5 
min values  :       0,       0,       0,       0,       0 
max values  :       0,       0,       0,       0,       0

正如你所看到的,两个RasterBricks完全相同,对于任意选择的坐标都不可能,如下面用一个小矩阵所示:

enter image description here

我做错了什么?在使用它们进行计算之前裁剪数据应该明确地给出不同的结果。

1 个答案:

答案 0 :(得分:3)

好的,我将在上一个问题中继续post

我们从完整的hadsst.raster砖开始(对于具有可重复的示例,可以在我之前的答案中使用我的解决方案的第一部分进行伪造)。

因此,此数据集的维度为180, 360, 516,表示180行,360列和516个时间层。

从技术上讲,光栅是一个矩阵,这可能是它的样子:

raster

只是一堆矩阵层(准确地说是516),其中每个像素都是精确对齐的。这里我只有三个示例图层,其余部分由三个点表示。

因此,如果我们进行时间平均,我们基本上提取单个像素的所有值并采用它们的均值(或任何其他平均操作)。这由红色方块表示。

这也说明了为什么裁剪影响时间平均的原因:

如果我们说橙色方块是我们感兴趣的程度,并且我们在平均之前执行裁剪操作,我们基本上会丢弃此方块周围的所有值。之后,我们再次获取所有图层上每个像素的所有值并执行平均值。

现在应该清楚了,为什么当你丢弃橙色方块周围的像素时它并不重要。您还可以计算它们的平均值,然后丢弃这些值,只留下橙色方块的值。如果你已经确定你不需要它们进行进一步的计算,它就没有任何意义。 无论如何,广场内的价值不会受到影响。

当我们谈论空间平均时,它通常意味着对单个图层中的像素求平均值,在这种情况下可能超过橙色矩形内的值。

两个常见的操作是

  • 焦点平均(也称为邻域平均)
  • 聚合

焦点平均将对每个像素采用定义数量的相邻像素的所有值的平均值(最常见的是3x3平方,其中要定义的像素是中心像素。 / p>

聚合实际上是采用多个像素并将它们组合成更大的像素。这意味着不仅会对此像素的值进行平均,而且还会使得到的栅格具有较少的单个像素和较粗糙的分辨率。

好的,为您找到实际的解决方案:

我假设您有一个由范围aoi定义的感兴趣区域:

aoi <- extent(xmin,xmax,ymin,ymax)

你要做的第一件事是裁剪初始砖块以减少计算负担:

hadsst.raster_crp <- crop(hadsst.raster,aoi)

下一步是时间平均,我们使用我在其他post的解决方案中定义的函数:

hadsst.raster_crp_avg <- hadSSTmean(hadsst.raster_crp, 1969:2011, first.range = 11:12, second.range = 1:4)

好的,现在您的时间平均值仅适用于您感兴趣的区域。下一步取决于您的最终目标。 据我所知,您只需要为您感兴趣的区域提供每个时间平均值的单一平均值。

如果是这种情况,可能是离开实际栅格域并继续使用基础R的正确时间:

res <- lapply(1:nlayers(hadsst.raster_crp_avg),function(ix) mean(as.matrix(hadsst.raster_crp_avg[[ix]])))

这将为您提供一个列表,其中包含与您的hadsst.raster_crp_avg砖一样多的元素。

使用lapply,我们遍历图层,将每个图层转换为矩阵,然后计算所有元素的平均值,为整个感兴趣的区域留下每个平均时间步长的单个值。

更进一步,您可以使用unlist将其转换为向量,并将其添加到data.frame或执行您喜欢的任何其他操作。

希望这很清楚,这就是你要找的东西。

最佳