class: center, middle, inverse, title-slide #
Statistical Learning:
## Resampling Methods II: Tuning Hyperparameters ### Prof. Carlos Trucíos
FACC/UFRJ
ctruciosm.github.io
carlos.trucios@facc.ufrj.br
### Grupo de Estudos CIA, – Causal Inference and Analytics – ### 2021-08-13 --- layout: true <a class="footer-link" href="http://ctruciosm.github.io">ctruciosm.github.io — Carlos Trucíos (FACC/UFRJ)</a> ---
# Motivação .panelset[ .panel[.panel-name[Importando Dados] ```r # Pacotes necessários library(dplyr) library(tidymodels) library(kknn) data("credit_data", package = "modeldata") credit_data <- credit_data %>% na.omit() ``` ] .panel[.panel-name[K = 1] ```r folds <- vfold_cv(credit_data, v = 10) model_spec <- nearest_neighbor(neighbors = 1) %>% set_engine("kknn") %>% set_mode("classification") model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_fit_rs <- model_wf %>% fit_resamples(folds) collect_metrics(model_fit_rs) ``` ``` ## # A tibble: 2 × 6 ## .metric .estimator mean n std_err .config ## <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 accuracy binary 0.732 10 0.00559 Preprocessor1_Model1 ## 2 roc_auc binary 0.640 10 0.00887 Preprocessor1_Model1 ``` ] .panel[.panel-name[K = 3] ```r folds <- vfold_cv(credit_data, v = 10) model_spec <- nearest_neighbor(neighbors = 3) %>% set_engine("kknn") %>% set_mode("classification") model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_fit_rs <- model_wf %>% fit_resamples(folds) collect_metrics(model_fit_rs) ``` ``` ## # A tibble: 2 × 6 ## .metric .estimator mean n std_err .config ## <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 accuracy binary 0.734 10 0.00313 Preprocessor1_Model1 ## 2 roc_auc binary 0.720 10 0.00352 Preprocessor1_Model1 ``` ] .panel[.panel-name[K = 5] ```r folds <- vfold_cv(credit_data, v = 10) model_spec <- nearest_neighbor(neighbors = 5) %>% set_engine("kknn") %>% set_mode("classification") model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_fit_rs <- model_wf %>% fit_resamples(folds) collect_metrics(model_fit_rs) ``` ``` ## # A tibble: 2 × 6 ## .metric .estimator mean n std_err .config ## <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 accuracy binary 0.763 10 0.00592 Preprocessor1_Model1 ## 2 roc_auc binary 0.732 10 0.00637 Preprocessor1_Model1 ``` ] .panel[.panel-name[K = 10] ```r folds <- vfold_cv(credit_data, v = 10) model_spec <- nearest_neighbor(neighbors = 10) %>% set_engine("kknn") %>% set_mode("classification") model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_fit_rs <- model_wf %>% fit_resamples(folds) collect_metrics(model_fit_rs) ``` ``` ## # A tibble: 2 × 6 ## .metric .estimator mean n std_err .config ## <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 accuracy binary 0.772 10 0.00667 Preprocessor1_Model1 ## 2 roc_auc binary 0.765 10 0.0100 Preprocessor1_Model1 ``` ] ] --- # Motivação - O método _KNN_ precisa que o usuário atribua um valor do número de vizinhos a serem utilizados. - Esse parâmetro `\(k\)` é chamado de _hiperparâmetro_. - Diferentes valores de `\(k\)` leverão a diferentes performances na amostra de teste (ou seja, diferentes valores estimados do desempenho do modelo). - O processo para escolher o _melhor valor de k_ é chamando de "Tunar o parâmetro" e será feito também com _Cross-Validation_ --- class: inverse, right, middle # Tuning Hyperparameters --- # Tuning Hyperparameters .panelset[ .panel[.panel-name[Código] ```r folds <- vfold_cv(credit_data, strata = Status) *model_spec <- nearest_neighbor(neighbors = tune()) %>% set_engine("kknn") %>% set_mode("classification") *model_grid <- grid_regular(neighbors(), levels = 5) model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_res <- model_wf %>% * tune_grid(resamples = folds, grid = model_grid) collect_metrics(model_res) ``` ] .panel[.panel-name[Resultado] ``` ## # A tibble: 10 × 7 ## neighbors .metric .estimator mean n std_err .config ## <int> <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 1 accuracy binary 0.735 10 0.00588 Preprocessor1_Model1 ## 2 1 roc_auc binary 0.646 10 0.00911 Preprocessor1_Model1 ## 3 3 accuracy binary 0.735 10 0.00588 Preprocessor1_Model2 ## 4 3 roc_auc binary 0.718 10 0.00967 Preprocessor1_Model2 ## 5 5 accuracy binary 0.760 10 0.00653 Preprocessor1_Model3 ## 6 5 roc_auc binary 0.741 10 0.00869 Preprocessor1_Model3 ## 7 7 accuracy binary 0.763 10 0.00688 Preprocessor1_Model4 ## 8 7 roc_auc binary 0.753 10 0.00787 Preprocessor1_Model4 ## 9 10 accuracy binary 0.773 10 0.00593 Preprocessor1_Model5 ## 10 10 roc_auc binary 0.765 10 0.00687 Preprocessor1_Model5 ``` ] ] -- > Achou alguma coisa estranha no processo de "tunar o parâmetro"? --- # Tuning Hyperparameters > Utilizamos os dados de teste para escolher o **melhor valor de `\(k\)`!!!** ou sejá não temos mais um conjunto de observações (não observadas pelo modelo treinado) onde poderiamos verificar que tão bom é nosso modelo. -- .bg-washed-green.b--dark-green.ba.bw2.br3.shadow-5.ph4.mt5[ Os dados de teste simulam aqueles dados novos que chegarão no futuro (os quais o modelo nunca viu). Eles **nunca** devem ser utilizados para alguma coisa a não ser avaliar a performance do nosso modelo. Se utilizarmos os dados de teste para escolher o hiperparâmetro, na verdade esses dados de teste viraram dados de treinamento. ] -- **O que fazer?** --- # Tuning Hyperparameters .panelset[ .panel[.panel-name[Código] ```r *data_split <- initial_split(credit_data, prop = 3/4, strata = Status) *train_data <- training(data_split) *test_data <- testing(data_split) *hyper_folds <- vfold_cv(train_data, strata = Status) model_spec <- nearest_neighbor(neighbors = tune()) %>% set_engine("kknn") %>% set_mode("classification") model_grid <- grid_regular(neighbors(), levels = 5) model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_res <- model_wf %>% tune_grid(resamples = hyper_folds, grid = model_grid) collect_metrics(model_res) ``` ] .panel[.panel-name[Resultado] ``` ## # A tibble: 10 × 7 ## neighbors .metric .estimator mean n std_err .config ## <int> <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 1 accuracy binary 0.728 10 0.00883 Preprocessor1_Model1 ## 2 1 roc_auc binary 0.635 10 0.00979 Preprocessor1_Model1 ## 3 3 accuracy binary 0.728 10 0.00883 Preprocessor1_Model2 ## 4 3 roc_auc binary 0.713 10 0.00989 Preprocessor1_Model2 ## 5 5 accuracy binary 0.749 10 0.00711 Preprocessor1_Model3 ## 6 5 roc_auc binary 0.731 10 0.00945 Preprocessor1_Model3 ## 7 7 accuracy binary 0.755 10 0.00744 Preprocessor1_Model4 ## 8 7 roc_auc binary 0.745 10 0.00992 Preprocessor1_Model4 ## 9 10 accuracy binary 0.772 10 0.00676 Preprocessor1_Model5 ## 10 10 roc_auc binary 0.759 10 0.00913 Preprocessor1_Model5 ``` ] .panel[.panel-name[Melhor modelo] ```r model_res %>% show_best("accuracy", 2) ``` ``` ## # A tibble: 2 × 7 ## neighbors .metric .estimator mean n std_err .config ## <int> <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 10 accuracy binary 0.772 10 0.00676 Preprocessor1_Model5 ## 2 7 accuracy binary 0.755 10 0.00744 Preprocessor1_Model4 ``` ```r best_model <- model_res %>% select_best("accuracy") best_model ``` ``` ## # A tibble: 1 × 2 ## neighbors .config ## <int> <chr> ## 1 10 Preprocessor1_Model5 ``` ```r final_wf <- model_wf %>% finalize_workflow(best_model) ``` ] .panel[.panel-name[Modelo Final] ```r folds <- vfold_cv(credit_data, strata = Status, v = 10) model_fit_rs <- final_wf %>% # Já contem os "melhores" valores dos hiperparâmeros fit_resamples(folds) collect_metrics(model_fit_rs) ``` ``` ## # A tibble: 2 × 6 ## .metric .estimator mean n std_err .config ## <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 accuracy binary 0.766 10 0.00625 Preprocessor1_Model1 ## 2 roc_auc binary 0.763 10 0.00765 Preprocessor1_Model1 ``` ] ] --- # Tuning Hyperparameters - Até agora temos utilizado `grid_regular(levels = n)` para escolher o melhor `\(k\)`. - `grid_regular(levels = n)` testa `n` diferentes valores para o número de vizinhos (entre valores mínimos e máximos pre-estabelecidos) de forma que os diferentes valores sejam espaçados de forma aproximadamente igual. - Outra forma de grid bastante popular é `grid_random(size = n)` (escolhe o número de vizinhos de forma aleatória). - Existem otras formas de grid que também estão disponíveis como `grid_max_entropy()` e `grid_latin_hypercube()`. -- ### Hands-on: 1. Substitua `grid_regular(neighbors(), levels = 5)` por `grid_random(neighbors(), size = 5)`, o que observa? 2. O que você espera que acontece se fizer `grid_regular(neighbors(), levels = 15)` ou `grid_random(neighbors(), size = 15)`. 3. Faça as mudanças no código para incluir alguma das opções no item 2. O que aconteceu? --- # Tuning Hyperparameters ```r data_split <- initial_split(credit_data, prop = 3/4, strata = Status) train_data <- training(data_split) test_data <- testing(data_split) folds <- vfold_cv(train_data, strata = Status) model_spec <- nearest_neighbor(neighbors = tune()) %>% set_engine("kknn") %>% set_mode("classification") model_grid <- grid_regular(neighbors(), levels = 5) model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_res <- model_wf %>% tune_grid(resamples = folds,grid = model_grid) collect_metrics(model_res) ``` 1. Substitua `grid_regular(neighbors(), levels = 5)` por `grid_random(neighbors(), size = 5)`, o que observa? 2. O que você espera que acontece se fizer `grid_regular(neighbors(), levels = 15)` ou `grid_random(neighbors(), size = 15)`. 3. Faça as mudanças no código para incluir alguma das opções no item 2. O que aconteceu? --- # Tuning Hyperparameters Por padrão, os valores máximos e mínimos dos hiperparâmetros já estão pre-estabelecidos, más é possivel mudar esse valores. .panelset[ .panel[.panel-name[Código] ```r data_split <- initial_split(credit_data, prop = 3/4, strata = Status) train_data <- training(data_split) test_data <- testing(data_split) folds <- vfold_cv(train_data, strata = Status) model_spec <- nearest_neighbor(neighbors = tune()) %>% set_engine("kknn") %>% set_mode("classification") *model_grid <- grid_random(neighbors(c(1, 50)), size = 15) model_wf <- workflow() %>% add_model(model_spec) %>% add_formula(Status ~ .) model_res <- model_wf %>% tune_grid(resamples = folds,grid = model_grid) model_res %>% show_best("accuracy",5) ``` ] .panel[.panel-name[Resultado] ``` ## # A tibble: 5 × 7 ## neighbors .metric .estimator mean n std_err .config ## <int> <chr> <chr> <dbl> <int> <dbl> <chr> ## 1 29 accuracy binary 0.783 10 0.00540 Preprocessor1_Model09 ## 2 25 accuracy binary 0.783 10 0.00573 Preprocessor1_Model08 ## 3 34 accuracy binary 0.782 10 0.00497 Preprocessor1_Model10 ## 4 35 accuracy binary 0.781 10 0.00446 Preprocessor1_Model11 ## 5 36 accuracy binary 0.780 10 0.00424 Preprocessor1_Model12 ``` ] ] --- # Tuning Hyperparameters - O processo de "tunar parâmetros" não e exclussivo do _KNN_, vários métodos precisam da escolha dos hiperparâmetros, mas o processo é semelhante ao visto aqui. - Nas próximas reuniões, quando necessário, utilizaremos o processo de "tunar parâmetros" para escolher nosso modelo. > Tunar parâmetros pode ser um processo caro computacionalmente. Quanto temos vários parâmetros a serem tunados e um número grande de `levels` ou `size`, computadores de alto desempenho são necessários. --- .bg-washed-blue.b--dark-blue.ba.bw2.br3.shadow-5.ph4.mt5[ ### Grupo de pesquisa em Big Data e Análise Quantitativa (BDAQ) Ná última reunião de Departamento foi aprovada a criação de um novo grupo de pesquisa na FACC/UFRJ 🕺 👨🏫 💻. O grupo de pesquisa **Big Data e Análise Quantitativa (BDAQ)** é formado pelos seguintes professores: - Dr. Carlos César Trucíos Maza, - Dra. Cristina Pimenta de Mello Spinet Luz, - Dr. Boris Asrilhant, - Dr. Marcelo Castañeda de Araujo, - Dra. Laura Marina Valencia Niño Logo logo teremos novidades sobre projetos de pesquisa para trabalharmos com alunos e outros professores 👩🔬 👩🎓. ] --- # Data-Tips: .pull-left[ ![](https://octodex.github.com/images/minertocat.png) ] .pull-right[ - Aqui temos "tunado o parâmetro" para obter a maior acurácia, mas lembre-se: existem várias métricas para avaliar a performance do modelo. - O melhor valor do hiperparâmetro segundo uma métrica (eg. acurácia) não necessáriamente será o melhor valor segundo outra métrica. - Estude o pacote `tidymodels`, fornece muitas opções interessantes para _machine/statistical learning_. Confira [aqui](https://www.tidymodels.org/start/) o material introdutório elaborado pelos próprios criadores do pacote. - Um material mais completo sobre `tidymodels` pode ser encontrado [aqui](https://www.tmwr.org). **Happy Coding!** ]