{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_3-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "5015d65d61ba75a223bfc56c273aa174", "translation_date": "2025-08-29T22:55:39+00:00", "source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb", "language_code": "br" } }, "cells": [ { "cell_type": "markdown", "source": [], "metadata": { "id": "EgQw8osnsUV-" } }, { "cell_type": "markdown", "source": [ "## Regressão Linear e Polinomial para Precificação de Abóboras - Aula 3\n", "

\n", " \n", "

Infográfico por Dasani Madipalli
\n", "\n", "\n", "#### Introdução\n", "\n", "Até agora, você explorou o que é regressão com dados de exemplo coletados do conjunto de dados de precificação de abóboras que usaremos ao longo desta aula. Você também os visualizou usando `ggplot2`. 💪\n", "\n", "Agora você está pronto para se aprofundar na regressão para aprendizado de máquina. Nesta aula, você aprenderá mais sobre dois tipos de regressão: *regressão linear básica* e *regressão polinomial*, junto com parte da matemática por trás dessas técnicas.\n", "\n", "> Ao longo deste currículo, assumimos conhecimento mínimo de matemática e buscamos torná-la acessível para estudantes de outras áreas. Fique atento a notas, 🧮 destaques, diagramas e outras ferramentas de aprendizado para ajudar na compreensão.\n", "\n", "#### Preparação\n", "\n", "Como lembrete, você está carregando esses dados para fazer perguntas sobre eles.\n", "\n", "- Qual é o melhor momento para comprar abóboras?\n", "\n", "- Qual preço posso esperar por uma caixa de abóboras em miniatura?\n", "\n", "- Devo comprá-las em cestas de meio alqueire ou em caixas de 1 1/9 alqueire? Vamos continuar explorando esses dados.\n", "\n", "Na aula anterior, você criou um `tibble` (uma reinterpretação moderna do data frame) e o preencheu com parte do conjunto de dados original, padronizando os preços por alqueire. Ao fazer isso, no entanto, você conseguiu reunir apenas cerca de 400 pontos de dados e apenas para os meses de outono. Talvez possamos obter um pouco mais de detalhes sobre a natureza dos dados ao limpá-los mais? Vamos descobrir... 🕵️‍♀️\n", "\n", "Para esta tarefa, 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 [estrutura 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) fornece ferramentas simples para examinar e limpar dados sujos.\n", "\n", "- `corrplot`: O [pacote corrplot](https://cran.r-project.org/web/packages/corrplot/vignettes/corrplot-intro.html) oferece uma ferramenta visual exploratória para matrizes de correlação que suporta o reordenamento automático de variáveis para ajudar a detectar padrões ocultos entre elas.\n", "\n", "Você pode instalá-los com:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"corrplot\"))`\n", "\n", "O script abaixo verifica se você possui os pacotes necessários para completar este módulo e os instala para você caso estejam ausentes.\n" ], "metadata": { "id": "WqQPS1OAsg3H" } }, { "cell_type": "code", "execution_count": null, "source": [ "suppressWarnings(if (!require(\"pacman\")) install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, corrplot)" ], "outputs": [], "metadata": { "id": "tA4C2WN3skCf", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "c06cd805-5534-4edc-f72b-d0d1dab96ac0" } }, { "cell_type": "markdown", "source": [ "Vamos carregar esses pacotes incríveis e torná-los disponíveis na nossa sessão atual do R. (Isso é apenas para ilustração, `pacman::p_load()` já fez isso por você)\n", "\n", "## 1. Uma linha de regressão linear\n", "\n", "Como você aprendeu na Aula 1, o objetivo de um exercício de regressão linear é ser capaz de traçar uma *linha* *de* *melhor ajuste* para:\n", "\n", "- **Mostrar relações entre variáveis**. Demonstrar a relação entre as variáveis.\n", "\n", "- **Fazer previsões**. Fazer previsões precisas sobre onde um novo ponto de dados se encaixaria em relação a essa linha.\n", "\n", "Para traçar esse tipo de linha, usamos uma técnica estatística chamada **Regressão dos Mínimos Quadrados**. O termo `mínimos quadrados` significa que todos os pontos de dados ao redor da linha de regressão são elevados ao quadrado e, em seguida, somados. Idealmente, essa soma final deve ser o menor valor possível, porque queremos um número baixo de erros, ou `mínimos quadrados`. Assim, a linha de melhor ajuste é aquela que nos dá o menor valor para a soma dos erros ao quadrado - daí o nome *regressão dos mínimos quadrados*.\n", "\n", "Fazemos isso porque queremos modelar uma linha que tenha a menor distância acumulada de todos os nossos pontos de dados. Também elevamos os termos ao quadrado antes de somá-los, pois estamos preocupados com a magnitude, e não com a direção.\n", "\n", "> **🧮 Mostre-me a matemática**\n", ">\n", "> Essa linha, chamada de *linha de melhor ajuste*, pode ser expressa por [uma equação](https://en.wikipedia.org/wiki/Simple_linear_regression):\n", ">\n", "> Y = a + bX\n", ">\n", "> `X` é a '`variável explicativa` ou `preditor`'. `Y` é a '`variável dependente` ou `resultado`'. A inclinação da linha é `b` e `a` é o intercepto no eixo y, que se refere ao valor de `Y` quando `X = 0`.\n", ">\n", "\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/slope.png \"slope = $y/x$\")\n", " Infográfico por Jen Looper\n", ">\n", "> Primeiro, calcule a inclinação `b`.\n", ">\n", "> Em outras palavras, e referindo-se à pergunta original dos dados das abóboras: \"prever o preço de uma abóbora por alqueire por mês\", `X` se referiria ao preço e `Y` ao mês de venda.\n", ">\n", "> ![](../../../../../../translated_images/calculation.989aa7822020d9d0ba9fc781f1ab5192f3421be86ebb88026528aef33c37b0d8.br.png)\n", " Infográfico por Jen Looper\n", "> \n", "> Calcule o valor de Y. Se você está pagando cerca de \\$4, deve ser abril!\n", ">\n", "> A matemática que calcula a linha deve demonstrar a inclinação da linha, que também depende do intercepto, ou onde `Y` está situado quando `X = 0`.\n", ">\n", "> Você pode observar o método de cálculo desses valores no site [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html). Também visite [este calculador de mínimos quadrados](https://www.mathsisfun.com/data/least-squares-calculator.html) para ver como os valores dos números impactam a linha.\n", "\n", "Não é tão assustador, certo? 🤓\n", "\n", "#### Correlação\n", "\n", "Outro termo importante para entender é o **Coeficiente de Correlação** entre as variáveis X e Y fornecidas. Usando um gráfico de dispersão, você pode visualizar rapidamente esse coeficiente. Um gráfico com pontos de dados alinhados de forma ordenada tem alta correlação, mas um gráfico com pontos de dados espalhados por toda parte entre X e Y tem baixa correlação.\n", "\n", "Um bom modelo de regressão linear será aquele que possui um Coeficiente de Correlação alto (mais próximo de 1 do que de 0) usando o método de Regressão dos Mínimos Quadrados com uma linha de regressão.\n" ], "metadata": { "id": "cdX5FRpvsoP5" } }, { "cell_type": "markdown", "source": [ "## **2. Uma dança com dados: criando um data frame que será usado para modelagem**\n", "\n", "

\n", " \n", "

Arte por @allison_horst
\n", "\n", "\n", "\n" ], "metadata": { "id": "WdUKXk7Bs8-V" } }, { "cell_type": "markdown", "source": [ "Carregue as bibliotecas necessárias e o conjunto de dados. Converta os dados em um data frame contendo um subconjunto dos dados:\n", "\n", "- Considere apenas abóboras com preço por alqueire\n", "\n", "- Converta a data para o formato de mês\n", "\n", "- Calcule o preço como a média entre os preços mais altos e mais baixos\n", "\n", "- Converta o preço para refletir a precificação pela quantidade em alqueires\n", "\n", "> Cobrimos essas etapas na [lição anterior](https://github.com/microsoft/ML-For-Beginners/blob/main/2-Regression/2-Data/solution/lesson_2-R.ipynb).\n" ], "metadata": { "id": "fMCtu2G2s-p8" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the core Tidyverse packages\n", "library(tidyverse)\n", "library(lubridate)\n", "\n", "# Import the pumpkins data\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\")\n", "\n", "\n", "# Get a glimpse and dimensions of the data\n", "glimpse(pumpkins)\n", "\n", "\n", "# Print the first 50 rows of the data set\n", "pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "ryMVZEEPtERn" } }, { "cell_type": "markdown", "source": [ "No espírito de pura aventura, vamos explorar o [`pacote janitor`](../../../../../../2-Regression/3-Linear/solution/R/github.com/sfirke/janitor) que fornece funções simples para examinar e limpar dados desorganizados. Por exemplo, vamos dar uma olhada nos nomes das colunas dos nossos dados:\n" ], "metadata": { "id": "xcNxM70EtJjb" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "5XtpaIigtPfW" } }, { "cell_type": "markdown", "source": [ "🤔 Podemos fazer melhor. Vamos tornar esses nomes de colunas `friendR` convertendo-os para a convenção [snake_case](https://en.wikipedia.org/wiki/Snake_case) usando `janitor::clean_names`. Para saber mais sobre essa função: `?clean_names`\n" ], "metadata": { "id": "IbIqrMINtSHe" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Clean names to the snake_case convention\n", "pumpkins <- pumpkins %>% \n", " clean_names(case = \"snake\")\n", "\n", "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "a2uYvclYtWvX" } }, { "cell_type": "markdown", "source": [ "Muito tidyR 🧹! Agora, uma dança com os dados usando `dplyr`, como na lição anterior! 💃\n" ], "metadata": { "id": "HfhnuzDDtaDd" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Select desired columns\n", "pumpkins <- pumpkins %>% \n", " select(variety, city_name, package, low_price, high_price, date)\n", "\n", "\n", "\n", "# Extract the month from the dates to a new column\n", "pumpkins <- pumpkins %>%\n", " mutate(date = mdy(date),\n", " month = month(date)) %>% \n", " select(-date)\n", "\n", "\n", "\n", "# Create a new column for average Price\n", "pumpkins <- pumpkins %>% \n", " mutate(price = (low_price + high_price)/2)\n", "\n", "\n", "# Retain only pumpkins with the string \"bushel\"\n", "new_pumpkins <- pumpkins %>% \n", " filter(str_detect(string = package, pattern = \"bushel\"))\n", "\n", "\n", "# Normalize the pricing so that you show the pricing per bushel, not per 1 1/9 or 1/2 bushel\n", "new_pumpkins <- new_pumpkins %>% \n", " mutate(price = case_when(\n", " str_detect(package, \"1 1/9\") ~ price/(1.1),\n", " str_detect(package, \"1/2\") ~ price*2,\n", " TRUE ~ price))\n", "\n", "# Relocate column positions\n", "new_pumpkins <- new_pumpkins %>% \n", " relocate(month, .before = variety)\n", "\n", "\n", "# Display the first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "X0wU3gQvtd9f" } }, { "cell_type": "markdown", "source": [ "Bom trabalho!👌 Agora você tem um conjunto de dados limpo e organizado para construir seu novo modelo de regressão!\n", "\n", "Que tal um gráfico de dispersão?\n" ], "metadata": { "id": "UpaIwaxqth82" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Set theme\n", "theme_set(theme_light())\n", "\n", "# Make a scatter plot of month and price\n", "new_pumpkins %>% \n", " ggplot(mapping = aes(x = month, y = price)) +\n", " geom_point(size = 1.6)\n" ], "outputs": [], "metadata": { "id": "DXgU-j37tl5K" } }, { "cell_type": "markdown", "source": [ "Um gráfico de dispersão nos lembra que só temos dados mensais de agosto a dezembro. Provavelmente precisamos de mais dados para conseguir tirar conclusões de forma linear.\n", "\n", "Vamos dar uma olhada novamente nos nossos dados de modelagem:\n" ], "metadata": { "id": "Ve64wVbwtobI" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Display first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "HFQX2ng1tuSJ" } }, { "cell_type": "markdown", "source": [ "E se quiséssemos prever o `price` de uma abóbora com base nas colunas `city` ou `package`, que são do tipo caractere? Ou, de forma ainda mais simples, como poderíamos encontrar a correlação (que exige que ambos os seus inputs sejam numéricos) entre, por exemplo, `package` e `price`? 🤷🤷\n", "\n", "Modelos de aprendizado de máquina funcionam melhor com características numéricas em vez de valores de texto, então geralmente é necessário converter características categóricas em representações numéricas.\n", "\n", "Isso significa que precisamos encontrar uma maneira de reformular nossos preditores para torná-los mais fáceis de usar por um modelo de forma eficaz, um processo conhecido como `feature engineering`.\n" ], "metadata": { "id": "7hsHoxsStyjJ" } }, { "cell_type": "markdown", "source": [ "## 3. Pré-processamento de dados para modelagem com recipes 👩‍🍳👨‍🍳\n", "\n", "Atividades que reformulam os valores dos preditores para torná-los mais fáceis de serem usados de forma eficaz por um modelo são chamadas de `engenharia de atributos`.\n", "\n", "Modelos diferentes têm requisitos de pré-processamento diferentes. Por exemplo, mínimos quadrados requerem `codificação de variáveis categóricas`, como mês, variedade e city_name. Isso simplesmente envolve `traduzir` uma coluna com `valores categóricos` em uma ou mais `colunas numéricas` que substituem a original.\n", "\n", "Por exemplo, suponha que seus dados incluam a seguinte característica categórica:\n", "\n", "| cidade |\n", "|:---------:|\n", "| Denver |\n", "| Nairobi |\n", "| Tóquio |\n", "\n", "Você pode aplicar *codificação ordinal* para substituir cada categoria por um valor inteiro único, assim:\n", "\n", "| cidade |\n", "|:------:|\n", "| 0 |\n", "| 1 |\n", "| 2 |\n", "\n", "E é isso que faremos com nossos dados!\n", "\n", "Nesta seção, exploraremos outro pacote incrível do Tidymodels: [recipes](https://tidymodels.github.io/recipes/) - que foi projetado para ajudar você a pré-processar seus dados **antes** de treinar seu modelo. No seu núcleo, uma receita é um objeto que define quais etapas devem ser aplicadas a um conjunto de dados para prepará-lo para a modelagem.\n", "\n", "Agora, vamos criar uma receita que prepara nossos dados para modelagem, substituindo um número inteiro único para todas as observações nas colunas de preditores:\n" ], "metadata": { "id": "AD5kQbcvt3Xl" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\n", "pumpkins_recipe <- recipe(price ~ ., data = new_pumpkins) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "# Print out the recipe\n", "pumpkins_recipe" ], "outputs": [], "metadata": { "id": "BNaFKXfRt9TU" } }, { "cell_type": "markdown", "source": [ "Incrível! 👏 Acabamos de criar nossa primeira receita que especifica um resultado (preço) e seus respectivos preditores, e que todas as colunas de preditores devem ser codificadas em um conjunto de números inteiros 🙌! Vamos analisar isso rapidamente:\n", "\n", "- A chamada para `recipe()` com uma fórmula informa à receita os *papéis* das variáveis usando os dados de `new_pumpkins` como referência. Por exemplo, a coluna `price` foi atribuída ao papel de `outcome`, enquanto o restante das colunas foi atribuído ao papel de `predictor`.\n", "\n", "- `step_integer(all_predictors(), zero_based = TRUE)` especifica que todos os preditores devem ser convertidos em um conjunto de números inteiros, começando a numeração em 0.\n", "\n", "Temos certeza de que você pode estar pensando algo como: \"Isso é tão legal!! Mas e se eu precisar confirmar que as receitas estão fazendo exatamente o que eu espero? 🤔\"\n", "\n", "Esse é um pensamento incrível! Veja bem, uma vez que sua receita está definida, você pode estimar os parâmetros necessários para realmente pré-processar os dados e, em seguida, extrair os dados processados. Normalmente, você não precisa fazer isso ao usar Tidymodels (veremos a convenção normal em apenas um minuto-\\> `workflows`), mas pode ser útil quando você quiser fazer algum tipo de verificação para confirmar que as receitas estão funcionando como esperado.\n", "\n", "Para isso, você precisará de dois outros verbos: `prep()` e `bake()`, e como sempre, nossos pequenos amigos do R criados por [`Allison Horst`](https://github.com/allisonhorst/stats-illustrations) ajudam você a entender isso melhor!\n", "\n", "

\n", " \n", "

Arte por @allison_horst
\n" ], "metadata": { "id": "KEiO0v7kuC9O" } }, { "cell_type": "markdown", "source": [ "[`prep()`](https://recipes.tidymodels.org/reference/prep.html): estima os parâmetros necessários a partir de um conjunto de treinamento que podem ser posteriormente aplicados a outros conjuntos de dados. Por exemplo, para uma determinada coluna preditora, qual observação será atribuída ao inteiro 0, 1, 2, etc.\n", "\n", "[`bake()`](https://recipes.tidymodels.org/reference/bake.html): utiliza uma receita preparada e aplica as operações a qualquer conjunto de dados.\n", "\n", "Dito isso, vamos preparar e aplicar nossas receitas para realmente confirmar que, nos bastidores, as colunas preditoras serão primeiro codificadas antes que um modelo seja ajustado.\n" ], "metadata": { "id": "Q1xtzebuuTCP" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Prep the recipe\n", "pumpkins_prep <- prep(pumpkins_recipe)\n", "\n", "# Bake the recipe to extract a preprocessed new_pumpkins data\n", "baked_pumpkins <- bake(pumpkins_prep, new_data = NULL)\n", "\n", "# Print out the baked data set\n", "baked_pumpkins %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "FGBbJbP_uUUn" } }, { "cell_type": "markdown", "source": [ "Uhuu! 🥳 Os dados processados `baked_pumpkins` têm todos os seus preditores codificados, confirmando que, de fato, as etapas de pré-processamento definidas como nossa receita funcionarão conforme o esperado. Isso pode dificultar a leitura para você, mas torna muito mais compreensível para o Tidymodels! Reserve um tempo para descobrir qual observação foi mapeada para um número inteiro correspondente.\n", "\n", "Também vale mencionar que `baked_pumpkins` é um data frame no qual podemos realizar cálculos.\n", "\n", "Por exemplo, vamos tentar encontrar uma boa correlação entre dois pontos dos seus dados para, potencialmente, construir um bom modelo preditivo. Usaremos a função `cor()` para isso. Digite `?cor()` para saber mais sobre a função.\n" ], "metadata": { "id": "1dvP0LBUueAW" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Find the correlation between the city_name and the price\n", "cor(baked_pumpkins$city_name, baked_pumpkins$price)\n", "\n", "# Find the correlation between the package and the price\n", "cor(baked_pumpkins$package, baked_pumpkins$price)\n" ], "outputs": [], "metadata": { "id": "3bQzXCjFuiSV" } }, { "cell_type": "markdown", "source": [ "Como se verifica, há apenas uma correlação fraca entre a Cidade e o Preço. No entanto, há uma correlação um pouco melhor entre o Pacote e seu Preço. Faz sentido, certo? Normalmente, quanto maior a caixa do produto, maior o preço.\n", "\n", "Já que estamos nisso, vamos também tentar visualizar uma matriz de correlação de todas as colunas usando o pacote `corrplot`.\n" ], "metadata": { "id": "BToPWbgjuoZw" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the corrplot package\n", "library(corrplot)\n", "\n", "# Obtain correlation matrix\n", "corr_mat <- cor(baked_pumpkins %>% \n", " # Drop columns that are not really informative\n", " select(-c(low_price, high_price)))\n", "\n", "# Make a correlation plot between the variables\n", "corrplot(corr_mat, method = \"shade\", shade.col = NA, tl.col = \"black\", tl.srt = 45, addCoef.col = \"black\", cl.pos = \"n\", order = \"original\")" ], "outputs": [], "metadata": { "id": "ZwAL3ksmutVR" } }, { "cell_type": "markdown", "source": [ "🤩🤩 Muito melhor.\n", "\n", "Uma boa pergunta a se fazer agora com esses dados seria: '`Qual preço posso esperar de um determinado pacote de abóboras?`' Vamos direto ao ponto!\n", "\n", "> Nota: Quando você **`bake()`** a receita preparada **`pumpkins_prep`** com **`new_data = NULL`**, você extrai os dados de treinamento processados (ou seja, codificados). Se você tivesse outro conjunto de dados, por exemplo, um conjunto de teste, e quisesse ver como a receita o pré-processaria, bastaria assar **`pumpkins_prep`** com **`new_data = test_set`**\n", "\n", "## 4. Construir um modelo de regressão linear\n", "\n", "

\n", " \n", "

Infográfico por Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "YqXjLuWavNxW" } }, { "cell_type": "markdown", "source": [ "Agora que criamos uma receita e confirmamos que os dados serão pré-processados adequadamente, vamos construir um modelo de regressão para responder à pergunta: `Qual preço posso esperar de um determinado pacote de abóbora?`\n", "\n", "#### Treinar um modelo de regressão linear usando o conjunto de treinamento\n", "\n", "Como você já deve ter percebido, a coluna *price* é a variável `resultado`, enquanto a coluna *package* é a variável `preditor`.\n", "\n", "Para isso, primeiro dividiremos os dados de forma que 80% sejam destinados ao treinamento e 20% ao conjunto de teste. Em seguida, definiremos uma receita que codificará a coluna preditora em um conjunto de números inteiros e, depois, construiremos uma especificação de modelo. Não vamos preparar e aplicar nossa receita, já que sabemos que ela pré-processará os dados conforme esperado.\n" ], "metadata": { "id": "Pq0bSzCevW-h" } }, { "cell_type": "code", "execution_count": null, "source": [ "set.seed(2056)\n", "# Split the data into training and test sets\n", "pumpkins_split <- new_pumpkins %>% \n", " initial_split(prop = 0.8)\n", "\n", "\n", "# Extract training and test data\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "\n", "\n", "# Create a recipe for preprocessing the data\n", "lm_pumpkins_recipe <- recipe(price ~ package, data = pumpkins_train) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "\n", "# Create a linear model specification\n", "lm_spec <- linear_reg() %>% \n", " set_engine(\"lm\") %>% \n", " set_mode(\"regression\")" ], "outputs": [], "metadata": { "id": "CyoEh_wuvcLv" } }, { "cell_type": "markdown", "source": [ "Bom trabalho! Agora que temos uma receita e uma especificação de modelo, precisamos encontrar uma maneira de agrupá-las em um objeto que, primeiro, faça o pré-processamento dos dados (prep+bake nos bastidores), ajuste o modelo nos dados pré-processados e também permita possíveis atividades de pós-processamento. Que tal isso para sua tranquilidade! 🤩\n", "\n", "No Tidymodels, esse objeto prático é chamado de [`workflow`](https://workflows.tidymodels.org/) e organiza convenientemente seus componentes de modelagem! É o que chamaríamos de *pipelines* em *Python*.\n", "\n", "Então, vamos agrupar tudo em um workflow! 📦\n" ], "metadata": { "id": "G3zF_3DqviFJ" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Hold modelling components in a workflow\n", "lm_wf <- workflow() %>% \n", " add_recipe(lm_pumpkins_recipe) %>% \n", " add_model(lm_spec)\n", "\n", "# Print out the workflow\n", "lm_wf" ], "outputs": [], "metadata": { "id": "T3olroU3v-WX" } }, { "cell_type": "markdown", "source": [ "👌 Além disso, um fluxo de trabalho pode ser ajustado/treinado de maneira muito semelhante a um modelo.\n" ], "metadata": { "id": "zd1A5tgOwEPX" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Train the model\n", "lm_wf_fit <- lm_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the model coefficients learned \n", "lm_wf_fit" ], "outputs": [], "metadata": { "id": "NhJagFumwFHf" } }, { "cell_type": "markdown", "source": [ "A partir da saída do modelo, podemos observar os coeficientes aprendidos durante o treinamento. Eles representam os coeficientes da linha de melhor ajuste que nos dá o menor erro geral entre a variável real e a prevista.\n", "\n", "#### Avaliar o desempenho do modelo usando o conjunto de teste\n", "\n", "É hora de ver como o modelo se saiu 📏! Como fazemos isso?\n", "\n", "Agora que treinamos o modelo, podemos usá-lo para fazer previsões para o `test_set` usando `parsnip::predict()`. Em seguida, podemos comparar essas previsões com os valores reais dos rótulos para avaliar o quão bem (ou não!) o modelo está funcionando.\n", "\n", "Vamos começar fazendo previsões para o conjunto de teste e, em seguida, vinculando as colunas ao conjunto de teste.\n" ], "metadata": { "id": "_4QkGtBTwItF" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make predictions for the test set\n", "predictions <- lm_wf_fit %>% \n", " predict(new_data = pumpkins_test)\n", "\n", "\n", "# Bind predictions to the test set\n", "lm_results <- pumpkins_test %>% \n", " select(c(package, price)) %>% \n", " bind_cols(predictions)\n", "\n", "\n", "# Print the first ten rows of the tibble\n", "lm_results %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "UFZzTG0gwTs9" } }, { "cell_type": "markdown", "source": [ "Sim, você acabou de treinar um modelo e usá-lo para fazer previsões! 🔮 Será que ele é bom? Vamos avaliar o desempenho do modelo!\n", "\n", "No Tidymodels, fazemos isso usando `yardstick::metrics()`! Para regressão linear, vamos focar nas seguintes métricas:\n", "\n", "- `Root Mean Square Error (RMSE)`: A raiz quadrada do [MSE](https://en.wikipedia.org/wiki/Mean_squared_error). Isso resulta em uma métrica absoluta na mesma unidade do rótulo (neste caso, o preço de uma abóbora). Quanto menor o valor, melhor o modelo (de forma simplificada, representa o preço médio pelo qual as previsões estão erradas!).\n", "\n", "- `Coefficient of Determination (geralmente conhecido como R-quadrado ou R2)`: Uma métrica relativa em que, quanto maior o valor, melhor o ajuste do modelo. Essencialmente, essa métrica representa o quanto da variância entre os valores previstos e reais o modelo é capaz de explicar.\n" ], "metadata": { "id": "0A5MjzM7wW9M" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Evaluate performance of linear regression\n", "metrics(data = lm_results,\n", " truth = price,\n", " estimate = .pred)" ], "outputs": [], "metadata": { "id": "reJ0UIhQwcEH" } }, { "cell_type": "markdown", "source": [ "Lá se vai o desempenho do modelo. Vamos ver se conseguimos uma indicação melhor visualizando um gráfico de dispersão do pacote e do preço, e então usar as previsões feitas para sobrepor uma linha de melhor ajuste.\n", "\n", "Isso significa que teremos que preparar e processar o conjunto de teste para codificar a coluna de pacote e, em seguida, vinculá-la às previsões feitas pelo nosso modelo.\n" ], "metadata": { "id": "fdgjzjkBwfWt" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Encode package column\n", "package_encode <- lm_pumpkins_recipe %>% \n", " prep() %>% \n", " bake(new_data = pumpkins_test) %>% \n", " select(package)\n", "\n", "\n", "# Bind encoded package column to the results\n", "lm_results <- lm_results %>% \n", " bind_cols(package_encode %>% \n", " rename(package_integer = package)) %>% \n", " relocate(package_integer, .after = package)\n", "\n", "\n", "# Print new results data frame\n", "lm_results %>% \n", " slice_head(n = 5)\n", "\n", "\n", "# Make a scatter plot\n", "lm_results %>% \n", " ggplot(mapping = aes(x = package_integer, y = price)) +\n", " geom_point(size = 1.6) +\n", " # Overlay a line of best fit\n", " geom_line(aes(y = .pred), color = \"orange\", size = 1.2) +\n", " xlab(\"package\")\n", " \n" ], "outputs": [], "metadata": { "id": "R0nw719lwkHE" } }, { "cell_type": "markdown", "source": [ "Ótimo! Como você pode ver, o modelo de regressão linear não generaliza muito bem a relação entre um pacote e seu preço correspondente.\n", "\n", "🎃 Parabéns, você acabou de criar um modelo que pode ajudar a prever o preço de algumas variedades de abóboras. Sua plantação de abóboras para o feriado ficará linda. Mas provavelmente você pode criar um modelo melhor!\n", "\n", "## 5. Construir um modelo de regressão polinomial\n", "\n", "

\n", " \n", "

Infográfico por Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "HOCqJXLTwtWI" } }, { "cell_type": "markdown", "source": [ "Às vezes, nossos dados podem não ter uma relação linear, mas ainda assim queremos prever um resultado. A regressão polinomial pode nos ajudar a fazer previsões para relações não lineares mais complexas.\n", "\n", "Por exemplo, considere a relação entre o pacote e o preço no nosso conjunto de dados de abóboras. Embora às vezes haja uma relação linear entre as variáveis - quanto maior o volume da abóbora, maior o preço - em outras ocasiões essas relações não podem ser representadas como um plano ou uma linha reta.\n", "\n", "> ✅ Aqui estão [alguns exemplos adicionais](https://online.stat.psu.edu/stat501/lesson/9/9.8) de dados que poderiam usar regressão polinomial\n", ">\n", "> Dê outra olhada na relação entre Variedade e Preço no gráfico anterior. Esse gráfico de dispersão parece que necessariamente deveria ser analisado por uma linha reta? Talvez não. Nesse caso, você pode tentar a regressão polinomial.\n", ">\n", "> ✅ Polinômios são expressões matemáticas que podem consistir em uma ou mais variáveis e coeficientes\n", "\n", "#### Treine um modelo de regressão polinomial usando o conjunto de treinamento\n", "\n", "A regressão polinomial cria uma *linha curva* para ajustar melhor os dados não lineares.\n", "\n", "Vamos ver se um modelo polinomial terá um desempenho melhor ao fazer previsões. Seguiremos um procedimento um pouco semelhante ao que fizemos antes:\n", "\n", "- Criar uma receita que especifique os passos de pré-processamento que devem ser realizados nos nossos dados para prepará-los para modelagem, ou seja: codificar os preditores e calcular polinômios de grau *n*\n", "\n", "- Construir uma especificação de modelo\n", "\n", "- Agrupar a receita e a especificação do modelo em um fluxo de trabalho\n", "\n", "- Criar um modelo ajustando o fluxo de trabalho\n", "\n", "- Avaliar o desempenho do modelo nos dados de teste\n", "\n", "Vamos começar!\n" ], "metadata": { "id": "VcEIpRV9wzYr" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\r\n", "poly_pumpkins_recipe <-\r\n", " recipe(price ~ package, data = pumpkins_train) %>%\r\n", " step_integer(all_predictors(), zero_based = TRUE) %>% \r\n", " step_poly(all_predictors(), degree = 4)\r\n", "\r\n", "\r\n", "# Create a model specification\r\n", "poly_spec <- linear_reg() %>% \r\n", " set_engine(\"lm\") %>% \r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Bundle recipe and model spec into a workflow\r\n", "poly_wf <- workflow() %>% \r\n", " add_recipe(poly_pumpkins_recipe) %>% \r\n", " add_model(poly_spec)\r\n", "\r\n", "\r\n", "# Create a model\r\n", "poly_wf_fit <- poly_wf %>% \r\n", " fit(data = pumpkins_train)\r\n", "\r\n", "\r\n", "# Print learned model coefficients\r\n", "poly_wf_fit\r\n", "\r\n", " " ], "outputs": [], "metadata": { "id": "63n_YyRXw3CC" } }, { "cell_type": "markdown", "source": [ "#### Avaliar o desempenho do modelo\n", "\n", "👏👏Você construiu um modelo polinomial, vamos fazer previsões no conjunto de teste!\n" ], "metadata": { "id": "-LHZtztSxDP0" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make price predictions on test data\r\n", "poly_results <- poly_wf_fit %>% predict(new_data = pumpkins_test) %>% \r\n", " bind_cols(pumpkins_test %>% select(c(package, price))) %>% \r\n", " relocate(.pred, .after = last_col())\r\n", "\r\n", "\r\n", "# Print the results\r\n", "poly_results %>% \r\n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "YUFpQ_dKxJGx" } }, { "cell_type": "markdown", "source": [ "Uhuu, vamos avaliar como o modelo se saiu no test_set usando `yardstick::metrics()`.\n" ], "metadata": { "id": "qxdyj86bxNGZ" } }, { "cell_type": "code", "execution_count": null, "source": [ "metrics(data = poly_results, truth = price, estimate = .pred)" ], "outputs": [], "metadata": { "id": "8AW5ltkBxXDm" } }, { "cell_type": "markdown", "source": [ "🤩🤩 Desempenho muito melhor.\n", "\n", "O `rmse` diminuiu de cerca de 7 para cerca de 3, indicando uma redução no erro entre o preço real e o preço previsto. Você pode *interpretar livremente* isso como significando que, em média, as previsões incorretas erram por volta de R\\$3. O `rsq` aumentou de cerca de 0,4 para 0,8.\n", "\n", "Todas essas métricas indicam que o modelo polinomial tem um desempenho muito melhor do que o modelo linear. Bom trabalho!\n", "\n", "Vamos ver se conseguimos visualizar isso!\n" ], "metadata": { "id": "6gLHNZDwxYaS" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Bind encoded package column to the results\r\n", "poly_results <- poly_results %>% \r\n", " bind_cols(package_encode %>% \r\n", " rename(package_integer = package)) %>% \r\n", " relocate(package_integer, .after = package)\r\n", "\r\n", "\r\n", "# Print new results data frame\r\n", "poly_results %>% \r\n", " slice_head(n = 5)\r\n", "\r\n", "\r\n", "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_line(aes(y = .pred), color = \"midnightblue\", size = 1.2) +\r\n", " xlab(\"package\")\r\n" ], "outputs": [], "metadata": { "id": "A83U16frxdF1" } }, { "cell_type": "markdown", "source": [ "Você pode ver uma linha curva que se ajusta melhor aos seus dados! 🤩\n", "\n", "Você pode torná-la ainda mais suave passando uma fórmula polinomial para `geom_smooth`, assim:\n" ], "metadata": { "id": "4U-7aHOVxlGU" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_smooth(method = lm, formula = y ~ poly(x, degree = 4), color = \"midnightblue\", size = 1.2, se = FALSE) +\r\n", " xlab(\"package\")" ], "outputs": [], "metadata": { "id": "5vzNT0Uexm-w" } }, { "cell_type": "markdown", "source": [ "Muito parecido com uma curva suave!🤩\n", "\n", "Aqui está como você pode fazer uma nova previsão:\n" ], "metadata": { "id": "v9u-wwyLxq4G" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a hypothetical data frame\r\n", "hypo_tibble <- tibble(package = \"bushel baskets\")\r\n", "\r\n", "# Make predictions using linear model\r\n", "lm_pred <- lm_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Make predictions using polynomial model\r\n", "poly_pred <- poly_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Return predictions in a list\r\n", "list(\"linear model prediction\" = lm_pred, \r\n", " \"polynomial model prediction\" = poly_pred)\r\n" ], "outputs": [], "metadata": { "id": "jRPSyfQGxuQv" } }, { "cell_type": "markdown", "source": [ "A previsão do `polynomial model` faz sentido, considerando os gráficos de dispersão de `price` e `package`! E, se este modelo for melhor do que o anterior, analisando os mesmos dados, você precisará planejar um orçamento para essas abóboras mais caras!\n", "\n", "🏆 Muito bem! Você criou dois modelos de regressão em uma única lição. Na seção final sobre regressão, você aprenderá sobre regressão logística para determinar categorias.\n", "\n", "## **🚀Desafio**\n", "\n", "Teste várias variáveis diferentes neste notebook para ver como a correlação corresponde à precisão do modelo.\n", "\n", "## [**Questionário pós-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/14/)\n", "\n", "## **Revisão e Autoestudo**\n", "\n", "Nesta lição, aprendemos sobre Regressão Linear. Existem outros tipos importantes de Regressão. Leia sobre as técnicas Stepwise, Ridge, Lasso e Elasticnet. Um bom curso para aprender mais é o [curso de Aprendizado Estatístico de Stanford](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).\n", "\n", "Se você quiser aprender mais sobre como usar o incrível framework Tidymodels, confira os seguintes recursos:\n", "\n", "- Site do Tidymodels: [Comece com Tidymodels](https://www.tidymodels.org/start/)\n", "\n", "- Max Kuhn e Julia Silge, [*Tidy Modeling with R*](https://www.tmwr.org/)*.*\n", "\n", "###### **AGRADECIMENTOS A:**\n", "\n", "[Allison Horst](https://twitter.com/allison_horst?lang=en) por criar as ilustrações incríveis que tornam o R mais acolhedor e envolvente. Encontre mais ilustrações na sua [galeria](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n" ], "metadata": { "id": "8zOLOWqMxzk5" } }, { "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" ] } ] }