我正在构建一个随机森林中的一些工作数据(这意味着我无法共享该数据,有15k观测值),使用插入符号列功能进行交叉验证,模型的准确性非常低:0.9%。
这是我使用的代码:
set.seed(512)
n <- nrow(my_data)
train_indices <- sample(1:n)
my_folds <- createFolds(train_indices, k=5)
model <- train(ICNumber ~ ., tuneGrid = data.frame(mtry = c(32), min.node.size = 1, splitrule = "gini"),
data = my_data, method = "ranger",
trControl = trainControl(verboseIter = TRUE, savePredictions = T, index=my_folds))
print(model$resample)
- 编辑
正如吉尔斯所注意到的那样,折叠指数构造错误,并且在20%的观测值上进行了训练,但即使我通过添加returnTrain = T
来解决这个问题,我仍然接近零准确度
- 编辑
model $ resample产生这个:
Accuracy ___ Kappa_____ Resample
0.026823683_ 0.0260175246_ Fold1
0.002615234_ 0.0019433907_ Fold2
0.002301118_ 0.0017644472_ Fold3
0.001637733_ 0.0007026352_ Fold4
0.010187315_ 0.0094986595_ Fold5
现在,如果我像这样手工进行交叉验证:
set.seed(512)
n <- nrow(my_data)
train_indices <- sample(1:n)
my_folds <- createFolds(train_indices, k=5)
for (fold in my_folds) {
train_data <- my_data[-fold,]
test_data <- my_data[fold,]
model <- train(ICNumber ~ ., tuneGrid = data.frame(mtry = c(32), min.node.size = 1, splitrule = "gini"),
data = train_data, method = "ranger",
trControl = trainControl(method = "none"))
p <- predict(model, test_data)
e <- ifelse(p == test_data$ICNumber, T, F)
print(sum(e) / nrow(test_data))
}
我得到以下准确度:
[1] 0.743871
[1] 0.7566957
[1] 0.7380645
[1] 0.7390181
[1] 0.7311168
我期待获得相同的准确度值,我在火车上做错了什么?或者手动预测代码是错误的?
- 编辑 此外,此代码适用于大豆数据,我可以重现以下Gilles的结果 - 编辑
--Edit2 以下是我的数据的一些细节: 15493 obs。 17个变量: ICNUmber是一个包含1531个不同值的字符串,这些是类 其他16个变量是33个级别的因子 --Edit2
--Edit3 我的最后一个实验是放弃所有类别的观察结果发生不到10次,仍有12k观察到396个类别。对于此数据集,手动和自动交叉验证精度匹配... --Edit3
这是一个棘手的问题! ;-)
该错误来自于index
中trainControl
选项的误用。
根据帮助页面,qazxsw poi应该是:
包含每个重采样迭代元素的列表。每个列表元素是一个整数向量,对应于在该迭代中用于训练的行。
在您的代码中,您提供了与应从训练数据集中删除的行相对应的整数,而不是提供与应该使用的行相对应的整数...
您可以使用index
而不是createFolds(train_indices, k=5, returnTrain = T)
来实现这一目标。
另请注意,inaialy,afaik,createFolds(train_indices, k=5)
正在创建相对于您要预测的类平衡的折叠。所以代码应该更像是:caret
,特别是如果类不平衡的话......
以下是Soybean数据集的可重现示例
createFolds(my_data[train_indices, "Class"], k=5, returnTrain = T)
您的代码(训练数据比预期的要小得多,您只使用20%的数据,因此精度较低)。 由于训练数据集中某些类的缺失(由于类不平衡和训练集减少),您也会收到一些警告。
library(caret)
#> Le chargement a nécessité le package : lattice
#> Le chargement a nécessité le package : ggplot2
data(Soybean, package = "mlbench")
my_data <- droplevels(na.omit(Soybean))
更正了代码,只需使用set.seed(512)
n <- nrow(my_data)
train_indices <- sample(1:n)
my_folds <- createFolds(train_indices, k=5)
model <- train(Class ~ ., tuneGrid = data.frame(mtry = c(32), min.node.size = 1, splitrule = "gini"),
data = my_data, method = "ranger",
trControl = trainControl(verboseIter = F, savePredictions = T,
index=my_folds))
#> Warning: Dropped unused factor level(s) in dependent variable: rhizoctonia-
#> root-rot.
#> Warning: Dropped unused factor level(s) in dependent variable: downy-
#> mildew.
print(model$resample)
#> Accuracy Kappa Resample
#> 1 0.7951002 0.7700909 Fold1
#> 2 0.5846868 0.5400131 Fold2
#> 3 0.8440980 0.8251373 Fold3
#> 4 0.8822222 0.8679453 Fold4
#> 5 0.8444444 0.8263563 Fold5
(这里你真的使用80%的数据进行培训......)
returnTrain = T
要与你的循环进行比较。仍然存在一些小的差异,所以可能还有一些我不理解的东西。
set.seed(512)
n <- nrow(my_data)
train_indices <- sample(1:n)
my_folds <- createFolds(train_indices, k=5, returnTrain = T)
model <- train(Class ~ ., tuneGrid = data.frame(mtry = c(32), min.node.size = 1, splitrule = "gini"),
data = my_data, method = "ranger",
trControl = trainControl(verboseIter = F, savePredictions = T,
index=my_folds))
print(model$resample)
#> Accuracy Kappa Resample
#> 1 0.9380531 0.9293371 Fold1
#> 2 0.8750000 0.8583687 Fold2
#> 3 0.9115044 0.9009814 Fold3
#> 4 0.8660714 0.8505205 Fold4
#> 5 0.9107143 0.9003825 Fold5
由set.seed(512)
n <- nrow(my_data)
train_indices <- sample(1:n)
my_folds <- createFolds(train_indices, k=5)
for (fold in my_folds) {
train_data <- my_data[-fold,]
test_data <- my_data[fold,]
model <- train(Class ~ ., tuneGrid = data.frame(mtry = c(32), min.node.size = 1, splitrule = "gini"),
data = train_data, method = "ranger",
trControl = trainControl(method = "none"))
p <- predict(model, test_data)
e <- ifelse(p == test_data$Class, T, F)
print(sum(e) / nrow(test_data))
}
#> [1] 0.9380531
#> [1] 0.875
#> [1] 0.9115044
#> [1] 0.875
#> [1] 0.9196429
创建于2018-03-09(v0.2.0)。
为了扩展吉尔斯的优秀答案。除了指定用于测试和训练的索引的错误,要获得一个完全可重现的算法模型,其中包含一些随机过程,如随机forrest,你应该在reprex package中指定seeds
参数。此参数的长度应等于重新采样的数量+ 1(对于最终模型):
trainControl
现在让我们手动重新采样:
library(caret)
library(mlbench)
data(Sonar)
data(Sonar)
set.seed(512)
n <- nrow(Sonar)
train_indices <- sample(1:n)
my_folds <- createFolds(train_indices, k = 5, returnTrain = T)
model <- train(Class ~ .,
tuneGrid = data.frame(mtry = c(32),
min.node.size = 1,
splitrule = "gini"),
data = Sonar,
method = "ranger",
trControl = trainControl(verboseIter = F,
savePredictions = T,
index = my_folds,
seeds = rep(512, 6))) #this is the important part
model$resample
#output
Accuracy Kappa Resample
1 0.8536585 0.6955446 Fold1
2 0.8095238 0.6190476 Fold2
3 0.8536585 0.6992665 Fold3
4 0.7317073 0.4786127 Fold4
5 0.8372093 0.6681367 Fold5
@semicolo如果您可以在Sonar数据集上重现此示例,但不能使用您自己的数据,则问题出在数据集中,任何进一步的见解都需要调查相关数据。
看起来火车功能将类列转换为一个因子,在我的数据集中有很多(约20%)具有少于4个观察值的类。当手动分割集合时,在分割之后构造因子,并且对于每个因子值,至少有一个观察值。但是在自动交叉验证期间,因子是在完整数据集上构建的,并且当完成拆分时,该因子的某些值没有任何观察值。这似乎在某种程度上搞砸了准确性。这可能需要一个新的不同的问题,感谢吉尔斯和他们的帮助。