Unterschiedliche Ergebnisse von randomForest über caret und das Basispaket randomForest

14

Ich bin etwas verwirrt: Wie können sich die Ergebnisse eines trainierten Modells per Caret vom Modell in der Originalverpackung unterscheiden? Ich habe gelesen, ob vor der Vorhersage mit FinalModel von RandomForest mit Caret-Paket eine Vorverarbeitung erforderlich ist. aber ich benutze hier keine vorverarbeitung.

Ich habe verschiedene Zufallswälder trainiert, indem ich das Caret-Paket verwendet und für verschiedene mtry-Werte gestimmt habe.

> 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

Ich fand mtry = 15 als den besten Parameter für die 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. 

Ich habe das Modell mit einer ROC-Kurve und einer Verwirrungsmatrix bewertet:

##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")

Die resultierende Verwirrungsmatrix und Genauigkeit:

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

           Accuracy : 0.8984
 ....

Jetzt habe ich mit dem Basispaket randomForest einen Zufalls-Rorest mit denselben Parametern und denselben trainingsdaten trainiert:

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

Wiederum habe ich Vorhersagen für dieselben Testdaten wie oben erstellt und die Verwirrungsmatrix mit demselben Code wie oben bewertet. Aber jetzt habe ich verschiedene Maßnahmen:

Confusion Matrix and Statistics

      Reference
Prediction   No  Yes
       No  2702  897
       Yes  430 6480

           Accuracy : 0.8737 
           ....

Was ist der Grund? Was vermisse ich?

Malte
quelle
3
Haben Sie für beide Modelle den gleichen Wert für den Zufallsstartwert verwendet?
mmmmmmmmmm
Ich glaube schon. Ich habe den Startwert früher im Code festgelegt, als der Datensatz in Trainings- und Testdaten aufgeteilt wurde, und dann das Caret-Modell und dann das "ursprüngliche" RF-Modell trainiert. Der Same sollte also derselbe bleiben, wenn er am Anfang gesetzt wurde, oder?
Malte,
Ich habe versucht, ein anderes set.seed direkt vor dem Training des "originalen" RF-Modells einzufügen. Löst das Problem leider nicht.
Malte,
3
Sie sollten dies mit dem seedsArgument vontrainControl
topepo 15.03.15

Antworten:

4

Ich denke, dass die Frage, während sie auf den ersten Blick etwas trivial und "programmatisch" ist, zwei Hauptthemen berührt, die in der modernen Statistik sehr wichtig sind:

  1. Reproduzierbarkeit der Ergebnisse und
  2. nicht deterministische Algorithmen.

Der Grund für die unterschiedlichen Ergebnisse ist, dass die beiden Verfahren unter Verwendung verschiedener zufälliger Samen trainiert werden. Zufällige Gesamtstrukturen verwenden eine zufällige Teilmenge aus den Variablen des vollständigen Datensatzes als Kandidaten für jeden Split (das ist das mtryArgument und bezieht sich auf die Methode des zufälligen Unterraums ) sowie Taschen (Bootstrap-Aggregate) des ursprünglichen Datensatzes, um die Varianz des Modells zu verringern. Diese beiden internen Zufallsstichprobenverfahren sind zwischen verschiedenen Läufen des Algorithmus nicht deterministisch. Die zufällige Reihenfolge, in der die Probenahme erfolgt, wird durch die verwendeten Zufallskeime gesteuert. Wenn die gleichen Samen verwendet würden, würde man in beiden Fällen, in denen die randomForestRoutine aufgerufen wird, genau die gleichen Ergebnisse erzielen; beide intern incaret::trainsowie extern, wenn eine zufällige Gesamtstruktur manuell angepasst wird. Ich füge ein einfaches Code-Snippet bei, um dies zu demonstrieren. Bitte beachte, dass ich eine sehr kleine Anzahl von Bäumen verwende (Argument:) ntree, um das Training schnell zu halten. Es sollte im Allgemeinen viel größer sein.

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) 

Zu diesem Zeitpunkt wurden sowohl das caret.trainObjekt fitRFcaretals auch das manuell definierte randomForestObjekt fitRFmanualmit denselben Daten trainiert, wobei jedoch bei der Anpassung des endgültigen Modells die gleichen zufälligen Startwerte verwendet wurden. Wenn wir also versuchen, die Verwendung dieser Objekte vorherzusagen, und wenn wir unsere Daten nicht vorverarbeiten, erhalten wir dieselben genauen Antworten.

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

Nur um dies später noch einmal zu verdeutlichen: predict(xx$finalModel, testData)und predict(xx, testData)wird anders sein, wenn man die preProcessOption bei der Verwendung setzt train. Bei finalModeldirekter Verwendung entspricht dies jedoch der predictFunktion des eingebauten Modells (predict.randomForest hier) anstelle von zu verwenden predict.train. Es findet keine Vorverarbeitung statt. Offensichtlich sind in dem in der ursprünglichen Frage beschriebenen Szenario, in dem keine Vorverarbeitung durchgeführt wird, die Ergebnisse bei Verwendung finalModeldes manuell angepassten randomForestObjekts oder des caret.trainObjekts gleich.

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

Ich würde Ihnen dringend empfehlen immer den von R, MATLAB oder einem anderen verwendeten Programm verwendeten Zufallsstartwert festlegen. Andernfalls können Sie die Reproduzierbarkeit der Ergebnisse nicht überprüfen (was in Ordnung ist, es könnte nicht das Ende der Welt sein) oder einen Fehler oder externen Faktor ausschließen, der die Leistung eines Modellierungsvorgangs beeinträchtigt (was ja, irgendwie scheiße ist). Viele der führenden ML-Algorithmen (z. B. Gradienten-Boosting, zufällige Wälder, extreme neuronale Netze) verwenden während ihrer Trainingsphasen bestimmte interne Resampling-Verfahren. Das Festlegen der zufälligen Startzustände vor (oder manchmal sogar innerhalb) ihrer Trainingsphase kann wichtig sein.

usεr11852 sagt Reinstate Monic
quelle
Der wichtige Teil bestand darin, das Argument seeds explizit in "trainControl" unter Verwendung des Arguments "seeds"
Malte,
Ja natürlich. Ich wollte sicherstellen, dass die Frage, warum dies erforderlich ist, vollständig geklärt wurde.
usεr11852 sagt Reinstate Monic
Wie laufe ich, traindamit es genau gleichwertig ist randomForest? Ich habe versucht, method="none"aber nicht sicher, wie ich den Startwert auf den Einzelwert setzen soll. Vielen Dank.
Simon Woodward
Entschuldigung, aber es ist unklar, ob Sie welche haben preProcessoder wie die randomForestzu Beginn trainiert werden. Vorausgesetzt, wir haben keine Vorverarbeitungsschritte, müssen wir im Allgemeinen sicherstellen, dass sowohl das Saatgut als auch die (hier nur mtry) verwendeten Hyperparameter gleich sind.
usεr11852 sagt Reinstate Monic
0

Vorhersagen von stimmen curClassifiernicht mit Vorhersagen von curClassifier$finalModel Link überein . Sie haben das reproduziert finalModelund vergleichen es mit dem predict.trainObjekt.

Tomaz
quelle
1
Während das, was Sie sagen, wahr ist, ist es in der aktuellen Einstellung leider etwas irreführend, da das OP keine Vorverarbeitung vornimmt. Beide predictsollten (und tun es tatsächlich) die gleichen Vorhersagen für den Fall geben, dass das OP untersucht. Ich erkläre diesen Punkt in meinem Beitrag etwas genauer.
usεr11852 sagt Reinstate Monic