class: center, middle, title-slide .title[ # Florestas Aleatórias ] .subtitle[ ## (Random Forests) ] .author[ ### Jaime Utria ] .institute[ ### Departamento de EstatÃstica - UFF ] --- <!-- macro comandos matemáticos Latex --> <script type="text/x-mathjax-config"> MathJax.Hub.Config({ TeX: { Macros: { vet: ["{\\mathbf #1}",1], prodint: ["\\langle #1, #2 \\rangle",2], posto: ["{\\mathrm{posto} (#1)}",1], tr: ["{\\mathrm{tr} (#1)}",1] } } }); </script> ## *Bagging* (Breiman, 1994) - De modo geral, árvores de decisão produzem resultados com grande variância: produze resultados muito diferentes quando mudamos o conjunto de treinamento. - A técnica de *bagging* (*bootstrap aggregating*), em português **agregação bootstrap** visa contornar esse problema. - *Bagging* é um método para gerar múltiplas versões de um previsor a partir de vários conjuntos de treinamento, e com base nessas versões, criar um **previsor agregado**. - A variância desse previsor agregado deve ser menor do que a variância de cada um dos previsores individuais. - A ideia básica é considerar um conjunto de previsores *fracos* (alta taxa de erro) de modo a obter um previsor *forte* (baixa taxa de erro). - Como em geral, não dispomos de vários conjuntos de treinamento, a alternativa é utiliar amostras *bootstrap* do conjunto de treinamento disponÃvel. --- ## Diabetes ``` r library(rpart) library(rpart.plot) library(ipred) # libraria para bagging # treinamos um modelo bagged set.seed(12345) diabetes_bag <- bagging(Outcome ~ ., data = diabetes, nbagg = 200, coob = TRUE, control = rpart.control(minsplit = 20, cp = 0)) ``` --- ``` r diabetes_bag ``` ``` ## ## Bagging classification trees with 200 bootstrap replications ## ## Call: bagging.data.frame(formula = Outcome ~ ., data = diabetes, nbagg = 200, ## coob = TRUE, control = rpart.control(minsplit = 20, cp = 0)) ## ## Out-of-bag estimate of misclassification error: 0.2105 ``` ``` r tab <- table(diabetes$Outcome,predict(diabetes_bag, type = "class"))/nrow(diabetes) tab[1,1]+tab[2,2] ``` ``` ## [1] 0.7894737 ``` --- .center[ <!-- --> ] --- .center[ <!-- --> ] --- ## Com `caret::train()` ``` r library(caret) diabetes_bag2 <- train(Outcome ~ ., data = diabetes, method = "treebag", trControl = trainControl(method = "cv", number = 10), nbagg = 200, control = rpart.control(minsplit = 20, cp = 0)) ``` --- ``` r diabetes_bag2 ``` ``` ## Bagged CART ## ## 532 samples ## 7 predictor ## 2 classes: '0', '1' ## ## No pre-processing ## Resampling: Cross-Validated (10 fold) ## Summary of sample sizes: 479, 480, 480, 478, 479, 478, ... ## Resampling results: ## ## Accuracy Kappa ## 0.7764393 0.4739668 ``` --- ## Florestas aleatórias (para classificação): algoritmo 1. Utilize *bagging* para selecionar `\(B\)` amostras aleatórias do conjunto de treinamento. 2. Na construção de cada nó da árvore, em vez de escolher a melhor variável preditora dentre as `\(p\)` disponÃveis, escolha a melhor delas entre um conjunto de `\(m < p\)`, selecionadas por *bagging*. Usualmente `\(m \approx \sqrt{p}\)`. **Obs**. Não pode as árvores. 3. Para cada árvore construÃda, obtenha um classificador `\(\hat{f}_b\)`, `\(b=1, \ldots, B\)` e a correspondente classificação `\(\hat{f}_b(\mathbf{x}) = k\)` para os elementos do conjunto de dados. 4. A classe `\(k^*\)` escolhida para a observação `\(\mathbf{x}\)` é aquela em que o elemento do conjunto de treino com valor das variáveis preditoras igual a `\(\mathbf{x}\)` foi classificado pelo maior número de árvores (escolha feita pelo voto majoritário). --- ## Passo 1: Selecionar `\(B\)` amostras *boostrap* do conjunto de treinamento. - A amostra bootstrap terá o mesmo tamanho do banco original, e será usada como amostra para o treinamento. Em geral, selecionam-se amostras com cerca de 2/3 dos elementos do banco original. - Os elemnentos restantes fazem parte da chamada amostra *OOB* (*out of bag*). - Amostras *OOB* serão utilizadas para estimar a taxa de erros de classificação (amostra teste). --- ### Exemplo ``` r # banco de dados original <- 1:10 # fixamos a semente set.seed(12345) # geramos amostras bootstrap bootstrap <- sample(original, size = length(original), replace = TRUE) # amostras oob oob <- setdiff(original, bootstrap) # resultados cat("Amostra original: ",original,"\n") cat("Amostra bootstrap: ", bootstrap, "\n") cat("Amostras OOB: ", oob,"\n") cat("Número de OOBs: ", length(oob), "\n") ``` --- ``` ## Amostra original: 1 2 3 4 5 6 7 8 9 10 ``` ``` ## Amostra bootstrap: 3 10 8 10 8 2 6 6 7 10 ``` ``` ## Observações OOB: 1 4 5 9 ``` ``` ## Número de OOBs: 4 ``` --- ## Passo 2: Selecionamos `\(m\)` variáveis preditoras, por *bagging*, e construÃmos uma árvore de decisão. - Comumente, sorteamos, `\(m \approx \sqrt{p}\)`, em que `\(p\)` é o número de variáveis preditoras para construir a árvore de decisão. ## Passo 3: Repetimos os passos 1 e 2 acima `\(B\)` vezes, gerando `\(B\)` árvores de decisão. - Para cada `\(b = 1, \ldots, B\)`: - primeiro, sorteamos a amostra *bootstrap* para treino; - segundo, sorteamos `\(\sqrt{p}\)` variáveis preditoras e construÃmos uma árvore de decisão. --- ## Passo 4: Para classificar uma nova amostra aplicamos todas as árvores de decisão da nossa floresta e escolhemos como classificação final o candidato que teve mais votos. - Considere, por exemplo, o problema de classificação binária, em que temos as classes: SIM e NÃO. - Suponha que ajustamos `\(B=100\)` árvores de decissão e a nova amostra `\(\mathbf{x}_0\)`, e obtivermos: - 75 árvores classificaram `\(\mathbf{x}_0\)` como SIM; e - 25 árvores classificaram `\(\mathbf{x}_0\)` como NÃO. Então, `\(\mathbf{x}_0\)` será classificado como SIM. --- ## Predição *OOB* - Note que por construção do método, uma amostra pode ser OOB para algumas árvores e para outras não. - Para avaliar a taxa de erro *OOB* da floresta gerada, cada amostra será avaliada pelas árvores em que ela foi *OOB*. - Por exemplo, considere uma floresta aleatória, para classificação binária, com 20 árvores. E suponha que a amostra `\(\mathbf{x}^*\)` foi *OOB* nas árvores 5,10, e 15. Além disso, as previsões por cada árvore são: - `\(Arvore^{(5)} (\mathbf{x}^*) =\)` SIM - `\(Arvore^{(10)} (\mathbf{x}^*) =\)` SIM - `\(Arvore^{(15)} (\mathbf{x}^*) =\)` NÃO Portanto, a observação `\(\mathbf{\mathbf{x}}^*\)` será classificada como SIM. --- ## Taxa de erro OOB - A predição final OBB de cada observação é comparada com sua classe verdadeira. - Calculamos a taxa de erro OOB por `$$\text{Taxa de Erro OOB} = \frac{\text{Número de predições OOB incorretas}}{\text{Número de amostras com predições OOB}}.$$` --- Dados `diabetes`: ``` r library(randomForest) rf <- randomForest(Outcome ~ ., data = diabetes) rf ``` ``` ## ## Call: ## randomForest(formula = Outcome ~ ., data = diabetes) ## Type of random forest: classification ## Number of trees: 500 ## No. of variables tried at each split: 2 ## ## OOB estimate of error rate: 22.18% ## Confusion matrix: ## 0 1 class.error ## 0 311 44 0.1239437 ## 1 74 103 0.4180791 ``` --- ## Avaliando a taxa de erro OOB ``` r library(ggplot2) error_df <- data.frame(error_rate_OOB = rf$err.rate[, 'OOB'], num_trees = 1:rf$ntree) ggplot(data = error_df, aes(x=num_trees, y = error_rate_OOB)) + geom_line() + theme_minimal() ``` --- .center[ <!-- --> ] --- ## Importância das variáveis - Mede a contribuição de cada variável na predição. - Tipo 1: Decrescimo na acurácia. Permutamos a variável que desejamos ver seu efeito e calculamos a acurácia, antes de "bagunçar" e depois de "bagunçar", se decai a variável é importante. - Tipo 2: Redução da impureza. Calculamos a redução da impureza de Gini cada vez que a variável que desejamos ver seu efeito é usada para dividir um nó de alguma árvore da floresta e calculamos a soma total da redução causada por essa variável. Quanto maior mais importante. ``` r library(randomForest) rf2 <- randomForest(Outcome ~ ., data = diabetes, importance= TRUE) ``` --- .center[ <!-- --> ] --- ## Separando a base em treino/teste ``` r set.seed(12345) index_train <- caret::createDataPartition(y = diabetes$Outcome, p = 0.7, list = FALSE) training <- diabetes[index_train,] testing <- diabetes[-index_train,] ``` ``` r rf3 <- randomForest(Outcome ~ ., data = training, importance = TRUE) ``` --- ``` r rf3 ``` ``` ## ## Call: ## randomForest(formula = Outcome ~ ., data = training, importance = TRUE) ## Type of random forest: classification ## Number of trees: 500 ## No. of variables tried at each split: 2 ## ## OOB estimate of error rate: 25.74% ## Confusion matrix: ## 0 1 class.error ## 0 210 39 0.1566265 ## 1 57 67 0.4596774 ``` ``` r predictions <- predict(rf3,testing,"class") ``` --- ``` r caret::confusionMatrix(predictions,testing$Outcome) ``` ``` ## Confusion Matrix and Statistics ## ## Reference ## Prediction 0 1 ## 0 95 26 ## 1 11 27 ## ## Accuracy : 0.7673 ## 95% CI : (0.6938, 0.8306) ## No Information Rate : 0.6667 ## P-Value [Acc > NIR] : 0.003733 ## ## Kappa : 0.4365 ## ## Mcnemar's Test P-Value : 0.021359 ## ## Sensitivity : 0.8962 ## Specificity : 0.5094 ## Pos Pred Value : 0.7851 ## Neg Pred Value : 0.7105 ## Prevalence : 0.6667 ## Detection Rate : 0.5975 ## Detection Prevalence : 0.7610 ## Balanced Accuracy : 0.7028 ## ## 'Positive' Class : 0 ## ``` --- .center[ <!-- --> ]