使用 terra::p redict 和 caret::train 护林员模型生成物种分布的预测栅格

Generate a prediction raster for a species distribution using terra::predict and caret::train ranger model

提问人:Joshua Borràs 提问时间:10/28/2023 最后编辑:Robert HijmansJoshua Borràs 更新时间:11/21/2023 访问量:76

问:

我有一个物种分布项目正在进行中,包括存在和伪缺席/背景点。我已经设置了一个数据帧并使用 10 k 倍的 caret::train 训练了一个模型,并且我使用 method=“ranger” 让生活更轻松。所以,现在我有一个平均的游侠模型。

现在,这就是我遇到障碍的地方。我得到了这个堆栈栅格文件,其中包含生物气候资料(WorldClim)、地形数据(高程、坡度等),以及几个分类栅格(土地利用和地质类型)。计划是使用 terra::p redict 来获取显示存在概率的栅格。

但这里有一个问题:当我运行预测函数时,它给我带来了麻烦。它要么根本不运行,要么吐出一条错误消息,说明我检查过的“列中缺少数据”,我的堆栈栅格都很好;当我使用没有 k 折叠的更简单的 *randomForest * 时,它们工作正常。

我尝试过寻找其他预测方法,并尝试过如何输入数据,但到目前为止还没有运气。有人有任何想法或技巧可以帮助我解决这个问题吗?

目的: 使用伪缺失和 RandomForest 生成物种分布的概率栅格。然后,使用该模型仅预测当前和未来变化的气候栅格的分布。

示例数据

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), #This way factor is not separated by levels
  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, ...)
R-卡莱特 Terra

评论

0赞 Robert Hijmans 10/28/2023
当提出R问题时,请包括一个最小的、独立的、可重现的例子(有关示例,请参阅我的答案、R帮助文件和本网站上的问答)。
0赞 Robert Hijmans 10/28/2023
感谢您添加一个示例,但它不是独立的。也就是说,您需要更改脚本,以便我们可以使用您提供的示例数据运行它。(请参阅我的示例;不要提供文件)。
0赞 Joshua Borràs 10/28/2023
我不完全明白这将如何帮助我的具体情况,但你明白了。
0赞 Robert Hijmans 10/29/2023
我希望现在很清楚了。
0赞 Joshua Borràs 10/29/2023
是的,我可以得到我想要的数据。非常感谢。下次我发帖时,我会记住这一点。

答:

3赞 Robert Hijmans 10/28/2023 #1

如果使用默认参数运行,则会得到:terra::predict

x <- terra::predict(logo, ranger_model)
#Error: Missing data in columns: red, green, blue.

您可以使用以下方法修复此问题na.rm=TRUE

x <- terra::predict(logo, ranger_model, na.rm=TRUE)

您不需要提供专门的预测函数,因为插入符号预测函数返回一个简单的向量

predict(ranger_model, logo[1:4])
#[1] Pres Pres Pres Pres
#Levels: Pres Abs

相反,如果你使用“ranger”的预测函数,你会得到一个列表,在这种情况下,你可以使用

predfun <- function(...) predict(...)$predictions
x <- terra::predict(logo, ranger_model, fun=predfun, na.rm=TRUE)

评论

0赞 Joshua Borràs 10/28/2023
对不起,我更新了它。