如何用R的raster/terra包中focal函数实现IDW填充NA值?
高效实现栅格NA值的反距离权重(IDW)填充(基于9个最近邻)
针对大栅格的NA填充需求,推荐用terra包的批量最近邻查找+手动IDW计算方案,比gstat的idw效率提升显著,同时能自动获取9个最近的有效单元格,不受固定窗口限制。
步骤1:准备示例数据(转terra格式)
先把示例栅格转为terra的SpatRaster(terra性能远优于旧raster包):
library(terra) # 生成示例栅格 r <- rast(nrow = 20, ncol = 20) r[1:300] <- sample(1:4, size = 300, replace = TRUE) plot(r) # 标记待填充的NA位置 gaps_cells <- c(310, 330) gaps_xy <- xyFromCell(r, gaps_cells) points(gaps_xy, pch = 16, col = "red")
步骤2:提取有效点与NA点数据
把栅格中的非NA点和待填充NA点提取为矢量数据:
# 提取所有非NA单元格的坐标和值 valid_pts <- as.points(r, na.rm = TRUE) valid_vals <- values(valid_pts)[,1] valid_coords <- crds(valid_pts) # 提取所有NA单元格的坐标 na_cells <- which(is.na(values(r))) na_coords <- xyFromCell(r, na_cells)
步骤3:查找每个NA点的9个最近有效点
用terra::nearest批量查找最近邻(基于空间索引,效率极高):
# 返回每个NA点对应的9个最近有效点的索引 nn_idx <- nearest(na_coords, valid_coords, k = 9)
步骤4:计算IDW权重并填充NA
这里用距离的倒数作为权重(可改为1/d²,即IDW常用的幂次参数idp=2),再计算加权平均值:
# 计算每个NA点到9个最近点的距离 distances <- distance(na_coords, valid_coords[nn_idx, ]) # 计算权重(加极小值避免距离为0的情况) weights <- 1 / (distances + 1e-10) # 归一化权重,确保权重和为1 weights <- weights / rowSums(weights) # 计算加权平均值 filled_vals <- rowSums(valid_vals[nn_idx] * weights) # 将填充值赋值回原栅格 r_filled <- r values(r_filled)[na_cells] <- filled_vals
步骤5:查看结果
plot(r_filled) points(gaps_xy, pch = 16, col = "red")
核心优势
- 效率碾压:terra的底层C++实现,批量处理14000个NA点仅需几秒,远快于gstat逐点调用
idw的方式。 - 动态范围:无需固定窗口,自动找到距离最近的9个有效单元格,不管这些点的位置。
- 灵活可调:可轻松修改权重计算方式、调整最近邻数量。
简化方案:用terra::interpolate
如果偏好更简洁的插值函数写法,也可以用terra结合gstat的IDW模型:
library(gstat) # 构建IDW模型,设置nmax=9,idp=1对应倒数权重(idp=2对应平方倒数) idw_model <- gstat(formula = lyr1 ~ 1, data = valid_pts, nmax = 9, set = list(idp = 1)) # 插值填充NA r_filled2 <- interpolate(r, idw_model) # 保留原栅格的非NA值 r_filled2 <- cover(r_filled2, r)
这个方案代码更简洁,但效率略低于手动计算的方案。
内容的提问来源于stack exchange,提问作者silasprincipe
相关产品推荐
相关产品推荐

