通过插入符号和基本 randomForest 包获得 randomForest 的不同结果

机器算法验证 r 机器学习 随机森林 插入符号 火车
2022-03-08 23:21:57

我有点困惑:通过插入符号训练的模型的结果与原始包中的模型有何不同?我阅读了在使用带有插入符号包的 RandomForest 的 FinalModel 进行预测之前是否需要预处理?但我在这里不使用任何预处理。

我通过使用 caret 包和调整不同的 mtry 值来训练不同的随机森林。

> cvCtrl = trainControl(method = "repeatedcv",number = 10, repeats = 3, classProbs = TRUE, summaryFunction = twoClassSummary)
> newGrid = expand.grid(mtry = c(2,4,8,15))
> classifierRandomForest = train(case_success ~ ., data = train_data, trControl = cvCtrl, method = "rf", metric="ROC", tuneGrid = newGrid)
> curClassifier = classifierRandomForest

我发现 mtry=15 是 training_data 上的最佳参数:

> curClassifier
 ...
Resampling results across tuning parameters:

mtry  ROC    Sens   Spec   ROC SD   Sens SD  Spec SD
 4    0.950  0.768  0.957  0.00413  0.0170   0.00285
 5    0.951  0.778  0.957  0.00364  0.0148   0.00306
 8    0.953  0.792  0.956  0.00395  0.0152   0.00389
10    0.954  0.797  0.955  0.00384  0.0146   0.00369
15    0.956  0.803  0.951  0.00369  0.0155   0.00472

ROC was used to select the optimal model using  the largest value.
The final value used for the model was mtry = 15. 

我用 ROC 曲线和混淆矩阵评估了模型:

##ROC-Curve
predRoc = predict(curClassifier, test_data, type = "prob")
myroc = pROC::roc(test_data$case_success, as.vector(predRoc[,2]))
plot(myroc, print.thres = "best")

##adjust optimal cut-off threshold for class probabilities
threshold = coords(myroc,x="best",best.method = "closest.topleft")[[1]] #get optimal cutoff threshold
predCut = factor( ifelse(predRoc[, "Yes"] > threshold, "Yes", "No") )


##Confusion Matrix (Accuracy, Spec, Sens etc.)
curConfusionMatrix = confusionMatrix(predCut, test_data$case_success, positive = "Yes")

由此产生的混淆矩阵和准确性:

Confusion Matrix and Statistics
      Reference
Prediction   No  Yes
   No  2757  693
   Yes  375 6684

           Accuracy : 0.8984
 ....

现在我使用基本的 randomForest 包训练了具有相同参数和相同 training_data 的 Random Rorest:

randomForestManual <- randomForest(case_success ~ ., data=train_data, mtry = 15, ntree=500,keep.forest=TRUE)
curClassifier = randomForestManual

我再次为与上面相同的 test_data 创建了预测,并使用与上面相同的代码评估了混淆矩阵。但现在我得到了不同的措施:

Confusion Matrix and Statistics

      Reference
Prediction   No  Yes
       No  2702  897
       Yes  430 6480

           Accuracy : 0.8737 
           ....

是什么原因?我错过了什么?

2个回答

我认为这个问题虽然初读时有些微不足道和“程序化”,但涉及现代统计学中非常重要的两个主要问题:

  1. 结果的再现性和
  2. 非确定性算法。

结果不同的原因是这两个过程是使用不同的随机种子训练的。随机森林使用来自完整数据集变量的随机子集作为每次拆分的候选者(这是mtry参数并且与随机子空间方法相关)以及原始数据集的袋子(引导聚合)以减少模型的方差。这两个内部随机抽样程序被认为在算法的不同运行之间不是确定性的。抽样的随机顺序由使用的随机种子控制。randomForest如果使用相同的种子,那么在调用例程的两种情况下都会得到完全相同的结果;两者在内部caret::train以及手动拟合随机森林时的外部。我附上了一个简单的代码片段来展示这个。请注意,我使用非常少量的树(参数:)ntree来保持快速训练,通常应该大得多。

library(caret)

set.seed(321)
trainData <- twoClassSim(5000, linearVars = 3, noiseVars = 9)
testData  <- twoClassSim(5000, linearVars = 3, noiseVars = 9)

set.seed(432)
mySeeds <- sapply(simplify = FALSE, 1:26, function(u) sample(10^4, 3))
cvCtrl = trainControl(method = "repeatedcv", number = 5, repeats = 5, 
                      classProbs = TRUE, summaryFunction = twoClassSummary, 
                      seeds = mySeeds)

fitRFcaret = train(Class ~ ., data = trainData, trControl = cvCtrl, 
                   ntree = 33, method = "rf", metric="ROC")

set.seed( unlist(tail(mySeeds,1))[1])
fitRFmanual <- randomForest(Class ~ ., data=trainData, 
                            mtry = fitRFcaret$bestTune$mtry, ntree=33) 

此时,caret.train对象fitRFcaret和手动定义的randomForest对象fitRFmanual都使用相同的数据进行了训练,但重要的是在拟合最终模型时使用了相同的随机种子。因此,当我们尝试使用这些对象进行预测时,并且由于我们不对数据进行预处理,我们将得到相同的准确答案。

all.equal(current =  as.vector(predict(fitRFcaret, testData)), 
          target = as.vector(predict(fitRFmanual, testData)))
# TRUE

predict(xx$finalModel, testData)只是为了进一步澄清这一点:predict(xx, testData)如果preProcess在使用train. 另一方面,当finalModel直接使用时,它等效于使用predict拟合模型中的函数(predict.randomForest此处)而不是predict.train; 不进行预处理。显然,在原始问题中概述的未进行预处理的场景中,使用finalModel手动拟合randomForest对象或caret.train对象时的结果将是相同的。

all.equal(current =  as.vector(predict(fitRFcaret$finalModel, testData)), 
          target = as.vector(predict(fitRFmanual, testData)))
 # TRUE

all.equal(current =  as.vector(predict(fitRFcaret$finalModel, testData)),
          target = as.vector(predict(fitRFcaret, testData)))
# TRUE

我强烈建议您始终设置 R、MATLAB 或任何其他使用的程序使用的随机种子。否则,您无法检查结果的可重复性(好吧,这可能不是世界末日),也无法排除影响建模过程性能的错误或外部因素(是的,这有点糟糕)。许多领先的 ML 算法(例如梯度提升、随机森林、极端神经网络)在训练阶段确实采用了某些内部重采样程序,因此在训练阶段之前(有时甚至在训练阶段之内)设置随机种子状态可能很重要。

来自curClassifier的预测与来自curClassifier$finalModel 链接的预测不同。您已经复制finalModel并正在将其与predict.train对象进行比较。