使用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) }
- 若需要物种存在概率(Pres类的概率),修改预测函数直接返回概率值:
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
相关产品推荐
相关产品推荐

