Capítulo 4 Floresta Aleatória

Random Forest, ou Floresta Aleatória, método desenvolvido por (Breiman 2001), utiliza um conjunto de Árvores de Decisão para realizar tarefas de classificação ou regressão. Os métodos, como a Floresta Aleatória, que dá-se pela combinação de outros métodos são denominados como ensemble. O conceito fundamental das Florestas Aleatórias é a sabedoria das multidões: um número grande de modelos não correlacionados, no caso as árvores, operando em conjunto irão performar melhor do que cada modelo individual.

Antes de apresentar o método veja um experimento feito com 50 pessoas, para ilustrar a ideia da sabedoria das multidões. Cada pessoa viu uma foto de uma garrafa de 300ml, transparente, com grãos de feijão nela. Mais ou menos até a metade da garrafa. Em seguida cada participante deu um palpite sobre o número grãos de feijão na garrafa.

A quantidade exata de grãos de feijão na garrafa era 524, valor marcado com a linha em preto no gráfico apresentado na 4.1. As linhas pontilhadas em preto representam um intervalo de raio 100, ou seja, estão nos números 424 e 624. Cada palpite de um participante é um ponto vermelho. Veja que a maioria dos palpites estão fora do intervalo pontilhado, que mostra que a maioria dos participantes não deram um bom palpite. O normal é errar mesmo. Mas quando calculamos o valor médio dos palpites, linha pontilhada em vermelho, temos um palpite muito melhor do que os palpites individuais.

Resultado do Experimento sobre a Sabedoria das Multidões

Figura 4.1: Resultado do Experimento sobre a Sabedoria das Multidões

A ideia da Floresta Aleatória é essa: em vez de construir uma única árvore para realizar previsões serão construídas muitas árvores, diferentes entre si. A previsão final será a média da previsão de todas as árvores.

Floresta Aleatória

Figura 4.2: Floresta Aleatória

Seguem algumas vantagens da Floresta Aleatória em relação à uma única árovre de decisão:

  • Alta precisão: A Random Forest geralmente produz resultados mais precisos em comparação com um único modelo de árvore de decisão, especialmente quando o conjunto de dados é grande e complexo.

  • Resistência ao overfitting: Ao combinar previsões de várias árvores, a Foresta Aleatória reduz o risco de overfitting, ou seja, de criar um modelo excessivamente ajustado aos dados de treinamento e com baixa capacidade de generalização para novos dados.

  • Melhor desempenho com bases contendo outliers: uma vez que cada árvore da floresta é gerada por uma amostra bootstrap das observações (linhas), a observações com outliers nem sempre serão selecionadas, e com isso estes valores atípicos não geram uma grande influência no resultado final.

  • Melhor absorção da informação contida em cada covariável: como as partições das árvores da floresta consideram um seleção das covariáveis (colunas), algumas partições não levam em consideração a covariável mais importante e com isso outras variáveis conseguem exercer influência no resultado final.

4.1 Bagging

A Floresta Aleatória é um modelo com bagging. Um modelo com bagging é uma abordagem de aprendizado de máquina ensemble que combina múltiplos modelos individuais em um único modelo mais robusto e preciso. O termo “bagging” é uma abreviação de “bootstrap aggregating”, que se refere às duas principais etapas do processo.

O processo começa gerando várias amostras de treinamento com reposição a partir do conjunto de dados original. Isso significa que cada amostra é obtida aleatoriamente, permitindo que uma mesma amostra apareça múltiplas vezes e outras possam não ser selecionadas. O objetivo é criar várias versões do conjunto de treinamento, cada uma com pequenas variações nos dados de entrada.

Ilustração do Bagging

Figura 4.3: Ilustração do Bagging

Em seguida, um modelo individual é treinado em cada uma das amostras de treinamento geradas no passo anterior. No caso da Floresta Aleatória, este modelo individual é a Árvore de Decisão.

