---
title: "Introdução ao aprendizado de máquina"
subtitle: "Aula 7"
author: "Bruno Montezano"
institute: "Grupo Alliance
Programa de Pós-Graduação em Psiquiatria e Ciências do Comportamento
Universidade Federal do Rio Grande do Sul"
date: last-modified
date-format: long
lang: pt-br
execute:
echo: true
format:
revealjs:
incremental: true
smaller: true
theme: [default, ../assets/custom.scss]
logo: "../assets/logo_ufrgs.png"
---
## 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
. . .
```{r exemplo-decision-tree}
#| echo: false
#| out.width: "90%"
#| fig-align: "center"
# Carregar pacotes para ajustar árvore de decisão e dados do Titanic
library(rpart)
library(rpart.plot)
library(titanic)
# Recodificar algumas variáveis
titanic_treino <- titanic_train |>
dplyr::mutate(
Survived = factor(
dplyr::case_when(
Survived == 1 ~ "Sobreviveu",
Survived == 0 ~ "Faleceu"
)
),
Sex = dplyr::case_when(
Sex == "male" ~ "Masculino",
Sex == "female" ~ "Feminino"
)
) |>
dplyr::rename(Sexo = Sex,
Idade = Age)
# Ajustar a árvore de decisão
titanic_ajuste <- rpart(Survived ~ Sexo + Idade,
data = titanic_treino)
# Mostrar gráfico da árvore
rpart.plot(titanic_ajuste,
extra = 6,
fallen.leaves = TRUE,
yes.text = "Sim",
no.text = "Não",
main = "Sobrevivência no desastre do Titanic: um exemplo de árvore de decisão")
```
## Tipos de aprendizado
```{r plot-tipos-aprendizado}
#| echo: false
#| fig-align: "center"
#| out.width: "90%"
library(ggplot2)
set.seed(123)
dados_aprendizado <- data.frame(
X = c(rnorm(50, mean = 0), rnorm(50, mean = 3)),
Y = c(rnorm(50, mean = 0), rnorm(50, mean = 3)),
Tipo = rep(c("Grupo A", "Grupo B"), each = 50)
)
p_supervisionado <- ggplot(dados_aprendizado, aes(x = X, y = Y, color = Tipo)) +
geom_point(alpha = 0.8,
size = 2.2) +
labs(title = "Aprendizado Supervisionado") +
theme_light(16, "Charter") +
ggsci::scale_color_jama() +
theme(legend.position = "none") +
labs(x = latex2exp::TeX("$x_1$"),
y = latex2exp::TeX("$x_2$"))
p_nao_supervisionado <- ggplot(dados_aprendizado, aes(x = X, y = Y)) +
geom_point() +
labs(title = "Aprendizado Não Supervisionado") +
theme_light(16, "Charter") +
ggforce::geom_mark_circle(aes(fill = Tipo)) +
ggsci::scale_fill_jama() +
labs(x = latex2exp::TeX("$x_1$"),
y = latex2exp::TeX("$x_2$")) +
theme(legend.position = "none")
library(patchwork)
p_supervisionado + p_nao_supervisionado
```
. . .
Vamos trabalhar com um exemplo em **aprendizado supervisionado**!
## Aprendizado supervisionado
```{r classificacao-regressao}
#| echo: false
#| fig-align: "center"
#| out.width: "90%"
set.seed(123)
dados_regressao <- data.frame(
X = seq(1, 10, by = 0.5),
Y = seq(2, 20, by = 1)
)
set.seed(123)
dados_classificacao <- data.frame(
X = c(rnorm(300, mean = 2, sd = 1.5), rnorm(300, mean = 8, sd = 3)),
Y = c(rep(0, 300), rep(1, 300))
)
set.seed(123)
p_regressao <- ggplot(dados_regressao, aes(x = X, y = Y)) +
geom_jitter(alpha = 0.8,
size = 2.5) +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Problema de Regressão") +
theme_light(18, "Charter") +
labs(x = latex2exp::TeX("$x_1"),
y = latex2exp::TeX("$Y$"))
set.seed(123)
p_classificacao <- ggplot(dados_classificacao, aes(x = X, y = Y)) +
geom_jitter(aes(color = as.factor(Y)), size = 2.5,
alpha = 0.4,
height = 0.002,
width = 0) +
geom_smooth(method = "glm", method.args = list(family = "binomial"),
se = FALSE) +
ggsci::scale_color_npg() +
labs(title = "Problema de Classificação") +
theme_light(18, "Charter") +
theme(legend.position = "none") +
labs(x = latex2exp::TeX("$x_1"),
y = latex2exp::TeX("$Y$")) +
scale_y_continuous(breaks = 0:1)
p_regressao + p_classificacao
```
. . .
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?**
```{r exploratoria-pinguins}
#| echo: false
#| fig-align: "center"
#| out.width: "90%"
library(dados)
library(dplyr)
pinguins |>
filter(!is.na(sexo)) |>
ggplot(aes(x = profundidade_bico,
y = comprimento_bico,
color = sexo,
size = massa_corporal)) +
geom_point(alpha = 0.55) +
facet_wrap(~ especie) +
ggsci::scale_color_nejm(labels = c("Fêmea", "Macho")) +
theme_classic(12, "Charter") +
labs(x = "Profundidade do bico (mm)",
y = "Comprimento do bico (mm)",
color = "Sexo",
size = "Massa corporal (g)")
```
## 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 probabilidade^[No R, a função logística pode ser usada com `LaplacesDemon::invlogit()`.]
* 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`
![](../assets/logo_tidymodels.png){fig-align="center" width=45%}
## Pacote `tidymodels`
```{r carregar-tidymodels}
#| message: true
library(tidymodels)
```
## 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
. . .
```{r limpar-dados-pinguins}
dados_pinguins <- pinguins |>
filter(!is.na(sexo)) |>
select(-ano, -ilha)
dados_pinguins
```
## 2. Dividir os dados
* Quando falamos em aprendizado supervisionado, buscamos simular a predição de dados nunca
visto antes
. . .
```{r dividir-dados-pinguins}
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
```
## 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
. . .
```{r criar-reamostragens}
set.seed(1)
boot_pinguins <- bootstraps(treino_pinguins, times = 25)
boot_pinguins
```
## 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()`
. . .
```{r especificar-algoritmo}
mod_log <- logistic_reg() |>
set_mode("classification") |>
set_engine("glm")
mod_log
```
## 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
. . .
```{r especificar-workflow}
wf_pinguins <- workflow() |>
add_formula(sexo ~ .)
wf_pinguins
```
## 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
. . .
```{r ajustar-reamostragens}
rs_pinguins <- wf_pinguins |>
add_model(mod_log) |>
fit_resamples(
resamples = boot_pinguins,
control = control_resamples(
save_pred = TRUE,
verbose = TRUE
)
)
rs_pinguins
```
## 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
. . .
```{r pegar-metricas}
collect_metrics(rs_pinguins)
```
. . .
```{r matriz-confusao-reamostragens}
rs_pinguins |>
conf_mat_resampled()
```
## 7. Verificar a performance
```{r curva-roc-reamostragem}
#| echo: false
#| out.width: "65%"
#| fig-align: "center"
rs_pinguins |>
collect_predictions() |>
group_by(id) |>
roc_curve(sexo, .pred_fêmea) |>
ggplot(aes(1 - specificity, sensitivity, color = id)) +
geom_abline(lty = 2, color = "gray80", size = 1.2) +
geom_path(show.legend = FALSE, alpha = 0.6, size = 1.2) +
coord_equal() +
theme_light(12, "Charter") +
labs(x = "1 - Especificidade", y = "Sensibilidade")
```
## 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
. . .
```{r ajustar-modelo-final}
final_pinguins <- wf_pinguins |>
add_model(mod_log) |>
last_fit(divisao_pinguins)
collect_metrics(final_pinguins)
collect_predictions(final_pinguins) |>
conf_mat(sexo, .pred_class)
```
## 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
. . .
```{r coeficientes}
final_pinguins |>
extract_workflow() |>
tidy(exponentiate = TRUE) |>
arrange(desc(estimate))
```
## Tarefa de casa
::: columns
::: {.column width="55%"}
* Dica de leitura: [An Introduction to Statistical Learning](https://www.statlearning.com/)
* Rodar os códigos dos slides para tentar reproduzir o exemplo
- Lembre-se de instalar o pacote `tidymodels` caso não o tenha
:::
::: {.column width="45%"}
![](../assets/capa_islr.jpg){width=65%}
:::
:::