Aula 13: Árvores de Regressão
1 Árvore de regressão
Quando usamos uma árvore de decisão para prever um valor contínuo, estamos trabalhando com uma árvore de regressão.
A construção da árvore de regressão segue a mesma lógica e procedimento que para árvores de classificação, exceto que a impureza dos nós é medida pelos desvios quadráticos da média (erros quadráticos) em cada divisão, e o desempenho preditivo é avaliado pelo RMSE.
Em uma árvore de classificação, a classe de cada nó folha é atribuida pela classe mais frequente de todas as observações naquele nó. Em uma árvore de regressão, a resposta de um nó \(a\), precisa ser um valor constante.
2 Atribuindo o valor do nó folha
Seja \(\mathcal{L} = \{(\mathbf{x}_i,y_i): \mathbf{x}_i \in \mathbb{R}^p, y_i \in \mathbb{R}, i= 1, \ldots, n\}\) o conjunto de dados de treino. Para uma árvore \(T\), denotamos por \(\widetilde{T} = \{a_1, \ldots, a_L\}\) o conjunto de seus nós folhas.
Definimos a impureza do nó \(a\) por
\[I(a) = \sum_{i: \mathbf{x}_i \in a}(y_i - \hat{y}_i(a))^2,\] em que \(y_i\) é a resposta da i-ésima unidade de investigação pertencente ao nó \(a\) e \(\hat{y}_i(a)\) é o valor que minimiza o erro de resubstituição: \[R(T) = \frac{1}{n}\sum_{a \in \widetilde{T}} \sum_{i: \mathbf{x}_i \in a} (y_i - \hat{y}_i(a))^2 = \sum_{l=1}^L R(a_l),\] em que \[R(a_l) = \frac{1}{n}\sum_{i: \mathbf{x}_i \in a} (y_i - \hat{y}_i(a))^2 = p(a_l)s^2(a_l),\] \(\displaystyle s^2(a_l) = \frac{1}{n(a_l)}\sum_{i:\mathbf{x}_i \in a_l} (y_i - \hat{y}_i(a_l))^2\) e \(p(a_l) = n(a_l)/n\).
Portanto, \[\hat{y}_i(a) = \frac{1}{n(a)}\sum_{i:\mathbf{x}_i \in a} y_i,\] ou seja, é a média das observações de \(y\) que pertencem ao nó \(a\).
3 Estratégia de divisão
Como antes, para cada variável de entrada \(X_j\) escolhemos aquela divisão \(d\) do nó pai \(a_p\) em seus dois nós filhos \(a_e\) e \(a_d\), que tenha o maior ganho de informação (ou seja, a maior redução no erro de resubstituição): \[\begin{align}IG(a_p,d) = \Delta(a_p,d) &= I(a_p) - \frac{n(e)}{n(p)}I(a_e)-\frac{n(d)}{n(p)}I(a_d)\\ &=R(a_p) - R(a_e)-R(a_d),\end{align}\] em que \(n(p), n(e)\) e \(n(d)\), são o número de observações no nó pai, no nó filho esquerdo e o nó filho direito, respectivamente.
4 Poda da árvore
Como antes, primeiro fazemos crescer uma árvore muito grande, \(T_\max\), dividindo os nós repetidamente até que cada nó contenha menos que um número mínimo de observações \(n_\min\), isto é, \(n(a) \leq n_\min\), para cada nó folha \(a \in \widetilde T\), tipicamente, fixamos \(n_\min = 5\).
Logo, calculamos a medida do custo de complexidade por \[R_\alpha(T) = R(T) + \alpha|\widetilde{T}|,\]
em que \(\alpha \geq 0\) é um parâmetro de complexidade. E usamos \(R_\alpha(T)\) na mesma maneira que foi usado para fazer a poda de uma árvore de classificação.
5 Prevendo o salário dos jogadores da Major League Baseball
O conjunto de dados consiste em informações sobre jogadores da Major League Baseball. A variável de resposta são seus salários de 1992 (medidos em milhares de dólares e obtidos do New York Times de 19 de novembro de 1992). Possíveis variáveis explicativas incluem diversas medidas do desempenho dos jogadores em 1991. Esses dados foram obtidos do Sacramento Bee de 15 de outubro de 1991. Mais detalhes podem ser encontrados em Watnik,1998.
Obs. Os alunos que não estão familiarizados com beisebol podem ser informados de que, com exceção de strike-outs e erros, todas essas variáveis seriam sensatamente correlacionadas positivamente com o salário.
# Carregando os dados
mlb <- read.csv("mlb.txt")
# Removendo os nomes dos jogadores
mlb <- mlb[,-18]
# Renomeando as vars indicadoras
names(mlb)[c(14,15,16,17)] <- c("FAE","FA","AE","A") library(rpart)
library(rpart.plot)
# Ajustando a árvore
set.seed(12345)
mlb_rpart <- rpart::rpart(Salary ~ .,
data = mlb,
method = "anova",
xval = 30,
cp = 0.00011)A continuação, apresentamos os resultados da validação cruzada para a escolha do parâmetro de complexidade:
##
## Regression tree:
## rpart::rpart(formula = Salary ~ ., data = mlb, method = "anova",
## xval = 30, cp = 0.00011)
##
## Variables actually used in tree construction:
## [1] AE Doubles FA FAE Hits HR OBP RBI Runs
## [10] SB SO
##
## Root node error: 516644690/337 = 1533070
##
## n= 337
##
## CP nsplit rel error xerror xstd
## 1 0.33946196 0 1.00000 1.00863 0.089271
## 2 0.14117583 1 0.66054 0.77075 0.075663
## 3 0.08888501 2 0.51936 0.65380 0.065270
## 4 0.05133621 3 0.43048 0.50514 0.057393
## 5 0.04766668 4 0.37914 0.50009 0.057105
## 6 0.03075163 5 0.33147 0.41532 0.046408
## 7 0.02166442 6 0.30072 0.40437 0.045434
## 8 0.02095516 7 0.27906 0.39333 0.044282
## 9 0.01992146 8 0.25810 0.38403 0.044419
## 10 0.01520262 9 0.23818 0.34130 0.045321
## 11 0.00858541 10 0.22298 0.32188 0.044154
## 12 0.00474248 11 0.21439 0.34416 0.046773
## 13 0.00440260 12 0.20965 0.36711 0.047633
## 14 0.00439663 13 0.20525 0.36782 0.047623
## 15 0.00349045 14 0.20085 0.36198 0.047531
## 16 0.00253731 15 0.19736 0.36898 0.048096
## 17 0.00156020 16 0.19482 0.37147 0.048106
## 18 0.00085416 17 0.19326 0.37060 0.048103
## 19 0.00063415 18 0.19241 0.37311 0.048066
## 20 0.00061661 20 0.19114 0.37265 0.047978
## 21 0.00038316 21 0.19052 0.37302 0.047972
## 22 0.00030215 22 0.19014 0.37368 0.047781
## 23 0.00021399 23 0.18984 0.37411 0.047774
## 24 0.00018508 24 0.18963 0.37412 0.047773
## 25 0.00011000 25 0.18944 0.37424 0.047771
Pelo observado nos gráficos acima a árvore de regressão podada para os dados da mlb, o menor valor do erro relativo, obtido por VC, ocorre para uma árvore com 10 divisões e 11 nós folhas.
cpmin <- mlb_rpart$cptable[which.min(mlb_rpart$cptable[,"xerror"])]
mlb_poda <- prune(mlb_rpart, cp = cpmin)
rpart.plot(mlb_poda, clip.right.labs = TRUE, under = FALSE, extra = 101, type = 4)##
## Regression tree:
## rpart::rpart(formula = Salary ~ ., data = mlb, method = "anova",
## xval = 30, cp = 0.00011)
##
## Variables actually used in tree construction:
## [1] AE FAE RBI Runs SB
##
## Root node error: 516644690/337 = 1533070
##
## n= 337
##
## CP nsplit rel error xerror xstd
## 1 0.3394620 0 1.00000 1.00863 0.089271
## 2 0.1411758 1 0.66054 0.77075 0.075663
## 3 0.0888850 2 0.51936 0.65380 0.065270
## 4 0.0513362 3 0.43048 0.50514 0.057393
## 5 0.0476667 4 0.37914 0.50009 0.057105
## 6 0.0307516 5 0.33147 0.41532 0.046408
## 7 0.0216644 6 0.30072 0.40437 0.045434
## 8 0.0209552 7 0.27906 0.39333 0.044282
## 9 0.0199215 8 0.25810 0.38403 0.044419
## 10 0.0152026 9 0.23818 0.34130 0.045321
## 11 0.0085854 10 0.22298 0.32188 0.044154
O erro de resubstituição da árvore de regressão, após a poda, é \(R(T) = 1533070 \times 0,22298 = \$341843,9\). Uma estimativa mais realista pode ser obtido pela VC e é igual \(R^{VC}(T) = 1533070 \times 0.32188 =\$493464,6\), com um desvio padrão de \(DP^{VC}(T)=1533070 \times 0.044154 = \$67691,17\).
6 Comentários finais
Em geral, árvores com muitos nós folhas apresentam bom desempenho no conjunto de treino, mas um desempenho pobre nos dados de teste, o que siginifica que podem estar associadas a sobreajuste.
Árvores com um número menor de subdivisões oferecem resultados com menor variância e mais interpretatibilidade.
A poda pode ser feita durante o treinamento (construção da árvore), isto é uma pré-poda, por exemplo, fixando um número mínimo de nós que deve conter cada nó folha.
A poda propriamente dita consiste em construir uma árvore muito grande e logo aplicamos uma regra de eliminação de alguns dos nós folhas. Neste caso, usamos o parâmetro de complexidade para controlar o tamanho da árvore.