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

使用caret训练的ranger模型结合terra::predict生成物种分布栅格报错求助

物种分布模型预测问题排查与解决思路

问题背景与现象

  • 基于存在点/伪缺失点开展物种分布研究,通过caret::train结合10折交叉验证训练了method="ranger"的集成模型
  • 使用包含WorldClim生物气候数据、地形数据(海拔/坡度)、土地利用及地质类型分类栅格的栅格栈,调用terra::predict生成物种存在概率栅格时,触发**"Missing data in columns"**报错;此前使用无交叉验证的randomForest模型可正常运行
  • 示例代码中执行预测时出现错误:Error in predict(...)$predictions : $ operator is invalid for atomic vectors
  • 核心目标:生成物种分布概率栅格,并支持仅替换气候栅格实现当前及未来物种分布预测

示例代码

数据准备

library(terra)
library(caret)
library(tuneRanger)
library(ranger)

logo <- rast(system.file("ex/logo.tif", package="terra"))   
logo[75:77, ] <- NA
p <- matrix(c(48, 48, 48, 53, 50, 46, 54, 70, 84, 85, 74, 84, 95, 85, 
              66, 42, 26, 4, 19, 17, 7, 14, 26, 29, 39, 45, 51, 56, 46, 38, 31, 
              22, 34, 60, 70, 73, 63, 46, 43, 28), ncol=2)

a <- matrix(c(22, 33, 64, 85, 92, 94, 59, 27, 30, 64, 60, 33, 31, 9,
              99, 67, 15, 5, 4, 30, 8, 37, 42, 27, 19, 69, 60, 73, 3, 5, 21,
              37, 52, 70, 74, 9, 13, 4, 17, 47), ncol=2)
xy <- rbind(cbind(1, p), cbind(0, a))
e <- extract(logo, xy[,2:3])
v <- data.frame(cbind(pa=xy[,1], e))

模型构建

v_NA_kNN <- caret::preProcess(v, method="bagImpute")
v_rf <- predict(v_NA_kNN,v)

v_rf$pa <- as.factor(v_rf$pa)
levels(v_rf$pa) <- c("Pres","Abs")

rf.task <-  makeClassifTask(data = v_rf, target = "pa")
res <- tuneRanger(rf.task, measure = list(multiclass.brier), num.trees = 1e+02,
                  num.threads = 4, iters = 20, save.file.path = NULL)

fitControl <- caret::trainControl(
  method = "repeatedcv", 
  number = 5,             
  repeats = 5,            
  allowParallel = T,
  classProbs=T,
  returnData = T,
  savePredictions = "final"
)

ranger_model <- caret::train(
  v_rf[,-1],     
  as.factor(v_rf$pa),
  method = "ranger",
  trControl = fitControl,
  tuneGrid = expand.grid(mtry = res$recommended.pars[,1],
                         min.node.size = res$recommended.pars[,2],
                         splitrule = "gini"),
  num.trees = 1e+02,
  num.threads = 4,
  importance = 'impurity'
)

预测代码及报错

predfun <- function(...) predict(...)$predictions
x <- terra::predict(logo, ranger_model, fun=predfun)
# Error in predict(...)$predictions : 
#  $ operator is invalid for atomic vectors
# Called from: fun(model, d, ...)

解决思路与技巧

1. 修复示例代码的$ operator is invalid for atomic vectors错误

  • 问题本质:caret训练的ranger模型,调用predict()返回的是原子向量(分类结果或概率向量),而非带$predictions属性的列表,自定义函数中的$predictions调用无意义。
  • 修正方案:
    • 若需要物种存在概率(Pres类的概率),修改预测函数直接返回概率值:
      predfun <- function(model, data) {
        # 指定type="prob"获取概率矩阵,提取Pres类的概率
        predict(model, data, type = "prob")$Pres
      }
      x <- terra::predict(logo, ranger_model, fun = predfun)
      
    • 若只需分类结果(Pres/Abs),简化预测函数:
      predfun <- function(model, data) {
        predict(model, data)
      }
      

2. 解决真实项目的"Missing data in columns"报错

  • 核心原则:确保栅格栈与训练数据的特征列名、数据类型、缺失值处理、分类变量水平完全一致
    • 列名一致性检查:
      对比训练数据特征列名与栅格栈图层名,确保大小写、拼写完全匹配:
      # 查看训练数据的特征列名
      colnames(v_rf[,-1])
      # 查看栅格栈的图层名
      names(raster_stack)
      
    • 缺失值处理对齐:
      训练时用bagImpute填充了缺失值,预测时必须对栅格栈应用相同的预处理规则:
      # 对栅格栈应用训练好的预处理对象
      raster_stack_imputed <- terra::predict(raster_stack, v_NA_kNN)
      
    • 分类变量水平一致性:
      检查土地利用、地质类型等分类栅格的类别,确保与训练数据中的类别完全一致(无新增类别),可通过levels()查看并统一:
      # 查看训练数据中分类变量的水平
      levels(v_rf$land_use)
      # 查看栅格的类别水平
      levels(raster_stack$land_use)
      
    • 特征顺序与数量匹配:
      确保栅格栈的特征顺序、数量与训练数据一致,可通过模型的coefnames属性验证:
      # 查看模型期望的特征列表
      ranger_model$coefnames
      
    • 数据类型匹配:
      对比训练数据特征的类型(数值/因子)与栅格数据类型,确保一致:
      # 查看训练数据特征类型
      str(v_rf[,-1])
      # 查看栅格数据类型
      terra::typeof(raster_stack)
      

3. 替换气候栅格实现多场景预测的技巧

  • 固定非气候栅格(地形、土地利用、地质类型等),仅替换气候图层,确保新栅格栈的列名、顺序与训练数据一致:
    # 假设base_stack是地形+土地利用+地质类型的固定栅格栈
    current_climate <- rast("current_worldclim.tif")
    future_climate <- rast("future_worldclim.tif")
    
    # 拼接当前场景栅格栈并对齐列名
    current_stack <- c(base_stack, current_climate)
    names(current_stack) <- colnames(v_rf[,-1])
    
    # 应用预处理并预测
    current_stack_imputed <- terra::predict(current_stack, v_NA_kNN)
    current_pred <- terra::predict(current_stack_imputed, ranger_model, fun = predfun)
    
    # 未来场景同理
    future_stack <- c(base_stack, future_climate)
    names(future_stack) <- colnames(v_rf[,-1])
    future_stack_imputed <- terra::predict(future_stack, v_NA_kNN)
    future_pred <- terra::predict(future_stack_imputed, ranger_model, fun = predfun)
    

内容的提问来源于stack exchange,提问作者Joshua Borrás

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:34:58