使用randomForest,Caret和因子变量预测栅格出现错误

4

我想用randomForest和caret包来预测一层栅格图像,但是当我引入因子变量时就会失败。如果没有因子变量,一切都很好,但是一旦引入因子变量,就会出现以下错误:

Error in predict.randomForest(modelFit, newdata) : Type of predictors in new data do not match that of the training data.

我在下面创建了一些示例代码,演示了整个过程。我把它分成几个步骤来透明地提供一个可工作的示例。

(如果要跳过设置代码,请从以下开始...)

首先是创建样本数据、拟合RF模型以及不涉及因子的预测栅格图像。一切正常。

# simulate data
x1p <- runif(50, 10, 20) # presence
x2p <- runif(50, 100, 200)
x1a <- runif(50, 15, 25) # absence
x2a <- runif(50, 180, 400)
x1 <- c(x1p, x1a)
x2 <- c(x2p,x2a)
y <- c(rep(1,50), rep(0,50)) # presence/absence
d <- data.frame(x1 = x1, x2 = x2, y = y)

# RF Classification on data with no factors... works fine
require(randomForest)
dRF <- d
dRF$y <- factor(ifelse(d$y == 1, "present", "absent"),
                levels = c("present", "absent"))
rfFit <- randomForest(y = dRF$y, x = dRF[,1:2], ntree=100) # RF Classfication

# Create sample Rasters
require(raster)
r1 <- r2 <- raster(nrow=100, ncol=100)
values(r1) <- runif(ncell(r1), 5, 25 )
values(r2) <- runif(ncell(r2), 85, 500 )
s <- stack(r1, r2)
names(s) <- c("x1", "x2")

# raster::predict() with no factors, works fine.
model <- predict(s, rfFit, na.rm=TRUE, type="prob", progress='text')
spplot(model)

下一步是创建一个因子变量,将其添加到训练数据中,并创建一个与预测值匹配的栅格图像。请注意,该栅格图像是普通的整数,而不是as.factor 栅格图像。一切仍然正常运作...
# Create factor variable
x3p <- sample(0:5, 50, replace=T)
x3a <- sample(3:7, 50, replace=T)
x3 <- c(x3p, x3a)
dFac <- dRF
dFac$x3 <- as.factor(x3)
dFac <- dFac[,c(1,2,4,3)] # reorder

# RF model with factors, works fine
rfFit2 <- randomForest(y ~ x1 + x2 + x3, data=dFac, ntree=100)

# Create new raster, but not as.factor()
r3 <- raster(nrow=100, ncol=100)
values(r3) <- sample(0:7, ncell(r3), replace=T)
s2 <- stack(s, r3)
names(s2) <- c("x1", "x2", "x3") 
s2 <- brick(s2) # brick or stack, either work

# RF, raster::predict() from fit with factor
f <- levels(dFac$x3) # included, but not necessary
model2 <- predict(s2, rfFit2,  type="prob", 
          progress='text', factors=f, index=1:2)
spplot(model2) # works fine

在完成上述步骤后,我现在拥有了一个RF模型,该模型是使用包含因子变量的数据进行训练,并在包含相似值的整数栅格的光栅砖上进行预测。这是我的最终目标,但我希望能够通过caret包的工作流程来实现。下面我介绍了caret::train(),不涉及任何因子变量,一切正常运行。
# RF with Caret and NO factors
require(caret)
rf_ctrl <- trainControl(method = "cv", number=10,
           allowParallel=FALSE, verboseIter=TRUE, 
           savePredictions=TRUE, classProbs=TRUE) 
cFit1 <- train(y = dRF$y, x = dRF[,1:2], method = "rf", 
         tuneLength=4, trControl = rf_ctrl, importance = TRUE)
model3 <- predict(s2, cFit1,  type="prob", 
          progress='text', factors=f, index=1:2) 
spplot(model3) # works with caret and NO factors

(...到这里。这就是问题开始的地方)

这里是事情失败的地方。一个经过训练的带有因子变量的Caret Rf模型可以工作,但在raster::predict()中失败。

# RF with Caret and FACTORS
rf_ctrl2 <- trainControl(method = "cv", number=10,
            allowParallel=FALSE, verboseIter=TRUE, 
            savePredictions=TRUE, classProbs=TRUE)
