在 R 中插入光栅砖的时间序列的有效方法
Efficient way to interpolate time series of raster bricks in R
我有一些代表时间序列的大型光栅砖(每一层是一个时间点)。我希望通过在层之间进行插值来提高时间分辨率(在下面的示例中,插值使用 zoo::na.spline
,但如果有帮助,我愿意接受其他插值方法)。我不能直接在积木上使用 na.spline
- 它不是为此而设计的,只是给出 Error in as.array.default(X) : 'dimnames' applied to non-array
.
目前我正在使用一系列循环来执行此操作(第一个循环用于生成具有更多时间层的砖块,第二个循环用于将原始砖块插入正确的层,第三个循环用于在每个单元格上使用 na.spline)。然而,这在大块上非常慢,而且似乎是一种相当低效的方法。
一个最小的可重现示例。
首先让我们制作一个代表低时间分辨率数据的初始栅格砖。请注意,左上角的单元格始终为 NA,因为任何解决方案都必须对仅包含 NA 的单元格具有鲁棒性:
library(raster); library(rasterVis); library(zoo)
r1 = raster(matrix(c(NA, rep(1,8)), 3, 3))
r2 = raster(matrix(c(NA, rep(2,8)), 3, 3))
r3 = raster(matrix(c(NA, rep(3,8)), 3, 3))
b1 = brick(list(r1,r2,r3))
levelplot(b1)
现在,让我们创建一个空的光栅块来插入值:
b2 = brick(lapply(1:9, function(x) raster(matrix(NA, 3, 3))))
接下来我们将 b1
的层插入到 b2
的适当层中。请注意,我什至在这里使用了一个循环,因为 .
old.layers = c(1,4,7)
for (i in 1:nlayers(b1)) {
b2[[old.layers[i]]] = b1[[i]]
}
levelplot(b2, layout=c(9,1))
最后我们遍历每个单元格以进行时间序列插值并将结果插入回 b2
:
for (cell in 1:ncell(b2)) {
if (all(is.na(as.vector(b2[cell])))) {
# na.spline wil fail if all are NA
new.values = as.numeric(rep(NA, dim(b2)[3]))
} else {
new.values = na.spline(as.vector(b2[cell]), na.rm = F)
}
b2[cell][] = new.values
}
levelplot(b2, layout=c(9,1))
这可行,但似乎效率极低且不够优雅。有没有更快(最好也更优雅)的方法来做到这一点?
您可以将 raster::calc
与这样的函数一起使用:
yy <- rep(NA, 9)
fun <- function(y) {
if (all(is.na(y))) yy else na.spline((yy[c(1,4,7)] <- y), xout=1:9)
}
b2 <- calc(b1, fun)
供参考,raster::approxNA
接近你想要的(但它不添加层,并使用线性插值)。
我有一些代表时间序列的大型光栅砖(每一层是一个时间点)。我希望通过在层之间进行插值来提高时间分辨率(在下面的示例中,插值使用 zoo::na.spline
,但如果有帮助,我愿意接受其他插值方法)。我不能直接在积木上使用 na.spline
- 它不是为此而设计的,只是给出 Error in as.array.default(X) : 'dimnames' applied to non-array
.
目前我正在使用一系列循环来执行此操作(第一个循环用于生成具有更多时间层的砖块,第二个循环用于将原始砖块插入正确的层,第三个循环用于在每个单元格上使用 na.spline)。然而,这在大块上非常慢,而且似乎是一种相当低效的方法。
一个最小的可重现示例。
首先让我们制作一个代表低时间分辨率数据的初始栅格砖。请注意,左上角的单元格始终为 NA,因为任何解决方案都必须对仅包含 NA 的单元格具有鲁棒性:
library(raster); library(rasterVis); library(zoo)
r1 = raster(matrix(c(NA, rep(1,8)), 3, 3))
r2 = raster(matrix(c(NA, rep(2,8)), 3, 3))
r3 = raster(matrix(c(NA, rep(3,8)), 3, 3))
b1 = brick(list(r1,r2,r3))
levelplot(b1)
现在,让我们创建一个空的光栅块来插入值:
b2 = brick(lapply(1:9, function(x) raster(matrix(NA, 3, 3))))
接下来我们将 b1
的层插入到 b2
的适当层中。请注意,我什至在这里使用了一个循环,因为
old.layers = c(1,4,7)
for (i in 1:nlayers(b1)) {
b2[[old.layers[i]]] = b1[[i]]
}
levelplot(b2, layout=c(9,1))
最后我们遍历每个单元格以进行时间序列插值并将结果插入回 b2
:
for (cell in 1:ncell(b2)) {
if (all(is.na(as.vector(b2[cell])))) {
# na.spline wil fail if all are NA
new.values = as.numeric(rep(NA, dim(b2)[3]))
} else {
new.values = na.spline(as.vector(b2[cell]), na.rm = F)
}
b2[cell][] = new.values
}
levelplot(b2, layout=c(9,1))
这可行,但似乎效率极低且不够优雅。有没有更快(最好也更优雅)的方法来做到这一点?
您可以将 raster::calc
与这样的函数一起使用:
yy <- rep(NA, 9)
fun <- function(y) {
if (all(is.na(y))) yy else na.spline((yy[c(1,4,7)] <- y), xout=1:9)
}
b2 <- calc(b1, fun)
供参考,raster::approxNA
接近你想要的(但它不添加层,并使用线性插值)。