--- 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%} ::: :::