Introdução ao aprendizado de máquina

Aula 7

Bruno Montezano

Grupo Alliance
Programa de Pós-Graduação em Psiquiatria e Ciências do Comportamento
Universidade Federal do Rio Grande do Sul

12 de junho de 2023

Conteúdo de hoje

  • O que é machine learning?
  • Aprendizado supervisionado e não-supervisionado
  • Regressão e classificação
  • Exemplo de regressão logística

Machine learning

  • Conjunto de técnicas que ensina um computador a reconhecer padrões e fazer previsões

Tipos de aprendizado


Vamos trabalhar com um exemplo em aprendizado supervisionado!

Aprendizado supervisionado

Hoje vamos trabalhar com classificação.

Problema de classificação

Pergunta de pesquisa: Podemos prever o sexo de um pinguim baseado em sua espécie, comprimento do bico e da nadadeira, profundidade do bico e massa corporal?

Regressão logística

  • Uma “extensão” da regressão linear para problemas de classificação

  • Usa a função logística para transformar saída da regressão linear em uma probabilidade1

  • Coeficientes: efeito logarítmico do \(X\) sobre a razão de chances (odds ratio). Ou seja, não devemos interpretar os coeficientes diretamente

  • Em geral, usamos um limiar para decidir em qual classe o dado pertence (geralmente 0,5)

  • Para calcular o odds ratio no R, podemos exponenciar o coeficiente da regressão com a função exp()

tidymodels

Pacote tidymodels

library(tidymodels)
── Attaching packages ────────────────────────────────────── tidymodels 1.1.0 ──
✔ broom        1.0.5     ✔ rsample      1.1.1
✔ dials        1.2.0     ✔ tibble       3.2.1
✔ infer        1.0.4     ✔ tidyr        1.3.0
✔ modeldata    1.1.0     ✔ tune         1.1.1
✔ parsnip      1.1.0     ✔ workflows    1.1.3
✔ purrr        1.0.1     ✔ workflowsets 1.0.1
✔ recipes      1.0.6     ✔ yardstick    1.2.0
── Conflicts ───────────────────────────────────────── tidymodels_conflicts() ──
✖ purrr::discard() masks scales::discard()
✖ dplyr::filter()  masks stats::filter()
✖ dplyr::lag()     masks stats::lag()
✖ dials::prune()   masks rpart::prune()
✖ recipes::step()  masks stats::step()
• Search for functions across packages at https://www.tidymodels.org/find/

Passo a passo

  1. Limpar os dados

  2. Dividir os dados em treino e teste

  3. Criar reamostragens com bootstrapping

  4. Especificar o algoritmo a ser usado

  5. Especificar o fluxo de modelagem com a pergunta de pesquisa

  6. Ajustar modelos nas reamostragens

  7. Verificar como o modelo performou

  8. Ajustar o modelo final no conjunto de treino e testar no conjunto de teste

  9. Checar os coeficientes

1. Limpar os dados

  • Nesta etapa, vamos remover pinguins com valor ausente no desfecho

  • E também remover as variáveis de ano e ilha que não usaremos

dados_pinguins <- pinguins |> 
  filter(!is.na(sexo)) |> 
  select(-ano, -ilha)

dados_pinguins
# A tibble: 333 × 6
   especie           comprimento_bico profundidade_bico comprimento_nadadeira
   <fct>                        <dbl>             <dbl>                 <int>
 1 Pinguim-de-adélia             39.1              18.7                   181
 2 Pinguim-de-adélia             39.5              17.4                   186
 3 Pinguim-de-adélia             40.3              18                     195
 4 Pinguim-de-adélia             36.7              19.3                   193
 5 Pinguim-de-adélia             39.3              20.6                   190
 6 Pinguim-de-adélia             38.9              17.8                   181
 7 Pinguim-de-adélia             39.2              19.6                   195
 8 Pinguim-de-adélia             41.1              17.6                   182
 9 Pinguim-de-adélia             38.6              21.2                   191
10 Pinguim-de-adélia             34.6              21.1                   198
# ℹ 323 more rows
# ℹ 2 more variables: massa_corporal <int>, sexo <fct>

2. Dividir os dados

  • Quando falamos em aprendizado supervisionado, buscamos simular a predição de dados nunca visto antes
set.seed(1)

divisao_pinguins <- initial_split(dados_pinguins, strata = "sexo", prop = 0.75)
treino_pinguins <- training(divisao_pinguins)
teste_pinguins <- testing(divisao_pinguins)

divisao_pinguins
<Training/Testing/Total>
<249/84/333>

3. Criar reamostragens

  • Bootstrapping: técnica que nos permite estimar a variabilidade do desempenho do modelo de classificação a partir de uma única amostra de treinamento

  • Como funciona: criamos várias amostras de treinamento adicionais, sorteando aleatoriamente observações do conjunto de treino original

set.seed(1)

boot_pinguins <- bootstraps(treino_pinguins, times = 25)

boot_pinguins
# Bootstrap sampling 
# A tibble: 25 × 2
   splits            id         
   <list>            <chr>      
 1 <split [249/93]>  Bootstrap01
 2 <split [249/93]>  Bootstrap02
 3 <split [249/97]>  Bootstrap03
 4 <split [249/95]>  Bootstrap04
 5 <split [249/103]> Bootstrap05
 6 <split [249/86]>  Bootstrap06
 7 <split [249/92]>  Bootstrap07
 8 <split [249/83]>  Bootstrap08
 9 <split [249/89]>  Bootstrap09