Ao fazer uma previsão usando o modelo com bagging, as previsões de cada modelo individual são combinadas para obter uma única previsão final. O bagging ajuda a reduzir o overfitting, pois as variações introduzidas nas amostras de treinamento aumentam a diversidade dos modelos individuais.

Segundo (James et al. 2013), o bagging é particularmente útil para árvores de decisão. Para aplicar o bagging no Modelo de Árvores de Decisão simplesmente contrói-se \(B\) árvores de decisão usando os \(B\) conjuntos de treinamento gerados pelo bootstrap. Essas árvores são cultivadas profundamente, ou seja, deixamos elas crescere o quanto quiserem. Portanto, cada árvore individual tem alta variância, mas baixo viés.

4.2 Partições

Neste momento já ficou claro porque a Floresta se chama Aleatória. Mas o bagging não é a única parte aleatória da floresta. Na costrução de uma árvore da Floresta Aleatória, cada vez que uma divisão em um nó da árvore será realizado, um sorteio de \(m\) covariáveis, entre todas as \(p\) covariáveis da base, é realizado. As covariáveis selecionadas serão as únicas candidatas à realizar a partição no nó.Uma nova amostra de \(m\) covariáveis é selecionada em cada divisão da árvore e, tipicamente, escolhe-se \(m \approx \sqrt{p}\).

A decisão de não usar todas as covariáveis como candidatas para uma partição em um nó reduz a correlação entre as árvores da floresta. Como a saída de uma Floresta aleatória é feita, em geral, pela média das saídas de cada árvore, a redução da correlação entre as árvores reduz a variância da saída do método, tornando mais confiável.

Uma outra vantagem neste processo é que ao considerar apenas um subconjunto das covariáveis, em muitos nós a partição é realizada sem que a covariáveis mais importante seja uma candidata. Isto permite que outras covariáveis tenham mais chances de serem escolhidas.

4.3 Regressão x Classificação

Até o momento só foi falado sobre árvores de decisão, de forma geral, sem diferenciar o caso de regressão do de classificação. A única diferença entre os dois casos é que para regressão a Floresta Aleatória é uma floresta de árvores de regressão, enquanto que para classificação, é uma floresta de árvores de classificação.

A previsão também é semelhante, a resposta que a Floresta Aleatória retorna é a média simples das respostas de todas as árvores. Ou seja, a nova observação, para a qual queremos fazer uma previsão, é colocada como dado de entrada em todas as árvores da floresta e cada árvore retorna um valor de previsão. A previsão da floresta aleatória será a média das previsões das árvores.

4.4 Algoritmo

Considere uma base de dados supervisionada, onde \(Y\) é a variável resposta (qualitativa ou quantitativa) e \(X_j\), \(j=1, 2, \ldots, p\) são as \(p\) covariáveis. Para cada observação \(i\), \(i=1, 2, \ldots, n\), isto é, para cada linha \(i\) da base, temos \(Y_i\) o valor da variável resposta para a observação \(i\) e \(X_{i,j}\) o valor ca covariável \(j\) para a observação \(i\). Posto isso, segue o algorítimo para o Método de Floresta Aleatória.

Escolhe-se o valor do hiperparâmtro \(B\), que é o número de árvores na floresta.

  1. Faça \(b=1\) .

  2. Selecione uma amostra de tamanho \(n\) do banco de treino a partir do método bootstrap, com reposição (bagging).

  3. A amostra selecionada será a base de dados de entrada de uma nova árvore, vamos chamá-la de \(X\).

  4. Faça um sorteio aleatório simples, sem reposição, de \(\sqrt{p}\) covariáveis entre as \(p\) covariáveis de \(X\). Vamos chamar de \(J\) o conjunto dos índices das covariáveis sorteadas.

  5. Defina a covariável \(j \in J\) e o valor \(s \in \mathrm{R}\) tais que minimizam a soma dos índices Gini, para o caso de um problema de classificação, ou o \(RSS\), para o caso de um problema de regressão, nas regiões \(R_1 = \{X|X_j < s\}\) e \(R_2 = \{X|X_j \ge s\}\).

  6. Verifique se em \(R_1\) um dos critérios de parada foi atingido. Se sim, este nó é uma folha e vá para o passo 8. Se não, faça \(X = R_1\) e volte para o passo 4.

  7. Verifique se em \(R_2\) um dos critérios de parada foi atingido. Se sim, este nó é uma folha e vá para o passo 8. Se não, faça \(X = R_2\) e volte para o passo 4.

  8. Faça \(b = b + 1\). Se \(b \le B\), volte para o passo 2. Caso contrário, FIM.

