class: center, middle, inverse, title-slide #
Statistical Learning:
## Árvores de Decisão ### Prof. Carlos Trucíos
FACC/UFRJ
ctruciosm.github.io
carlos.trucios@facc.ufrj.br
### Grupo de Estudos CIA, – Causal Inference and Analytics – ### 2021-10-08 --- layout: true <a class="footer-link" href="http://ctruciosm.github.io">ctruciosm.github.io — Carlos Trucíos (FACC/UFRJ)</a> ---
# Motivação - Suponha que queremos um modelo preditivo para salários dos jogadores de futebol no Brazil ( `\(Y\)` ) em função de um conjunto de variáveis explicativas ( `\(X_1, X_2, \ldots, X_k\)` ). -- - Uma alternativa seria fazer um modelo de regressão do tipo `$$Y = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + \cdots + \beta_k X_k + u.$$` -- - Mas, o que fazer se a relação entre `\(Y\)` e as `\(X\)`s não for linear? -- - Podemos tentar aplicar transformações nas variáveis, mas... se isso não funcionar? -- - Uma alternaiva é `segmentar` a variável target `\(Y\)` em várias regiões (em função de suas caracteristicas contidas nas `\(X\)`s). Assim, para fazer a predição de uma observação qualquer, pegamos a média do segmento onde se encontra. > Veremos isto com um exemplo 👨🏫 --- class: inverse, right, middle # Árvore de Decisão --- ## Árvore de Decisão --- ## Árvore de Decisão **A ideia por trás da árvore de decisão é a seguinte:** .blue[ 1. Dividir o espaço dos preditores ( `\(X_1,X_2, \ldots, X_k\)`) em J regiões diferentes não sobrepostas, `\(R_1, R_2, \ldots, R_J\)`. 2. Para cada nova observação que cair na região `\(R_J\)` teremos a a mesma predição, que será igual à média da variável `\(Y\)` (nos dados de treinamento) na região `\(R_J\)`. ] -- **Mas como são construidas essas regiões `\(R_1, R_2, \ldots, R_J\)`?** -- A princípio, podemos obter os `\(R_1, R_2, \ldots, R_J\)` de forma que minimizem `$$\displaystyle \sum_{j=1}^J \sum_{i \in R_j} (y_i - \bar{y}_{R_j})^2$$` -- Infelizmente, testar todas as possíves escolhas para as regiões `\(R_1, R_2, \ldots, R_J\)` é impraticável 😢. -- .red[Mas existem algumas alternativas para lidar com este problema. Veremos um exemplo no ilustrativo no **R** e depois veremos como funciona o algoritmo.] --- ## Árvore de Decisão: Exemplo simples ```r # Carregamos os pacotes library(tidymodels) library(ISLR) library(rpart) library(rpart.plot) # Dividimos os dados em treinamento e teste set.seed(1234) Hitters <- na.omit(Hitters) split_data <- initial_split(data = Hitters) train_data <- training(split_data) test_data <- testing(split_data) # Aplicamos a árvore de decisão nos dados de treinamento. Hitters_tree <- rpart(Salary ~ . , data = train_data) ``` -- Escreva no R: 1. `Hitters_tree` 2. `prp(Hitters_tree, digits = 4, extra = 1)` -- **Qual a diferença?** --- ## Árvore de Decisão: 1. .red[Entre todas as `\(X_1, \cdots, X_k\)` e possíveis valores de `\(s\)`, buscamos a melhor `\(X_j\)` e o ponto de corte `\(s_1\)` tal que minimizem `$$\displaystyle \sum_{i: x_i \in R_1} (y_i - \bar{y}_{R_1})^2 + \displaystyle \sum_{i: x_i \in R_2} (y_i - \bar{y}_{R_2})^2,$$` em que `\(R_1 = \{X | X_j > s_1\}\)` e `\(R_1 = \{X | X_j \leq s_1\}.\)`] -- 2. .green[Usando um procedimento semelhante, buscamos o mehor `\(X_i\)` e ponto de corte `\(s_2\)` tal que a soma de quadrados dos resísuos seja minimizada. A diferença do passo anterior, dividimos alguma das regiões `\(R_1\)` ou `\(R_2\)` de forma que teremos agora 3 regiões diferentes `\(R_1, R_2, R_3\)`.] -- 3. .blue[Buscamos outra variavel `\(X_m\)` e ponto de corte `\(s_3\)` tal que a soma de quadrados dos resísuos seja minimizada. Assim como no passo anterior, dividimos alguma das regiões `\(R_1\)`, `\(R_2\)`, `\(R_3\)` de forma que teremos agora 4 regiões diferentes `\(R_1, R_2, R_3, R_4\)`.] -- ... O mesmo procedimento é feito várias vezes até atingir algum critério de parada. --- ## Árvore de Decisão Uma vez que as regiões `\(R_1, R_2, \cdots, R_J\)` foram definidas utilizando os dados de treinamento, fazemos a predição com os dados de teste. Se a observação cair na `\(j\)`-ésima região, a predição será `\(\bar{y}_{R_j}\)`. -- ```r # Qual será o salário ds novos jogadores (test_data) segundo o modelo? yhat <- predict(Hitters_tree, newdata = test_data) rmse_vec(as.numeric(yhat),test_data$Salary) ``` ``` ## [1] 310.6233 ``` Lembre-se `$$RMSE = \sqrt{\dfrac{\displaystyle \sum_{i \in Teste} (y_i - \hat{y}_i)^2}{\text{Num. obs. Teste}}}$$` --- ## Árvore de Decisão: Dependendo do critério de parada escolhido, o modelo pode apresentar _overfitting_ (funcionar muito bem nos dados de treinamento mas muito pobre nos dados de teste). -- Para evitar _overfitting_ é feito uma _poda_ da árvore (*Pruning*), que consiste em `cortar` os galhos da árvore que podem ser muito específicos, forçando "muito a barra" na hora do ajuste. -- Discutir isto em profundida está fora de uma apresentação introdutória do método. Por enquanto, nos conformaremos em saber que precisamos escolher appropriadamente os valores da profundidade da árvore (`tree_depth`) e da complexidade da poda (`cost_complexity`). Para escolher os melhores valores, faremos validação cruzada. --- .panelset[ .panel[.panel-name[Slipts] ```r # Dividimos train e test set.seed(1234) split_data <- initial_split(data = Hitters) train_data <- training(split_data) test_data <- testing(split_data) ``` ] .panel[.panel-name[Tuning] ```r folds_tung <- vfold_cv(train_data, v = 10) model_spec <- decision_tree(tree_depth = tune(), cost_complexity = tune()) %>% set_mode("regression") %>% set_engine("rpart") model_grid <- grid_regular(cost_complexity(), tree_depth(), levels = 5) model_wflw <- workflow() %>% add_model(model_spec) %>% add_formula(Salary ~ .) model_resamp <- model_wflw %>% tune_grid(resamples = folds_tung, grid = model_grid) best_model <- model_resamp %>% select_best("rmse") best_model ``` ``` ## # A tibble: 1 × 3 ## cost_complexity tree_depth .config ## <dbl> <int> <chr> ## 1 0.000562 4 Preprocessor1_Model09 ``` ] .panel[.panel-name[Performance] ```r # Definimos o modelo definido final_wf <- model_wflw %>% finalize_workflow(best_model) # Treinamos o modelo e avaliaremos com validação cruzada set.seed(3210) folds <- vfold_cv(Hitters, v = 10) model_fit_rs <- final_wf %>% fit_resamples(folds) # Vemos a performance estimada collect_metrics(model_fit_rs) ``` ``` ## # A tibble: 2 × 6 ## .metric .estimator mean n std_err .config ## <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 rmse standard 379. 10 22.2 Preprocessor1_Model1 ## 2 rsq standard 0.399 10 0.0409 Preprocessor1_Model1 ``` ```r # Modelo final modelo_final <- final_wf %>% fit(data = Hitters) ``` ] ] --- # Data-Tips: .pull-left[ ![](https://octodex.github.com/images/minertocat.png) ] .pull-right[ - Temos aprendido como funciona uma árvore de decisão para regressão. Contudo, se nosso objetivo é classificar (se `\(Y\)` for uma variável qualitativa), é possível também utilizar uma árvore de decisão, basta especificar `set_mode("classification")` no slide anterior e pronto. - Para entender melhor como funcionam as árvores de decisão para fins de classificação, ver a Seção 8.1.2 do livro James et al. (2013). **Happy Coding!** ### Referências - [James, G., Witten, D., Hastie, T., and Tibshirani, R. (2013). An Introduction to Statistical Learning with Applications in R. New York: Springer.](https://www.statlearning.com) Chapter 8 ]