10 <split [249/95]>  Bootstrap10
# ℹ 15 more rows

4. Especificar o algoritmo

  • Especificamos que queremos usar uma regressão logística binomial

  • Dizemos para o R que o motor (engine) usado é a função glm()

mod_log <- logistic_reg() |> 
  set_mode("classification") |> 
  set_engine("glm")

mod_log
Logistic Regression Model Specification (classification)

Computational engine: glm 

5. Especificar o fluxo

  • Vamos dizer para o R que queremos prever o sexo do pinguim a partir de todas as outras variáveis do conjunto de dados
wf_pinguins <- workflow() |> 
  add_formula(sexo ~ .)

wf_pinguins
══ Workflow ════════════════════════════════════════════════════════════════════
Preprocessor: Formula
Model: None

── Preprocessor ────────────────────────────────────────────────────────────────
sexo ~ .

6. Ajustar modelos nas reamostragens

  • Para cada reamostragem (de treino e teste), vamos ajustar o modelo em cada base de treino e avaliar como o modelo desempenhou a partir das bases de teste
rs_pinguins <- wf_pinguins |> 
  add_model(mod_log) |> 
  fit_resamples(
    resamples = boot_pinguins,
    control = control_resamples(
      save_pred = TRUE,
      verbose = TRUE
    )
  )

rs_pinguins
# Resampling results
# Bootstrap sampling 
# A tibble: 25 × 5
   splits            id          .metrics         .notes           .predictions
   <list>            <chr>       <list>           <list>           <list>      
 1 <split [249/93]>  Bootstrap01 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 2 <split [249/93]>  Bootstrap02 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 3 <split [249/97]>  Bootstrap03 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 4 <split [249/95]>  Bootstrap04 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 5 <split [249/103]> Bootstrap05 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 6 <split [249/86]>  Bootstrap06 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 7 <split [249/92]>  Bootstrap07 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 8 <split [249/83]>  Bootstrap08 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
 9 <split [249/89]>  Bootstrap09 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
10 <split [249/95]>  Bootstrap10 <tibble [2 × 4]> <tibble [0 × 3]> <tibble>    
# ℹ 15 more rows

7. Verificar a performance

  • A curva ROC nos permite visualizar o desempenho do modelo em diferentes pontos de corte

  • Quanto mais próximo a curva estiver do canto superior esquerdo, melhor será o desempenho do modelo

  • Acurácia é a proporção de predições corretas em relação ao total de predições

collect_metrics(rs_pinguins)
# A tibble: 2 × 6
  .metric  .estimator  mean     n std_err .config             
  <chr>    <chr>      <dbl> <int>   <dbl> <chr>               
1 accuracy binary     0.915    25 0.00510 Preprocessor1_Model1
2 roc_auc  binary     0.977    25 0.00240 Preprocessor1_Model1
rs_pinguins |> 
  conf_mat_resampled()
# A tibble: 4 × 3
  Prediction Truth  Freq
  <fct>      <fct> <dbl>
1 fêmea      fêmea 41.1 
2 fêmea      macho  3.84
3 macho      fêmea  4.04
4 macho      macho 43.5 

7. Verificar a performance

8. Ajustar o modelo final

  • Agora o conjunto de testes entra em ação para verificar como nosso modelo vai performar nestes dados nunca visto antes
final_pinguins <- wf_pinguins |> 
  add_model(mod_log) |> 
  last_fit(divisao_pinguins)

collect_metrics(final_pinguins)
# A tibble: 2 × 4
  .metric  .estimator .estimate .config             
  <chr>    <chr>          <dbl> <chr>               
1 accuracy binary         0.905 Preprocessor1_Model1
2 roc_auc  binary         0.966 Preprocessor1_Model1
collect_predictions(final_pinguins) |> 
  conf_mat(sexo, .pred_class)
          Truth
Prediction fêmea macho
     fêmea    39     5
     macho     3    37

9. Olhar os coeficientes

  • Odds ratio:
    • OR = 1 (sem efeito); OR > 1 (risco); OR < 1 (proteção)
    • Variáveis numéricas: incremento percentual na chance para cada unidade de aumento
    • Variáveis categóricas: grupo 1 tem maior chance do evento ocorrer em comparação ao grupo 2
final_pinguins |> 
  extract_workflow() |> 
  tidy(exponentiate = TRUE) |> 
  arrange(desc(estimate))
# A tibble: 7 × 5
  term                         estimate std.error statistic     p.value
  <chr>                           <dbl>     <dbl>     <dbl>       <dbl>
1 profundidade_bico            7.50e+ 0   0.455       4.43  0.00000940 
2 comprimento_bico             1.88e+ 0   0.159       4.00  0.0000639  
3 comprimento_nadadeira        1.06e+ 0   0.0653      0.863 0.388      
4 massa_corporal               1.01e+ 0   0.00138     4.63  0.00000374 
5 `especiePinguim-de-barbicha` 9.76e- 4   1.91       -3.62  0.000295   
6 `especiePinguim-gentoo`      1.96e- 4   3.25       -2.63  0.00866    
7 (Intercept)                  2.35e-42  18.1        -5.30  0.000000115

Tarefa de casa