4.5 Como realizar previsões

Uma vez a floresta construída, ela pode ser usada para prever a variável resposta de novas observações. Para isso a nova observação passa a ser dado de entrada para todas as árvores da floresta. Cada uma das \(B\) árvores fornece uma previsão para a nova observação, vamos chamar de \(\hat{y}^b\) a previsão feita pela árvore \(b\) para a entrada \(y\). A previsão da floresta será:

\[ \hat{y} = \dfrac{\sum_{b=1}^B \hat{y}^b}{B} \]

4.6 Vamos praticar

Vamos repetir a prática dos dois últimos capítulos, mas agora com a Floresta Aleatória.

# Carregar pacotes e base de treino
library(tidyverse)
library(rpart)
base_treino = readRDS(file="arquivos-de-trabalho/base_treino_final.rds")

Para criar modelos de Floresta Aleatória será usado o pacote randomForest (Liaw and Wiener 2002).

#install.packages("randomForest")
library(randomForest)

Como o processo de criação das árvores trabalha com sorteios, é importante fixar a semente para garantir a reprodutibilidade do código.

set.seed(123456789)

Regressão

Vejamos os resultados das regressões já feitas para a árvore de regressão agora com o método da Floresta Aleatória.

Nota de Redação

Primeiro será ajustado um modelo para prever a nota em redação das escolas. A função a ser usada é a randomForest, do pacote de mesmo nome. No primeiro argumento desta função, x, deve ser colocadas as covariáveis. No argumento y é informado a variável alvo.

Ajuste do Modelo

Não é preciso informar se o modelo é de classificação ou regressão. A função identifica o tipo da variável y e automaticamente escolhe regressão se ela for numérica ou classificação se ela for fator.

rf_RD <- randomForest(x =  base_treino |>
                        select(-c(NU_TAXA_PARTICIPACAO, 
                                  NU_MEDIA_CN, 
                                  NU_MEDIA_CH, 
                                  NU_MEDIA_LP, 
                                  NU_MEDIA_MT, 
                                  NU_MEDIA_RED, 
                                  CO_ESCOLA_EDUCACENSO,
                                  NO_ESCOLA_EDUCACENSO,
                                  NU_PARTICIPANTES)), 
                      y = base_treino$NU_MEDIA_RED, ntree=500)
saveRDS(rf_RD,file = "arquivos-de-trabalho/rf_RD.rds")

As variáveis importantes para esse modelo são guardadas no próprio objeto gerado pela função randomForest.

Variáveis Importantes
importancia = rf_RD$importance
sort(importancia[,1],decreasing = TRUE)
## TP_DEPENDENCIA_ADM_ESCOLA                      INSE          NU_TAXA_ABANDONO 
##                18768178.1                13259812.2                 7931482.5 
##              SG_UF_ESCOLA       PC_FORMACAO_DOCENTE        NU_TAXA_REPROVACAO 
##                 7729902.0                 4909349.5                 4040871.1 
##             NU_MATRICULAS       NU_TAXA_PERMANENCIA              PORTE_ESCOLA 
##                 3936378.0                 3771669.2                 1083390.0 
##  NU_PARTICIPANTES_NEC_ESP     TP_LOCALIZACAO_ESCOLA 
##                  815759.7                  350065.4
Previsão para novas observações

Aqui na nova observação as variáveis categóricas são informadas como fator e, o que é importante, é preciso que os fatores tenham os mesmos levels. Por isso o código da base de dados para previsão será montada diferente da do último capítulo.

