You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用terra::focal自定义函数遇类型转换错误,求矩阵替代方案

移动窗口自定义函数报错及替代方案

我需要在移动窗口中运行一个自定义函数,之前用terra::focal成功过,但现在遇到错误:

Error in as.vector(x, "character") : cannot coerce type 'closure' to vector of type 'character'

查相关案例提示可能是函数名缺括号,但加括号后又出现新错误。我不一定非要用terra::focal,也接受在矩阵上运行、效率相当的替代方案,且不想来回转换矩阵和SpatRaster(因为不是空间工作流)。

示例代码:

# Custom function: if mean of the window is greater than the threshold 
# then return the value unchanged, otherwise return the minimum value in the window.
# (Returning value number 14, as this is the central cell in a 9 x 3 window)
mean.or.min <- function(x, ...){
  if(mean(x) > 10) {
    return(x[[14]])
  } else {
    x[[14]] <- min(x)
    return(x[[14]])
  }
}


# Create example data
set.seed(42)
temp.matrix <- matrix(data = sample(1:30, 600000, replace = TRUE), nrow = 200)

# Convert matrix to a spatRaster
temp.rast <- terra::rast(temp.matrix)

# Moving window
temp.rast.smoothed <- terra::focal(temp.rast, w = c(9,3), fun = mean.or.min, fillvalue = 0,  expand = TRUE)

一、修复terra::focal的用法问题

报错核心原因是terra::focal传递给自定义函数的x是数值向量,而非列表,你用的x[[14]]是列表索引写法,应改为向量索引x[14]。另外expand = TRUE参数在当前terra版本中已不适用,需移除。

修改后的代码:

mean.or.min <- function(x, ...){
  if(mean(x) > 10) {
    return(x[14])  # 向量用[]索引,而非[[ ]]
  } else {
    return(min(x))  # 无需修改x元素,直接返回窗口最小值
  }
}

# 调用focal时移除无效的expand参数
temp.rast.smoothed <- terra::focal(temp.rast, w = c(9,3), fun = mean.or.min, fillvalue = 0)

二、直接在矩阵上运行的替代方案(推荐)

使用RcppRoll包的滑动窗口函数,底层基于C++实现,效率和terra::focal相当,且无需转换空间对象:

  1. 安装并加载包
install.packages("RcppRoll")
library(RcppRoll)
  1. 实现矩阵滑动窗口逻辑
set.seed(42)
temp.matrix <- matrix(data = sample(1:30, 600000, replace = TRUE), nrow = 200)

# 定义9×3窗口的滑动处理函数
matrix_focal <- function(mat, window_rows = 9, window_cols = 3, threshold = 10) {
  # 计算窗口内中心元素的位置
  center_pos <- (ceiling(window_cols/2)-1)*window_rows + ceiling(window_rows/2)
  
  # 滑动窗口处理
  result <- RcppRoll::rollapply(mat, 
                                width = c(window_rows, window_cols),
                                FUN = function(x) {
                                  if(mean(x) > threshold) x[center_pos] else min(x)
                                },
                                fill = 0,
                                align = "center")
  return(result)
}

# 运行得到处理后的矩阵
temp.matrix.smoothed <- matrix_focal(temp.matrix, 9, 3, 10)

说明

  • align = "center"确保窗口以当前元素为中心,和terra::focal默认行为一致
  • fill = 0对应原代码的边缘填充值设置
  • 大矩阵场景下,RcppRoll的执行效率和terra持平,且省去了空间对象转换的步骤

内容的提问来源于stack exchange,提问作者EcologyTom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 13:35:08