cFit2 <- train(y = dFac$y, x = dFac[,1:3], method = "rf", 
         tuneLength=4, trControl = rf_ctrl2, importance = TRUE)
model4 <- predict(s2, cFit2,  type="prob", 
          progress='text', factors=f, index=1:2) 
# FAIL: "Type of predictors in new data do not match that of the training data."

尝试与上述相同的操作,但是不使用整数栅格,而是使用as.factor()将栅格转换为因子,并分配级别。但是这种方法也失败了。
#trying with raster as.factor()
r3f <- raster(nrow=100, ncol=100)
values(r3f) <- sample(0:7, ncell(r3f), replace=T)
r3f <- as.factor(r3f)
f <- levels(r3f)[[1]]
f$code <- as.character(f[,1])
levels(r3f) <- f
s2f <- stack(s, r3f)
names(s2f) <- c("x1", "x2", "x3")
s2f <- brick(s2f)

model4f <- predict(s2f, cFit2,  type="prob", 
           progress='text', factors=f, index=1:2)
# FAIL "Type of predictors in new data do not match that of the training data."

以上步骤中的错误和进展明确表明我的方法存在问题,可能是由于caret:train()raster::predict()之间的差异。我已经尽力进行了调试并解决了我注意到的问题,但是并没有找到问题的真正原因。
非常感谢您能提供任何帮助!
补充: 我继续测试后发现,如果在caret::train()中使用公式形式的模型,则可以成功运行。查看模型对象的结构,可以轻松地看到为因子变量创建了对比度。这也意味着raster::predict()识别了这些对比度。这样做虽然可行,但很遗憾我的方法不支持基于公式的预测。仍然非常感谢您的任何额外帮助。
#with Caret WITH FACTORS as model formula!
rf_ctrl3 <- trainControl(method = "cv", number=10,
            allowParallel=FALSE, verboseIter=TRUE, savePredictions=TRUE, classProbs=TRUE)
cFit3 <- train(y ~ x1 + x2 + x3, data=dFac, method = "rf", 
            tuneLength=4, trControl = rf_ctrl2, importance = TRUE)

model5 <- predict(s2, cFit3,  type="prob", progress='text') # prediction raster
spplot(model5) 

简而言之,当使用因子(factors)时,必须确保测试数据和预测数据中的因子水平完全相同。在使用as.factor()函数时,必须指定因子水平。 - Andrie
谢谢@Andrie,我在SA的其他地方也读到过这个。 在这种情况下,它们是相同的;成为示例数据。上面示例中光栅r3f和变量x3的级别相同。在我的实际项目中,有时它们并不相同,但我想到那时会解决。谢谢! - Mr.ecos
2个回答

5
经过大量测试,我们得出结论:raster::predict()只能与通过caret::train()生成的包含因子的模型一起使用,如果将模型表示为公式(y ~ x1 + x2 + x3)而不是y = y, x = x(作为矩阵或数据框)。只有通过公式接口,模型才能创建正确的对比或虚拟变量。无需通过as.factor()将栅格图层转换为因子。预测函数会为您完成这项工作。

我猜想在使用randomForest::randomForest()而不是caret::train()时,模型必须以公式的形式呈现?您能否详细说明需要指定因子水平的情况?这仅适用于训练数据吗?而用于预测的栅格堆栈只需要具有与这些因子水平相对应的单元格值即可吗?谢谢! - philiporlando
这对我来说不起作用。当我使用公式接口拟合随机森林时,raster::predict()不再失败,但栅格预测结果全部为NA - hendra

0

您的代码使用因子和raster::predict以及非公式接口的caret模型正常工作,如果将输入结构转换为函数raster::predict的参数factors的列表形式:

f <- list(x3 = levels(dFac$x3))

(替换代码行f <- levels(dFac$x3) # included, but not necessary。)

您的代码

# RF with Caret and FACTORS
rf_ctrl2 <- trainControl(method = "cv", number=10,
                         allowParallel=FALSE, verboseIter=TRUE, 
                         savePredictions=TRUE, classProbs=TRUE)
cFit2 <- train(y = dFac$y, x = dFac[,1:3], method = "rf", 
                tuneLength=4, trControl = rf_ctrl2, importance = TRUE)
model4 <- predict(s2, cFit2,  type="prob", 
                  progress='text', factors=f, index=1:2) 

然后可以无错误地运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接