SG_UF_ESCOLA = 
  factor(x = c("RJ","SP","MG","AM","RS"),
         levels = levels(base_treino$SG_UF_ESCOLA))

TP_DEPENDENCIA_ADM_ESCOLA = 
  factor( x = c("Estadual","Privada","Estadual","Municipal","Federal"),
          levels = levels(base_treino$TP_DEPENDENCIA_ADM_ESCOLA))

TP_LOCALIZACAO_ESCOLA = 
  factor(x = c("Urbana","Urbana","Urbana","Rural","Urbana"),
         levels = levels(base_treino$TP_LOCALIZACAO_ESCOLA))


INSE = factor(x = c("Grupo 3","Grupo 6","Grupo 4","Grupo 2","Grupo 4"),
              levels = levels(base_treino$INSE))

PORTE_ESCOLA = factor(x = c("De 61 a 90 alunos","Maior que 90 alunos","De 61 a 90 alunos","De 31 a 60 alunos","Maior que 90 alunos"),
                      levels = levels(base_treino$PORTE_ESCOLA))

NU_MATRICULAS = c(87,44,102,21,80)

NU_PARTICIPANTES_NEC_ESP = c(1,2,0,0,1)

PC_FORMACAO_DOCENTE = c(48.1 , 75.7 , 68.8 , 51.2 , 70.3)

NU_TAXA_PERMANENCIA = c(67,100,92,87,75)

NU_TAXA_REPROVACAO = c(6.1,3.3, 9.1, 8.7,5.6)

NU_TAXA_ABANDONO = c(0,0,1, 2, 3)

escola = tibble(SG_UF_ESCOLA ,  
                TP_DEPENDENCIA_ADM_ESCOLA, 
                TP_LOCALIZACAO_ESCOLA , 
                NU_MATRICULAS , 
                NU_PARTICIPANTES_NEC_ESP ,
                INSE ,
                PC_FORMACAO_DOCENTE , 
                NU_TAXA_PERMANENCIA , 
                NU_TAXA_REPROVACAO ,  
                NU_TAXA_ABANDONO ,  
                PORTE_ESCOLA)
predict(rf_RD, newdata = escola)
##        1        2        3        4        5 
## 496.5097 674.8462 552.3417 516.4380 592.1234

4.6.0.1 Nota de Matemática

Os mesmos passos serão repetidos para a nota de matemática.

Ajuste do Modelo
rf_MT <- randomForest(
  x =  base_treino |> 
    select(-c(NU_TAXA_PARTICIPACAO,
              NU_MEDIA_CN,
              NU_MEDIA_CH,
              NU_MEDIA_LP, 
              NU_MEDIA_MT,
              NU_MEDIA_RED,
              CO_ESCOLA_EDUCACENSO,
              NO_ESCOLA_EDUCACENSO,
              NU_PARTICIPANTES)),
  y = base_treino$NU_MEDIA_MT, 
  ntree=500)
saveRDS(rf_MT,file = "arquivos-de-trabalho/rf_MT.rds")
Variáveis Importantes
importancia = rf_MT$importance
sort(importancia[,1],decreasing = TRUE)
##                      INSE TP_DEPENDENCIA_ADM_ESCOLA              SG_UF_ESCOLA 
##                17100690.9                11849612.6                 5640099.9 
##          NU_TAXA_ABANDONO       PC_FORMACAO_DOCENTE       NU_TAXA_PERMANENCIA 
##                 5222819.8                 3203708.3                 2840186.6 
##             NU_MATRICULAS        NU_TAXA_REPROVACAO              PORTE_ESCOLA 
##                 2693996.3                 2586864.2                  779179.8 
##  NU_PARTICIPANTES_NEC_ESP     TP_LOCALIZACAO_ESCOLA 
##                  428176.8                  128173.5
Previsão para novas observações
predict(rf_MT, newdata = escola)
##        1        2        3        4        5 
## 457.7980 640.1608 488.2122 439.1422 529.1003

Classificação Binária

