You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ML-For-Beginners/translations/br/2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb

685 lines
31 KiB

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Construir um modelo de regressão logística - Aula 4\n",
"\n",
"![Infográfico de regressão logística vs. regressão linear](../../../../../../translated_images/linear-vs-logistic.ba180bf95e7ee66721ba10ebf2dac2666acbd64a88b003c83928712433a13c7d.br.png)\n",
"\n",
"#### **[Questionário pré-aula](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n",
"\n",
"#### Introdução\n",
"\n",
"Nesta última aula sobre Regressão, uma das técnicas *clássicas* básicas de Machine Learning, vamos explorar a Regressão Logística. Você usaria essa técnica para descobrir padrões e prever categorias binárias. Este doce é de chocolate ou não? Esta doença é contagiosa ou não? Este cliente escolherá este produto ou não?\n",
"\n",
"Nesta aula, você aprenderá:\n",
"\n",
"- Técnicas para regressão logística\n",
"\n",
"✅ Aprofunde seu entendimento sobre como trabalhar com este tipo de regressão neste [módulo do Learn](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n",
"\n",
"## Pré-requisito\n",
"\n",
"Depois de trabalhar com os dados de abóboras, já estamos suficientemente familiarizados com eles para perceber que há uma categoria binária com a qual podemos trabalhar: `Color`.\n",
"\n",
"Vamos construir um modelo de regressão logística para prever, dado algumas variáveis, *qual é a cor provável de uma determinada abóbora* (laranja 🎃 ou branca 👻).\n",
"\n",
"> Por que estamos falando de classificação binária em uma aula sobre regressão? Apenas por conveniência linguística, já que a regressão logística é [na verdade um método de classificação](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), embora baseado em um modelo linear. Aprenda sobre outras formas de classificar dados no próximo grupo de aulas.\n",
"\n",
"Para esta aula, precisaremos dos seguintes pacotes:\n",
"\n",
"- `tidyverse`: O [tidyverse](https://www.tidyverse.org/) é uma [coleção de pacotes R](https://www.tidyverse.org/packages) projetada para tornar a ciência de dados mais rápida, fácil e divertida!\n",
"\n",
"- `tidymodels`: O [tidymodels](https://www.tidymodels.org/) é uma [coleção de pacotes](https://www.tidymodels.org/packages/) para modelagem e aprendizado de máquina.\n",
"\n",
"- `janitor`: O pacote [janitor](https://github.com/sfirke/janitor) oferece ferramentas simples para examinar e limpar dados desorganizados.\n",
"\n",
"- `ggbeeswarm`: O pacote [ggbeeswarm](https://github.com/eclarke/ggbeeswarm) fornece métodos para criar gráficos no estilo \"beeswarm\" usando ggplot2.\n",
"\n",
"Você pode instalá-los com o seguinte comando:\n",
"\n",
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n",
"\n",
"Alternativamente, o script abaixo verifica se você possui os pacotes necessários para completar este módulo e os instala caso estejam ausentes.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n",
"\n",
"pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **Defina a pergunta**\n",
"\n",
"Para os nossos propósitos, vamos expressar isso como um binário: 'Branco' ou 'Não Branco'. Há também uma categoria 'listrado' em nosso conjunto de dados, mas há poucos exemplos dela, então não a utilizaremos. De qualquer forma, ela desaparece quando removemos os valores nulos do conjunto de dados.\n",
"\n",
"> 🎃 Curiosidade: às vezes chamamos abóboras brancas de abóboras 'fantasmas'. Elas não são muito fáceis de esculpir, então não são tão populares quanto as laranjas, mas têm uma aparência bem legal! Assim, também poderíamos reformular nossa pergunta como: 'Fantasma' ou 'Não Fantasma'. 👻\n",
"\n",
"## **Sobre regressão logística**\n",
"\n",
"A regressão logística difere da regressão linear, que você aprendeu anteriormente, de algumas maneiras importantes.\n",
"\n",
"#### **Classificação binária**\n",
"\n",
"A regressão logística não oferece os mesmos recursos que a regressão linear. A primeira fornece uma previsão sobre uma `categoria binária` (\"laranja ou não laranja\"), enquanto a segunda é capaz de prever `valores contínuos`, por exemplo, dado a origem de uma abóbora e o momento da colheita, *quanto o preço dela vai aumentar*.\n",
"\n",
"![Infográfico por Dasani Madipalli](../../../../../../translated_images/pumpkin-classifier.562771f104ad5436b87d1c67bca02a42a17841133556559325c0a0e348e5b774.br.png)\n",
"\n",
"### Outras classificações\n",
"\n",
"Existem outros tipos de regressão logística, incluindo multinomial e ordinal:\n",
"\n",
"- **Multinomial**, que envolve mais de uma categoria - \"Laranja, Branco e Listrado\".\n",
"\n",
"- **Ordinal**, que envolve categorias ordenadas, útil se quisermos organizar nossos resultados de forma lógica, como nossas abóboras ordenadas por um número finito de tamanhos (mini,pequeno,médio,grande,xl,xxl).\n",
"\n",
"![Regressão multinomial vs ordinal](../../../../../../translated_images/multinomial-vs-ordinal.36701b4850e37d86c9dd49f7bef93a2f94dbdb8fe03443eb68f0542f97f28f29.br.png)\n",
"\n",
"#### **As variáveis NÃO precisam ser correlacionadas**\n",
"\n",
"Lembra como a regressão linear funcionava melhor com variáveis mais correlacionadas? A regressão logística é o oposto - as variáveis não precisam estar alinhadas. Isso funciona para este conjunto de dados, que tem correlações um tanto fracas.\n",
"\n",
"#### **Você precisa de muitos dados limpos**\n",
"\n",
"A regressão logística fornecerá resultados mais precisos se você usar mais dados; nosso pequeno conjunto de dados não é o ideal para essa tarefa, então tenha isso em mente.\n",
"\n",
"✅ Pense nos tipos de dados que se adaptariam bem à regressão logística.\n",
"\n",
"## Exercício - organize os dados\n",
"\n",
"Primeiro, limpe um pouco os dados, removendo valores nulos e selecionando apenas algumas das colunas:\n",
"\n",
"1. Adicione o seguinte código:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Load the core tidyverse packages\n",
"library(tidyverse)\n",
"\n",
"# Import the data and clean column names\n",
"pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n",
" clean_names()\n",
"\n",
"# Select desired columns\n",
"pumpkins_select <- pumpkins %>% \n",
" select(c(city_name, package, variety, origin, item_size, color)) \n",
"\n",
"# Drop rows containing missing values and encode color as factor (category)\n",
"pumpkins_select <- pumpkins_select %>% \n",
" drop_na() %>% \n",
" mutate(color = factor(color))\n",
"\n",
"# View the first few rows\n",
"pumpkins_select %>% \n",
" slice_head(n = 5)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Você pode sempre dar uma olhada no seu novo dataframe usando a função [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html) como mostrado abaixo:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"pumpkins_select %>% \n",
" glimpse()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos confirmar que estaremos realmente lidando com um problema de classificação binária:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Subset distinct observations in outcome column\n",
"pumpkins_select %>% \n",
" distinct(color)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Visualização - gráfico categórico\n",
"Agora você já carregou novamente os dados das abóboras e os limpou para preservar um conjunto de dados contendo algumas variáveis, incluindo Cor. Vamos visualizar o dataframe no notebook usando a biblioteca ggplot.\n",
"\n",
"A biblioteca ggplot oferece maneiras interessantes de visualizar seus dados. Por exemplo, você pode comparar as distribuições dos dados para cada Variedade e Cor em um gráfico categórico.\n",
"\n",
"1. Crie um gráfico desse tipo usando a função geombar, com os dados das abóboras, e especifique um mapeamento de cores para cada categoria de abóbora (laranja ou branca):\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "python"
}
},
"outputs": [],
"source": [
"# Specify colors for each value of the hue variable\n",
"palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n",
"\n",
"# Create the bar plot\n",
"ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n",
" geom_bar(position = \"dodge\") +\n",
" scale_fill_manual(values = palette) +\n",
" labs(y = \"Variety\", fill = \"Color\") +\n",
" theme_minimal()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ao observar os dados, você pode ver como as informações de Cor se relacionam com a Variedade.\n",
"\n",
"✅ Dado este gráfico categórico, quais são algumas explorações interessantes que você consegue imaginar?\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Pré-processamento de dados: codificação de características\n",
"\n",
"Nosso conjunto de dados de abóboras contém valores em formato de texto para todas as suas colunas. Trabalhar com dados categóricos é intuitivo para humanos, mas não para máquinas. Os algoritmos de aprendizado de máquina funcionam melhor com números. Por isso, a codificação é uma etapa muito importante na fase de pré-processamento de dados, pois nos permite transformar dados categóricos em dados numéricos, sem perder nenhuma informação. Uma boa codificação contribui para a construção de um bom modelo.\n",
"\n",
"Para a codificação de características, existem dois principais tipos de codificadores:\n",
"\n",
"1. Codificador ordinal: é adequado para variáveis ordinais, que são variáveis categóricas cujos dados seguem uma ordem lógica, como a coluna `item_size` no nosso conjunto de dados. Ele cria um mapeamento em que cada categoria é representada por um número, que corresponde à ordem da categoria na coluna.\n",
"\n",
"2. Codificador categórico: é adequado para variáveis nominais, que são variáveis categóricas cujos dados não seguem uma ordem lógica, como todas as características diferentes de `item_size` no nosso conjunto de dados. Trata-se de uma codificação one-hot, o que significa que cada categoria é representada por uma coluna binária: a variável codificada é igual a 1 se a abóbora pertence àquela variedade e 0 caso contrário.\n",
"\n",
"O Tidymodels oferece mais um pacote interessante: [recipes](https://recipes.tidymodels.org/) - um pacote para pré-processamento de dados. Vamos definir uma `recipe` que especifica que todas as colunas preditoras devem ser codificadas em um conjunto de números inteiros, `prep` para estimar as quantidades e estatísticas necessárias para quaisquer operações e, por fim, `bake` para aplicar os cálculos aos novos dados.\n",
"\n",
"> Normalmente, o recipes é usado como um pré-processador para modelagem, onde define quais etapas devem ser aplicadas a um conjunto de dados para prepará-lo para a modelagem. Nesse caso, é **altamente recomendado** que você use um `workflow()` em vez de estimar manualmente uma receita usando prep e bake. Veremos tudo isso em breve.\n",
">\n",
"> No entanto, por enquanto, estamos usando recipes + prep + bake para especificar quais etapas devem ser aplicadas a um conjunto de dados para prepará-lo para análise de dados e, em seguida, extrair os dados pré-processados com as etapas aplicadas.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Preprocess and extract data to allow some data analysis\n",
"baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n",
" # Define ordering for item_size column\n",
" step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n",
" # Convert factors to numbers using the order defined above (Ordinal encoding)\n",
" step_integer(item_size, zero_based = F) %>%\n",
" # Encode all other predictors using one hot encoding\n",
" step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n",
" prep(data = pumpkin_select) %>%\n",
" bake(new_data = NULL)\n",
"\n",
"# Display the first few rows of preprocessed data\n",
"baked_pumpkins %>% \n",
" slice_head(n = 5)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"✅ Quais são as vantagens de usar um codificador ordinal para a coluna Item Size?\n",
"\n",
"### Analisar relações entre variáveis\n",
"\n",
"Agora que pré-processamos nossos dados, podemos analisar as relações entre as características e o rótulo para ter uma ideia de quão bem o modelo será capaz de prever o rótulo com base nas características. A melhor maneira de realizar esse tipo de análise é plotando os dados. \n",
"Usaremos novamente a função ggplot geom_boxplot_ para visualizar as relações entre Item Size, Variety e Color em um gráfico categórico. Para melhorar a visualização dos dados, utilizaremos a coluna codificada de Item Size e a coluna não codificada de Variety.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Define the color palette\n",
"palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n",
"\n",
"# We need the encoded Item Size column to use it as the x-axis values in the plot\n",
"pumpkins_select_plot<-pumpkins_select\n",
"pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n",
"\n",
"# Create the grouped box plot\n",
"ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n",
" geom_boxplot() +\n",
" facet_grid(variety ~ ., scales = \"free_x\") +\n",
" scale_fill_manual(values = palette) +\n",
" labs(x = \"Item Size\", y = \"\") +\n",
" theme_minimal() +\n",
" theme(strip.text = element_text(size = 12)) +\n",
" theme(axis.text.x = element_text(size = 10)) +\n",
" theme(axis.title.x = element_text(size = 12)) +\n",
" theme(axis.title.y = element_blank()) +\n",
" theme(legend.position = \"bottom\") +\n",
" guides(fill = guide_legend(title = \"Color\")) +\n",
" theme(panel.spacing = unit(0.5, \"lines\"))+\n",
" theme(strip.text.y = element_text(size = 4, hjust = 0)) \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Use um gráfico swarm\n",
"\n",
"Como Cor é uma categoria binária (Branco ou Não), ela requer '[uma abordagem especializada](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) para visualização'.\n",
"\n",
"Experimente um `gráfico swarm` para mostrar a distribuição de cor em relação ao item_size.\n",
"\n",
"Usaremos o [pacote ggbeeswarm](https://github.com/eclarke/ggbeeswarm), que fornece métodos para criar gráficos no estilo beeswarm usando ggplot2. Gráficos beeswarm são uma forma de plotar pontos que normalmente se sobreporiam, organizando-os lado a lado.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Create beeswarm plots of color and item_size\n",
"baked_pumpkins %>% \n",
" mutate(color = factor(color)) %>% \n",
" ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n",
" geom_quasirandom() +\n",
" scale_color_brewer(palette = \"Dark2\", direction = -1) +\n",
" theme(legend.position = \"none\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora que temos uma ideia da relação entre as categorias binárias de cor e o grupo maior de tamanhos, vamos explorar a regressão logística para determinar a provável cor de uma abóbora.\n",
"\n",
"## Construa seu modelo\n",
"\n",
"Selecione as variáveis que você deseja usar no seu modelo de classificação e divida os dados em conjuntos de treinamento e teste. O [rsample](https://rsample.tidymodels.org/), um pacote do Tidymodels, fornece uma infraestrutura para divisão e reamostragem de dados de forma eficiente:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Split data into 80% for training and 20% for testing\n",
"set.seed(2056)\n",
"pumpkins_split <- pumpkins_select %>% \n",
" initial_split(prop = 0.8)\n",
"\n",
"# Extract the data in each split\n",
"pumpkins_train <- training(pumpkins_split)\n",
"pumpkins_test <- testing(pumpkins_split)\n",
"\n",
"# Print out the first 5 rows of the training set\n",
"pumpkins_train %>% \n",
" slice_head(n = 5)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"🙌 Estamos prontos para treinar um modelo ajustando as características de treinamento ao rótulo de treinamento (cor).\n",
"\n",
"Começaremos criando uma receita que especifica as etapas de pré-processamento que devem ser realizadas em nossos dados para prepará-los para a modelagem, ou seja: codificar variáveis categóricas em um conjunto de números inteiros. Assim como `baked_pumpkins`, criaremos uma `pumpkins_recipe`, mas não usaremos `prep` e `bake`, já que isso será incorporado em um fluxo de trabalho, como você verá em apenas alguns passos.\n",
"\n",
"Existem várias maneiras de especificar um modelo de regressão logística no Tidymodels. Veja `?logistic_reg()`. Por enquanto, especificaremos um modelo de regressão logística usando o mecanismo padrão `stats::glm()`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Create a recipe that specifies preprocessing steps for modelling\n",
"pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n",
" step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n",
" step_integer(item_size, zero_based = F) %>% \n",
" step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n",
"\n",
"# Create a logistic model specification\n",
"log_reg <- logistic_reg() %>% \n",
" set_engine(\"glm\") %>% \n",
" set_mode(\"classification\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora que temos uma receita e uma especificação de modelo, precisamos encontrar uma maneira de combiná-los em um objeto que primeiro pré-processará os dados (prep+bake nos bastidores), ajustará o modelo nos dados pré-processados e também permitirá atividades de pós-processamento, se necessário.\n",
"\n",
"No Tidymodels, esse objeto prático é chamado de [`workflow`](https://workflows.tidymodels.org/) e organiza convenientemente seus componentes de modelagem.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Bundle modelling components in a workflow\n",
"log_reg_wf <- workflow() %>% \n",
" add_recipe(pumpkins_recipe) %>% \n",
" add_model(log_reg)\n",
"\n",
"# Print out the workflow\n",
"log_reg_wf\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Depois que um fluxo de trabalho é *especificado*, um modelo pode ser `treinado` usando a função [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html). O fluxo de trabalho estimará uma receita e pré-processará os dados antes do treinamento, então não será necessário fazer isso manualmente usando prep e bake.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Train the model\n",
"wf_fit <- log_reg_wf %>% \n",
" fit(data = pumpkins_train)\n",
"\n",
"# Print the trained workflow\n",
"wf_fit\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O modelo exibe os coeficientes aprendidos durante o treinamento.\n",
"\n",
"Agora que treinamos o modelo usando os dados de treinamento, podemos fazer previsões nos dados de teste usando [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Vamos começar usando o modelo para prever os rótulos do nosso conjunto de teste e as probabilidades para cada rótulo. Quando a probabilidade for maior que 0,5, a classe prevista será `WHITE`, caso contrário, será `ORANGE`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Make predictions for color and corresponding probabilities\n",
"results <- pumpkins_test %>% select(color) %>% \n",
" bind_cols(wf_fit %>% \n",
" predict(new_data = pumpkins_test)) %>%\n",
" bind_cols(wf_fit %>%\n",
" predict(new_data = pumpkins_test, type = \"prob\"))\n",
"\n",
"# Compare predictions\n",
"results %>% \n",
" slice_head(n = 10)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Muito bom! Isso oferece mais insights sobre como a regressão logística funciona.\n",
"\n",
"### Melhor compreensão por meio de uma matriz de confusão\n",
"\n",
"Comparar cada previsão com seu respectivo valor real (\"ground truth\") não é uma maneira muito eficiente de determinar o quão bem o modelo está prevendo. Felizmente, o Tidymodels tem mais algumas cartas na manga: [`yardstick`](https://yardstick.tidymodels.org/) - um pacote usado para medir a eficácia de modelos utilizando métricas de desempenho.\n",
"\n",
"Uma métrica de desempenho associada a problemas de classificação é a [`matriz de confusão`](https://wikipedia.org/wiki/Confusion_matrix). Uma matriz de confusão descreve o quão bem um modelo de classificação está performando. Ela tabula quantos exemplos de cada classe foram classificados corretamente por um modelo. No nosso caso, ela mostrará quantas abóboras laranjas foram classificadas como laranjas e quantas abóboras brancas foram classificadas como brancas; a matriz de confusão também mostra quantas foram classificadas nas categorias **erradas**.\n",
"\n",
"A função [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) do yardstick calcula essa tabela cruzada de classes observadas e previstas.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Confusion matrix for prediction results\n",
"conf_mat(data = results, truth = color, estimate = .pred_class)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos interpretar a matriz de confusão. Nosso modelo foi solicitado a classificar abóboras entre duas categorias binárias, a categoria `branca` e a categoria `não-branca`.\n",
"\n",
"- Se o seu modelo prevê que uma abóbora é branca e ela realmente pertence à categoria 'branca', chamamos isso de `verdadeiro positivo`, representado pelo número no canto superior esquerdo.\n",
"\n",
"- Se o seu modelo prevê que uma abóbora não é branca e ela realmente pertence à categoria 'branca', chamamos isso de `falso negativo`, representado pelo número no canto inferior esquerdo.\n",
"\n",
"- Se o seu modelo prevê que uma abóbora é branca e ela realmente pertence à categoria 'não-branca', chamamos isso de `falso positivo`, representado pelo número no canto superior direito.\n",
"\n",
"- Se o seu modelo prevê que uma abóbora não é branca e ela realmente pertence à categoria 'não-branca', chamamos isso de `verdadeiro negativo`, representado pelo número no canto inferior direito.\n",
"\n",
"| Verdade |\n",
"|:-------:|\n",
"\n",
"| | | |\n",
"|---------------|--------|-------|\n",
"| **Previsto** | BRANCA | LARANJA |\n",
"| BRANCA | VP | FP |\n",
"| LARANJA | FN | VN |\n",
"\n",
"Como você deve ter imaginado, é preferível ter um número maior de verdadeiros positivos e verdadeiros negativos e um número menor de falsos positivos e falsos negativos, o que implica que o modelo tem um desempenho melhor.\n",
"\n",
"A matriz de confusão é útil porque dá origem a outras métricas que podem nos ajudar a avaliar melhor o desempenho de um modelo de classificação. Vamos analisar algumas delas:\n",
"\n",
"🎓 Precisão: `VP/(VP + FP)` definida como a proporção de positivos previstos que são realmente positivos. Também chamada de [valor preditivo positivo](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n",
"\n",
"🎓 Revocação: `VP/(VP + FN)` definida como a proporção de resultados positivos em relação ao número de amostras que eram realmente positivas. Também conhecida como `sensibilidade`.\n",
"\n",
"🎓 Especificidade: `VN/(VN + FP)` definida como a proporção de resultados negativos em relação ao número de amostras que eram realmente negativas.\n",
"\n",
"🎓 Acurácia: `VP + VN/(VP + VN + FP + FN)` A porcentagem de rótulos previstos corretamente para uma amostra.\n",
"\n",
"🎓 Medida F: Uma média ponderada entre a precisão e a revocação, sendo 1 o melhor valor e 0 o pior.\n",
"\n",
"Vamos calcular essas métricas!\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Combine metric functions and calculate them all at once\n",
"eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n",
"eval_metrics(data = results, truth = color, estimate = .pred_class)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualizar a curva ROC deste modelo\n",
"\n",
"Vamos fazer mais uma visualização para observar a chamada [`curva ROC`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic):\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Make a roc_curve\n",
"results %>% \n",
" roc_curve(color, .pred_ORANGE) %>% \n",
" autoplot()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Curvas ROC são frequentemente usadas para obter uma visão do desempenho de um classificador em termos de verdadeiros positivos versus falsos positivos. Curvas ROC geralmente apresentam a `Taxa de Verdadeiros Positivos`/Sensibilidade no eixo Y e a `Taxa de Falsos Positivos`/1-Especificidade no eixo X. Assim, a inclinação da curva e o espaço entre a linha do ponto médio e a curva são importantes: você quer uma curva que rapidamente suba e ultrapasse a linha. No nosso caso, há falsos positivos no início, e então a linha sobe e ultrapassa adequadamente.\n",
"\n",
"Por fim, vamos usar `yardstick::roc_auc()` para calcular a Área Sob a Curva. Uma forma de interpretar a AUC é como a probabilidade de que o modelo classifique um exemplo positivo aleatório mais alto do que um exemplo negativo aleatório.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "r"
}
},
"outputs": [],
"source": [
"# Calculate area under curve\n",
"results %>% \n",
" roc_auc(color, .pred_ORANGE)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O resultado é cerca de `0.975`. Dado que o AUC varia de 0 a 1, você quer um valor alto, já que um modelo que acerta 100% das previsões terá um AUC de 1; neste caso, o modelo é *muito bom*.\n",
"\n",
"Em futuras lições sobre classificações, você aprenderá como melhorar os resultados do seu modelo (como lidar com dados desbalanceados neste caso).\n",
"\n",
"## 🚀Desafio\n",
"\n",
"Há muito mais para explorar sobre regressão logística! Mas a melhor forma de aprender é experimentando. Encontre um conjunto de dados que se preste a esse tipo de análise e construa um modelo com ele. O que você aprende? dica: experimente [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) para conjuntos de dados interessantes.\n",
"\n",
"## Revisão & Estudo Individual\n",
"\n",
"Leia as primeiras páginas [deste artigo de Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) sobre alguns usos práticos da regressão logística. Pense em tarefas que são mais adequadas para um ou outro tipo de regressão entre as que estudamos até agora. O que funcionaria melhor?\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
]
}
],
"metadata": {
"anaconda-cloud": "",
"kernelspec": {
"display_name": "R",
"langauge": "R",
"name": "ir"
},
"language_info": {
"codemirror_mode": "r",
"file_extension": ".r",
"mimetype": "text/x-r-source",
"name": "R",
"pygments_lexer": "r",
"version": "3.4.1"
},
"coopTranslator": {
"original_hash": "feaf125f481a89c468fa115bf2aed580",
"translation_date": "2025-08-29T23:04:05+00:00",
"source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 1
}