Resultados diferentes do randomForest via acento circunflexo e do pacote randomForest básico

14

Estou um pouco confuso: como os resultados de um modelo treinado via sinal de intercalação diferem do modelo na embalagem original? Eu li se o pré-processamento é necessário antes da previsão usando o FinalModel do RandomForest com pacote de interpolação? mas eu não uso nenhum pré-processamento aqui.

Treinei diferentes florestas aleatórias usando o pacote de acento circunflexo e ajustando-me para diferentes valores de manejo.

> 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

Eu achei mtry = 15 o melhor parâmetro no 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. 

Avaliei o modelo com uma curva ROC e uma matriz de confusão:

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

A matriz de confusão e precisão resultantes:

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

           Accuracy : 0.8984
 ....

Agora eu treinei um Random Rorest com os mesmos parâmetros e os mesmos training_data usando o pacote randomForest básico:

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

Novamente, criei previsões para os mesmos dados_de_teste como acima e avaliei a matriz de confusão com o mesmo código acima. Mas agora eu tenho medidas diferentes:

Confusion Matrix and Statistics

      Reference
Prediction   No  Yes
       No  2702  897
       Yes  430 6480

           Accuracy : 0.8737 
           ....

Qual é a razão? o que estou perdendo?

Malte
fonte
3
Você usou o mesmo valor para a semente aleatória nos dois modelos?
mmmmmmmmmm
Acho que sim. Eu configurei a semente anteriormente no código ao dividir o conjunto de dados em dados de treinamento e teste, depois treinei o modelo de sinal de intercalação e, em seguida, treinei o modelo rf "original". Portanto, a semente deve permanecer a mesma uma vez estabelecida no início, não deveria?
Malte
Tentei inserir outro set.seed diretamente antes de treinar o modelo "rf" original. Infelizmente, não resolve o problema.
Malte
3
Você deve testar isso usando o seedsargumento detrainControl
topepo 15/03

Respostas:

4

Penso que a questão, embora um tanto trivial e "programática", à primeira leitura, aborda duas questões principais muito importantes na estatística moderna:

  1. reprodutibilidade dos resultados e
  2. algoritmos não determinísticos.

A razão para os diferentes resultados é que os dois procedimentos são treinados usando sementes aleatórias diferentes. Floresta aleatória utiliza um subconjunto aleatório de variáveis do full-conjunto de dados como candidatos em cada divisão (que é o mtryargumento e refere-se ao método de subespaço aleatório ), bem como sacos (agregados de bootstrap) o conjunto de dados original para diminuir a variância do modelo. Esses dois procedimentos internos de amostragem aleatória considerados não são determinísticos entre diferentes execuções do algoritmo. A ordem aleatória em que a amostragem é feita é controlada pelas sementes aleatórias utilizadas. Se as mesmas sementes fossem usadas, obteríamos exatamente os mesmos resultados nos dois casos em que a randomForestrotina é chamada; tanto internamente emcaret::trainbem como externamente ao ajustar manualmente uma floresta aleatória. Anexo um trecho de código simples para mostrar isso. Observe que eu uso um número muito pequeno de árvores (argumento:) ntreepara continuar treinando rapidamente, geralmente deve ser muito maior.

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) 

Nesse ponto, tanto o caret.trainobjeto fitRFcaretquanto o randomForestobjeto definido manualmente fitRFmanualforam treinados usando os mesmos dados, mas o mais importante, usando as mesmas sementes aleatórias ao ajustar seu modelo final. Como tal, quando tentarmos prever o uso desses objetos e como não fazemos pré-processamento de nossos dados , obteremos as mesmas respostas exatas.

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

Apenas para esclarecer isso, aponte um pouco mais adiante: predict(xx$finalModel, testData)e predict(xx, testData)será diferente se você definir a preProcessopção ao usar train. Por outro lado, ao usar finalModeldiretamente, é equivalente usar a predictfunção do modelo montado ( predict.randomForestaqui) em vez de predict.train; nenhuma pré-avaliação ocorre. Obviamente, no cenário descrito na pergunta original, onde nenhum pré-processamento é realizado, os resultados serão os mesmos ao usar o objeto finalModelajustado manualmente randomForestou o caret.trainobjeto.

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

Eu sugiro fortemente que você sempre defina a semente aleatória usada por R, MATLAB ou qualquer outro programa usado. Caso contrário, você não poderá verificar a reprodutibilidade dos resultados (o que é bom, pode não ser o fim do mundo) nem excluir um bug ou fator externo que afeta o desempenho de um procedimento de modelagem (o que sim, é meio ruim). Muitos dos principais algoritmos de ML (por exemplo, aumento de gradiente, florestas aleatórias, redes neurais extremas) empregam certos procedimentos internos de reamostragem durante suas fases de treinamento, definindo os estados aleatórios de sementes antes (ou às vezes até dentro) de sua fase de treinamento pode ser importante.

usεr11852 diz Reinstate Monic
fonte
A parte importante era definir o argumento sementes explicitamente em "trainControl" usando o argumento de "sementes"
Malte
Sim, claro. Eu queria ter certeza de que o problema de por que isso é necessário foi totalmente esclarecido.
usεr11852 diz Reinstate Monic 2/17/17
Como eu corro trainpara que seja exatamente equivalente a randomForest? Eu tentei, method="none"mas não sei como definir a semente para o valor único. Obrigado.
Simon Woodward
Desculpas, mas não está claro se você tem algum preProcessou como ele randomForesté treinado para começar. Em geral, assumindo que não temos etapas de pré-processamento, precisamos garantir que a semente e os hiperparâmetros (aqui apenas mtry) usados ​​sejam os mesmos.
usεr11852 diz Reinstate Monic
0

As previsões de curClassifiernão são iguais às previsões do curClassifier$finalModel link . Você reproduziu finalModele está comparando com o predict.trainobjeto.

tomaz
fonte
1
Embora o que você diz seja verdade, infelizmente é um pouco enganador na configuração atual, pois nenhum pré-processamento é feito pelo OP. Ambos predictdevem (e realmente) dão as mesmas previsões no caso em que o OP explora. Esclareço esse ponto um pouco mais no meu post.
usεr11852 diz Reinstate Monic