A principal difereça será que neste caso teremos que criar a variável alvo, que não está na base.

4.6.0.2 Nota de Redação

base_treino_RED = base_treino |> 
  mutate(NOTA_RED = ifelse(base_treino$NU_MEDIA_RED>=600,"boa","regular")) |>
  select(-c(NU_TAXA_PARTICIPACAO,
            NU_MEDIA_CN,
            NU_MEDIA_CH,
            NU_MEDIA_LP, 
            NU_MEDIA_MT,
            NU_MEDIA_RED,
            CO_ESCOLA_EDUCACENSO,
            NO_ESCOLA_EDUCACENSO,
            NU_PARTICIPANTES
  ))
base_treino_RED$NOTA_RED = as.factor(base_treino_RED$NOTA_RED)
Ajuste do Modelo
rf_RED <- randomForest(x =  base_treino_RED |> select(-NOTA_RED),
                       y = base_treino_RED$NOTA_RED , 
                       ntree=500)
saveRDS(rf_RED,file = "arquivos-de-trabalho/rf_RED.rds")
Variáveis Importantes
importancia = rf_RED$importance
sort(importancia[,1],decreasing = TRUE)
## TP_DEPENDENCIA_ADM_ESCOLA                      INSE              SG_UF_ESCOLA 
##                1055.14719                 755.09395                 497.67042 
##       PC_FORMACAO_DOCENTE          NU_TAXA_ABANDONO       NU_TAXA_PERMANENCIA 
##                 446.43378                 445.93058                 394.84455 
##        NU_TAXA_REPROVACAO             NU_MATRICULAS              PORTE_ESCOLA 
##                 391.63084                 380.26797                  85.36660 
##  NU_PARTICIPANTES_NEC_ESP     TP_LOCALIZACAO_ESCOLA 
##                  68.38661                  15.03753
Previsão para novas observações
predict(rf_RED, newdata = escola, type="prob")
##     boa regular
## 1 0.024   0.976
## 2 0.756   0.244
## 3 0.074   0.926
## 4 0.072   0.928
## 5 0.354   0.646
## attr(,"class")
## [1] "matrix" "array"  "votes"

Nota de Matemática

base_treino_MAT = base_treino |> 
  mutate(NOTA_MAT = ifelse(base_treino$NU_MEDIA_MT>=600,"boa","regular")) |>
  select(-c(NU_TAXA_PARTICIPACAO,
            NU_MEDIA_CN,
            NU_MEDIA_CH,
            NU_MEDIA_LP, 
            NU_MEDIA_MT,
            NU_MEDIA_RED,
            CO_ESCOLA_EDUCACENSO,
            NO_ESCOLA_EDUCACENSO,
            NU_PARTICIPANTES
  ))
base_treino_MAT$NOTA_MAT = as.factor(base_treino_MAT$NOTA_MAT)
Ajuste do Modelo
rf_MAT <- randomForest(x = base_treino_MAT |> select(-NOTA_MAT),
                       y = base_treino_MAT$NOTA_MAT , 
                       ntree=500)
saveRDS(rf_MAT,file = "arquivos-de-trabalho/rf_RED.rds")
Variáveis Importantes
importancia = rf_MAT$importance
sort(importancia[,1],decreasing = TRUE)
## TP_DEPENDENCIA_ADM_ESCOLA                      INSE              SG_UF_ESCOLA 
##                1055.14719                 755.09395                 497.67042 
##       PC_FORMACAO_DOCENTE          NU_TAXA_ABANDONO       NU_TAXA_PERMANENCIA 
##                 446.43378                 445.93058                 394.84455 
##        NU_TAXA_REPROVACAO             NU_MATRICULAS              PORTE_ESCOLA 
##                 391.63084                 380.26797                  85.36660 
##  NU_PARTICIPANTES_NEC_ESP     TP_LOCALIZACAO_ESCOLA 
##                  68.38661                  15.03753
Previsão para novas observações
predict(rf_MAT, newdata = escola, type="prob")
##     boa regular
## 1 0.024   0.976
## 2 0.756   0.244
## 3 0.074   0.926
## 4 0.072   0.928
## 5 0.354   0.646
## attr(,"class")
## [1] "matrix" "array"  "votes"

