在使用公式使用插入符号的 train() 训练的 randomForest 对象上使用 predict() 时出错
Error when using predict() on a randomForest object trained with caret's train() using formula
在 64 位 Linux 机器上使用带插入符 6.0-41 和 randomForest 4.6-10 的 R 3.2.0。
当尝试对使用公式从 caret
包中的 train()
函数训练的 randomForest
对象使用 predict()
方法时,函数 returns 一个错误。
当使用 x=
和 y=
而不是公式通过 randomForest()
and/or 进行训练时,一切运行顺利。
这是一个工作示例:
library(randomForest)
library(caret)
data(imports85)
imp85 <- imports85[, c("stroke", "price", "fuelType", "numOfDoors")]
imp85 <- imp85[complete.cases(imp85), ]
imp85[] <- lapply(imp85, function(x) if (is.factor(x)) x[,drop=TRUE] else x) ## Drop empty levels for factors.
modRf1 <- randomForest(numOfDoors~., data=imp85)
caretRf <- train( numOfDoors~., data=imp85, method = "rf" )
modRf2 <- caretRf$finalModel
modRf3 <- randomForest(x=imp85[,c("stroke", "price", "fuelType")], y=imp85[, "numOfDoors"])
caretRf <- train(x=imp85[,c("stroke", "price", "fuelType")], y=imp85[, "numOfDoors"], method = "rf")
modRf4 <- caretRf$finalModel
p1 <- predict(modRf1, newdata=imp85)
p2 <- predict(modRf2, newdata=imp85)
p3 <- predict(modRf3, newdata=imp85)
p4 <- predict(modRf4, newdata=imp85)
最后4行中,只有第二行p2 <- predict(modRf2, newdata=imp85)
returns出现如下错误:
Error in predict.randomForest(modRf2, newdata = imp85) :
variables in the training data missing in newdata
这个错误的原因似乎是predict.randomForest
方法使用rownames(object$importance)
来确定用于训练随机森林object
的变量名称。而当看
rownames(modRf1$importance)
rownames(modRf2$importance)
rownames(modRf3$importance)
rownames(modRf4$importance)
我们看到:
[1] "stroke" "price" "fuelType"
[1] "stroke" "price" "fuelTypegas"
[1] "stroke" "price" "fuelType"
[1] "stroke" "price" "fuelType"
所以不知何故,当使用带有公式的 caret
train()
函数时,会更改 randomForest
对象的 importance
字段中的(因子)变量的名称.
插入符号 train()
函数的公式版本和非公式版本之间真的存在不一致吗?还是我遗漏了什么?
首先,几乎从不使用$finalModel
对象进行预测。使用 predict.train
。这是一个很好的例子。
某些函数(包括 randomForest
和 train
)处理虚拟变量的方式有些不一致。 R 中使用公式方法的大多数函数会将因子预测变量转换为虚拟变量,因为它们的模型需要数据的数字表示。例外情况是基于树和规则的模型(可以根据分类预测变量进行拆分)、朴素贝叶斯和其他一些模型。
因此,当您使用 randomForest(y ~ ., data = dat)
时,randomForest
将 不会 创建虚拟变量,但 train
(以及大多数其他人)将使用类似的调用train(y ~ ., data = dat)
.
错误发生是因为fuelType
是一个因素。 train
创建的虚拟变量名称不同,因此 predict.randomForest
无法找到它们。
将非公式方法与 train
一起使用会将因子预测变量传递给 randomForest
,一切都会起作用。
TL;DR
如果你想要相同的级别或使用predict.train
,请使用train
的非公式方法
出现此错误的原因可能有两个。
1.训练集和测试集的分类变量类别不匹配。要检查这一点,您可以 运行 像下面这样的东西。
嗯,首先,将独立 variables/features 保留在列表中是一个很好的做法。假设该列表是 "vars"。比如说,你将 "Data" 分成了 "Train" 和 "Test"。出发吧:
for (v in vars){
if (class(Data[,v]) == 'factor'){
print(v)
# print(levels(Train[,v]))
# print(levels(Test[,v]))
print(all.equal(levels(Train[,v]) , levels(Test[,v])))
}
}
一旦找到不匹配的分类变量,就可以返回,将测试数据的类别强加到训练数据上,然后重新构建模型。在类似于上面的循环中,对于每个 nonMatchingVar,您可以执行
levels(Test$nonMatchingVar) <- levels(Train$nonMatchingVar)
2. 一个傻瓜。如果您不小心将因变量留在自变量集中,您可能会 运行 进入此错误消息。我犯了那个错误。解决办法:小心点就好了。
另一种方法是使用 model.matrix
显式编码测试数据,例如
p2 <- predict(modRf2, newdata=model.matrix(~., imp85))
在 64 位 Linux 机器上使用带插入符 6.0-41 和 randomForest 4.6-10 的 R 3.2.0。
当尝试对使用公式从 caret
包中的 train()
函数训练的 randomForest
对象使用 predict()
方法时,函数 returns 一个错误。
当使用 x=
和 y=
而不是公式通过 randomForest()
and/or 进行训练时,一切运行顺利。
这是一个工作示例:
library(randomForest)
library(caret)
data(imports85)
imp85 <- imports85[, c("stroke", "price", "fuelType", "numOfDoors")]
imp85 <- imp85[complete.cases(imp85), ]
imp85[] <- lapply(imp85, function(x) if (is.factor(x)) x[,drop=TRUE] else x) ## Drop empty levels for factors.
modRf1 <- randomForest(numOfDoors~., data=imp85)
caretRf <- train( numOfDoors~., data=imp85, method = "rf" )
modRf2 <- caretRf$finalModel
modRf3 <- randomForest(x=imp85[,c("stroke", "price", "fuelType")], y=imp85[, "numOfDoors"])
caretRf <- train(x=imp85[,c("stroke", "price", "fuelType")], y=imp85[, "numOfDoors"], method = "rf")
modRf4 <- caretRf$finalModel
p1 <- predict(modRf1, newdata=imp85)
p2 <- predict(modRf2, newdata=imp85)
p3 <- predict(modRf3, newdata=imp85)
p4 <- predict(modRf4, newdata=imp85)
最后4行中,只有第二行p2 <- predict(modRf2, newdata=imp85)
returns出现如下错误:
Error in predict.randomForest(modRf2, newdata = imp85) :
variables in the training data missing in newdata
这个错误的原因似乎是predict.randomForest
方法使用rownames(object$importance)
来确定用于训练随机森林object
的变量名称。而当看
rownames(modRf1$importance)
rownames(modRf2$importance)
rownames(modRf3$importance)
rownames(modRf4$importance)
我们看到:
[1] "stroke" "price" "fuelType"
[1] "stroke" "price" "fuelTypegas"
[1] "stroke" "price" "fuelType"
[1] "stroke" "price" "fuelType"
所以不知何故,当使用带有公式的 caret
train()
函数时,会更改 randomForest
对象的 importance
字段中的(因子)变量的名称.
插入符号 train()
函数的公式版本和非公式版本之间真的存在不一致吗?还是我遗漏了什么?
首先,几乎从不使用$finalModel
对象进行预测。使用 predict.train
。这是一个很好的例子。
某些函数(包括 randomForest
和 train
)处理虚拟变量的方式有些不一致。 R 中使用公式方法的大多数函数会将因子预测变量转换为虚拟变量,因为它们的模型需要数据的数字表示。例外情况是基于树和规则的模型(可以根据分类预测变量进行拆分)、朴素贝叶斯和其他一些模型。
因此,当您使用 randomForest(y ~ ., data = dat)
时,randomForest
将 不会 创建虚拟变量,但 train
(以及大多数其他人)将使用类似的调用train(y ~ ., data = dat)
.
错误发生是因为fuelType
是一个因素。 train
创建的虚拟变量名称不同,因此 predict.randomForest
无法找到它们。
将非公式方法与 train
一起使用会将因子预测变量传递给 randomForest
,一切都会起作用。
TL;DR
如果你想要相同的级别或使用predict.train
train
的非公式方法
出现此错误的原因可能有两个。
1.训练集和测试集的分类变量类别不匹配。要检查这一点,您可以 运行 像下面这样的东西。
嗯,首先,将独立 variables/features 保留在列表中是一个很好的做法。假设该列表是 "vars"。比如说,你将 "Data" 分成了 "Train" 和 "Test"。出发吧:
for (v in vars){ if (class(Data[,v]) == 'factor'){ print(v) # print(levels(Train[,v])) # print(levels(Test[,v])) print(all.equal(levels(Train[,v]) , levels(Test[,v]))) } }
一旦找到不匹配的分类变量,就可以返回,将测试数据的类别强加到训练数据上,然后重新构建模型。在类似于上面的循环中,对于每个 nonMatchingVar,您可以执行
levels(Test$nonMatchingVar) <- levels(Train$nonMatchingVar)
2. 一个傻瓜。如果您不小心将因变量留在自变量集中,您可能会 运行 进入此错误消息。我犯了那个错误。解决办法:小心点就好了。
另一种方法是使用 model.matrix
显式编码测试数据,例如
p2 <- predict(modRf2, newdata=model.matrix(~., imp85))