Classificação Multiclasses

4.6.0.3 Nota da redação

base_treino_RED_3 = base_treino |>
  mutate(NOTA_RED = 
           ifelse(
             base_treino$NU_MEDIA_RED>600,"boa",
             ifelse(base_treino$NU_MEDIA_RED<500,"ruim",
                    "regular"))) |>
  select(-c(NU_TAXA_PARTICIPACAO,
            NU_MEDIA_CN,
            NU_MEDIA_CH,
            NU_MEDIA_LP, 
            NU_MEDIA_MT,
            NU_MEDIA_RED,
            CO_ESCOLA_EDUCACENSO,
            NO_ESCOLA_EDUCACENSO,
            NU_PARTICIPANTES
  ))
base_treino_RED_3$NOTA_RED = as.factor(base_treino_RED_3$NOTA_RED)
summary(base_treino_RED_3$NOTA_RED)
##     boa regular    ruim 
##    3278    6126    2296
Ajuste do Modelo
rf_RED_3 <- randomForest(x =  base_treino_RED_3 |> select(-NOTA_RED),
                         y = base_treino_RED_3$NOTA_RED , 
                         ntree=500)
saveRDS(rf_RED_3,file = "arquivos-de-trabalho/rf_RED_3.rds")
Variáveis Importantes
importancia = rf_RED_3$importance
sort(importancia[,1],decreasing = TRUE)
##              SG_UF_ESCOLA       PC_FORMACAO_DOCENTE                      INSE 
##                 899.02614                 867.82477                 856.75535 
## TP_DEPENDENCIA_ADM_ESCOLA       NU_TAXA_PERMANENCIA        NU_TAXA_REPROVACAO 
##                 822.59051                 770.76462                 756.52912 
##             NU_MATRICULAS          NU_TAXA_ABANDONO  NU_PARTICIPANTES_NEC_ESP 
##                 745.30381                 728.47047                 168.25453 
##              PORTE_ESCOLA     TP_LOCALIZACAO_ESCOLA 
##                 166.06530                  41.00323
Previsão para novas observações
predict(rf_RED_3, newdata = escola, type = "prob")
##     boa regular  ruim
## 1 0.030   0.246 0.724
## 2 0.766   0.234 0.000
## 3 0.080   0.788 0.132
## 4 0.046   0.474 0.480
## 5 0.440   0.550 0.010
## attr(,"class")
## [1] "matrix" "array"  "votes"

4.7 Atividade

Trabalhar novamente com a base Bike Sharing Dataset.

  1. Ajuste um modelo de Floresta Aleatória para prever a quantidade de bicicletas alugadas (regressão).
  1. Identifique as variáveis importantes para o modelo.
  2. Faça uma previsão com valores hipotéticos.
  1. Ajuste um modelo de Floresta Aleatória para prever se a quantidade de bicicletas alugadas será ou não menor que abaixo de 4.000 (classificação binária).
  1. Identifique as variáveis importantes para o modelo.
  2. Faça uma previsão com valores hipotéticos.
  1. Ajuste um modelo de Floresta Aleatória para prever se a quantidade de bicicletas ficará em qual das três faixas: [0,4.000), [4.000,6.000) ou [6.000,\(\infty\)) (multiclasses).
  1. Identifique as variáveis importantes para o modelo.
  2. Faça uma previsão com valores hipotéticos.

4.8 Referências

References

Breiman, Leo. 2001. “Random Forests.” Machine Learning 45: 5–32.
James, Gareth, Daniela Witten, Trevor Hastie, and Robert Tibshirani. 2013. An Introduction to Statistical Learning. Vol. 112. Springer.
Liaw, Andy, and Matthew Wiener. 2002. “Classification and Regression by randomForest.” R News 2 (3): 18–22. https://CRAN.R-project.org/doc/Rnews/.