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.
723 lines
28 KiB
723 lines
28 KiB
{
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2,
|
|
"metadata": {
|
|
"colab": {
|
|
"name": "lesson_10-R.ipynb",
|
|
"provenance": [],
|
|
"collapsed_sections": []
|
|
},
|
|
"kernelspec": {
|
|
"name": "ir",
|
|
"display_name": "R"
|
|
},
|
|
"language_info": {
|
|
"name": "R"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "2621e24705e8100893c9bf84e0fc8aef",
|
|
"translation_date": "2025-09-03T20:39:15+00:00",
|
|
"source_file": "4-Classification/1-Introduction/solution/R/lesson_10-R.ipynb",
|
|
"language_code": "pt"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"# Construir um modelo de classificação: Deliciosas Cozinhas Asiáticas e Indianas\n"
|
|
],
|
|
"metadata": {
|
|
"id": "ItETB4tSFprR"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## Introdução à classificação: Limpar, preparar e visualizar os seus dados\n",
|
|
"\n",
|
|
"Nestes quatro módulos, irá explorar um dos focos fundamentais do machine learning clássico - *classificação*. Vamos percorrer o uso de vários algoritmos de classificação com um conjunto de dados sobre as brilhantes culinárias da Ásia e da Índia. Esperamos que esteja com fome!\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/pinch.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Celebre as culinárias pan-asiáticas nestas lições! Imagem por Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"<!---->\n",
|
|
"\n",
|
|
"Classificação é uma forma de [aprendizagem supervisionada](https://wikipedia.org/wiki/Supervised_learning) que tem muito em comum com técnicas de regressão. Na classificação, treina-se um modelo para prever a que `categoria` um item pertence. Se o machine learning trata de prever valores ou nomes para coisas usando conjuntos de dados, então a classificação geralmente se divide em dois grupos: *classificação binária* e *classificação multicategorias*.\n",
|
|
"\n",
|
|
"Lembre-se:\n",
|
|
"\n",
|
|
"- **Regressão linear** ajudou-o a prever relações entre variáveis e fazer previsões precisas sobre onde um novo ponto de dados se encaixaria em relação àquela linha. Por exemplo, poderia prever valores numéricos como *qual seria o preço de uma abóbora em setembro vs. dezembro*.\n",
|
|
"\n",
|
|
"- **Regressão logística** ajudou-o a descobrir \"categorias binárias\": a este preço, *esta abóbora é laranja ou não-laranja*?\n",
|
|
"\n",
|
|
"A classificação utiliza vários algoritmos para determinar outras formas de identificar o rótulo ou classe de um ponto de dados. Vamos trabalhar com estes dados de culinária para ver se, ao observar um grupo de ingredientes, conseguimos determinar a sua origem culinária.\n",
|
|
"\n",
|
|
"### [**Questionário pré-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/19/)\n",
|
|
"\n",
|
|
"### **Introdução**\n",
|
|
"\n",
|
|
"A classificação é uma das atividades fundamentais do investigador de machine learning e do cientista de dados. Desde a classificação básica de um valor binário (\"este email é spam ou não?\"), até à classificação e segmentação complexa de imagens usando visão computacional, é sempre útil poder organizar dados em classes e fazer perguntas sobre eles.\n",
|
|
"\n",
|
|
"Para expressar o processo de forma mais científica, o seu método de classificação cria um modelo preditivo que permite mapear a relação entre variáveis de entrada e variáveis de saída.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/binary-multiclass.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Problemas binários vs. multicategorias para algoritmos de classificação. Infográfico por Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Antes de começar o processo de limpar os nossos dados, visualizá-los e prepará-los para as nossas tarefas de ML, vamos aprender um pouco sobre as várias formas como o machine learning pode ser utilizado para classificar dados.\n",
|
|
"\n",
|
|
"Derivada da [estatística](https://wikipedia.org/wiki/Statistical_classification), a classificação usando machine learning clássico utiliza características, como `fumador`, `peso` e `idade`, para determinar *probabilidade de desenvolver X doença*. Como uma técnica de aprendizagem supervisionada semelhante aos exercícios de regressão que realizou anteriormente, os seus dados são rotulados e os algoritmos de ML utilizam esses rótulos para classificar e prever classes (ou 'características') de um conjunto de dados e atribuí-los a um grupo ou resultado.\n",
|
|
"\n",
|
|
"✅ Tire um momento para imaginar um conjunto de dados sobre culinárias. O que um modelo multicategorias seria capaz de responder? O que um modelo binário seria capaz de responder? E se quisesse determinar se uma determinada culinária provavelmente utiliza feno-grego? E se quisesse ver se, dado um saco de compras cheio de anis-estrelado, alcachofras, couve-flor e rábano, conseguiria criar um prato típico indiano?\n",
|
|
"\n",
|
|
"### **Olá 'classificador'**\n",
|
|
"\n",
|
|
"A pergunta que queremos fazer a este conjunto de dados de culinária é, na verdade, uma questão **multicategorias**, já que temos várias possíveis culinárias nacionais com que trabalhar. Dado um lote de ingredientes, a qual destas muitas classes os dados se encaixam?\n",
|
|
"\n",
|
|
"O Tidymodels oferece vários algoritmos diferentes para classificar dados, dependendo do tipo de problema que deseja resolver. Nas próximas duas lições, aprenderá sobre alguns desses algoritmos.\n",
|
|
"\n",
|
|
"#### **Pré-requisitos**\n",
|
|
"\n",
|
|
"Para esta lição, precisaremos dos seguintes pacotes para limpar, preparar e visualizar os nossos dados:\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 machine learning.\n",
|
|
"\n",
|
|
"- `DataExplorer`: O [pacote DataExplorer](https://cran.r-project.org/web/packages/DataExplorer/vignettes/dataexplorer-intro.html) foi criado para simplificar e automatizar o processo de EDA e geração de relatórios.\n",
|
|
"\n",
|
|
"- `themis`: O [pacote themis](https://themis.tidymodels.org/) fornece passos extras de receitas para lidar com dados desequilibrados.\n",
|
|
"\n",
|
|
"Pode instalá-los como:\n",
|
|
"\n",
|
|
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"DataExplorer\", \"here\"))`\n",
|
|
"\n",
|
|
"Alternativamente, o script abaixo verifica se tem os pacotes necessários para completar este módulo e instala-os caso estejam em falta.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "ri5bQxZ-Fz_0"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\r\n",
|
|
"\r\n",
|
|
"pacman::p_load(tidyverse, tidymodels, DataExplorer, themis, here)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "KIPxa4elGAPI"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Mais tarde, iremos carregar estes pacotes incríveis e torná-los disponíveis na nossa sessão atual de R. (Isto é apenas para ilustração, `pacman::p_load()` já fez isso por si)\n"
|
|
],
|
|
"metadata": {
|
|
"id": "YkKAxOJvGD4C"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## Exercício - limpar e equilibrar os seus dados\n",
|
|
"\n",
|
|
"A primeira tarefa, antes de começar este projeto, é limpar e **equilibrar** os seus dados para obter melhores resultados.\n",
|
|
"\n",
|
|
"Vamos conhecer os dados! 🕵️\n"
|
|
],
|
|
"metadata": {
|
|
"id": "PFkQDlk0GN5O"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Import data\r\n",
|
|
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv\")\r\n",
|
|
"\r\n",
|
|
"# View the first 5 rows\r\n",
|
|
"df %>% \r\n",
|
|
" slice_head(n = 5)\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "Qccw7okxGT0S"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Interessante! Pelo que parece, a primeira coluna é uma espécie de coluna `id`. Vamos obter um pouco mais de informações sobre os dados.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "XrWnlgSrGVmR"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Basic information about the data\r\n",
|
|
"df %>%\r\n",
|
|
" introduce()\r\n",
|
|
"\r\n",
|
|
"# Visualize basic information above\r\n",
|
|
"df %>% \r\n",
|
|
" plot_intro(ggtheme = theme_light())"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "4UcGmxRxGieA"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"A partir dos resultados, podemos ver imediatamente que temos `2448` linhas e `385` colunas e `0` valores em falta. Também temos 1 coluna discreta, *cuisine*.\n",
|
|
"\n",
|
|
"## Exercício - aprender sobre cozinhas\n",
|
|
"\n",
|
|
"Agora o trabalho começa a tornar-se mais interessante. Vamos descobrir a distribuição dos dados, por cozinha.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "AaPubl__GmH5"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Count observations per cuisine\r\n",
|
|
"df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(n)\r\n",
|
|
"\r\n",
|
|
"# Plot the distribution\r\n",
|
|
"theme_set(theme_light())\r\n",
|
|
"df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" ggplot(mapping = aes(x = n, y = reorder(cuisine, -n))) +\r\n",
|
|
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
|
|
" ylab(\"cuisine\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "FRsBVy5eGrrv"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Existem um número finito de cozinhas, mas a distribuição dos dados é desigual. Pode resolver isso! Antes de o fazer, explore um pouco mais.\n",
|
|
"\n",
|
|
"De seguida, vamos atribuir cada cozinha ao seu próprio tibble e descobrir quantos dados estão disponíveis (linhas, colunas) por cozinha.\n",
|
|
"\n",
|
|
"> Um [tibble](https://tibble.tidyverse.org/) é uma versão moderna de um data frame.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/dplyr_filter.jpg\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Ilustração por @allison_horst</figcaption>\n"
|
|
],
|
|
"metadata": {
|
|
"id": "vVvyDb1kG2in"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Create individual tibble for the cuisines\r\n",
|
|
"thai_df <- df %>% \r\n",
|
|
" filter(cuisine == \"thai\")\r\n",
|
|
"japanese_df <- df %>% \r\n",
|
|
" filter(cuisine == \"japanese\")\r\n",
|
|
"chinese_df <- df %>% \r\n",
|
|
" filter(cuisine == \"chinese\")\r\n",
|
|
"indian_df <- df %>% \r\n",
|
|
" filter(cuisine == \"indian\")\r\n",
|
|
"korean_df <- df %>% \r\n",
|
|
" filter(cuisine == \"korean\")\r\n",
|
|
"\r\n",
|
|
"\r\n",
|
|
"# Find out how much data is available per cuisine\r\n",
|
|
"cat(\" thai df:\", dim(thai_df), \"\\n\",\r\n",
|
|
" \"japanese df:\", dim(japanese_df), \"\\n\",\r\n",
|
|
" \"chinese_df:\", dim(chinese_df), \"\\n\",\r\n",
|
|
" \"indian_df:\", dim(indian_df), \"\\n\",\r\n",
|
|
" \"korean_df:\", dim(korean_df))"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "0TvXUxD3G8Bk"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## **Exercício - Descobrir os principais ingredientes por cozinha usando dplyr**\n",
|
|
"\n",
|
|
"Agora pode explorar mais profundamente os dados e descobrir quais são os ingredientes típicos de cada cozinha. Deve limpar os dados recorrentes que criam confusão entre as cozinhas, então vamos aprender sobre este problema.\n",
|
|
"\n",
|
|
"Crie uma função `create_ingredient()` em R que devolva um dataframe de ingredientes. Esta função começará por remover uma coluna pouco útil e organizar os ingredientes pelo seu número de ocorrências.\n",
|
|
"\n",
|
|
"A estrutura básica de uma função em R é:\n",
|
|
"\n",
|
|
"`myFunction <- function(arglist){`\n",
|
|
"\n",
|
|
"**`...`**\n",
|
|
"\n",
|
|
"**`return`**`(value)`\n",
|
|
"\n",
|
|
"`}`\n",
|
|
"\n",
|
|
"Uma introdução prática às funções em R pode ser encontrada [aqui](https://skirmer.github.io/presentations/functions_with_r.html#1).\n",
|
|
"\n",
|
|
"Vamos direto ao assunto! Vamos utilizar os [verbos dplyr](https://dplyr.tidyverse.org/) que temos vindo a aprender nas nossas lições anteriores. Como resumo:\n",
|
|
"\n",
|
|
"- `dplyr::select()`: ajuda a escolher quais **colunas** manter ou excluir.\n",
|
|
"\n",
|
|
"- `dplyr::pivot_longer()`: ajuda a \"alongar\" os dados, aumentando o número de linhas e diminuindo o número de colunas.\n",
|
|
"\n",
|
|
"- `dplyr::group_by()` e `dplyr::summarise()`: ajudam a encontrar estatísticas resumidas para diferentes grupos e colocá-las numa tabela organizada.\n",
|
|
"\n",
|
|
"- `dplyr::filter()`: cria um subconjunto dos dados contendo apenas as linhas que satisfazem as suas condições.\n",
|
|
"\n",
|
|
"- `dplyr::mutate()`: ajuda a criar ou modificar colunas.\n",
|
|
"\n",
|
|
"Confira este [tutorial *artístico* learnr](https://allisonhorst.shinyapps.io/dplyr-learnr/#section-welcome) de Allison Horst, que introduz algumas funções úteis de manipulação de dados no dplyr *(parte do Tidyverse)*.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "K3RF5bSCHC76"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Creates a functions that returns the top ingredients by class\r\n",
|
|
"\r\n",
|
|
"create_ingredient <- function(df){\r\n",
|
|
" \r\n",
|
|
" # Drop the id column which is the first colum\r\n",
|
|
" ingredient_df = df %>% select(-1) %>% \r\n",
|
|
" # Transpose data to a long format\r\n",
|
|
" pivot_longer(!cuisine, names_to = \"ingredients\", values_to = \"count\") %>% \r\n",
|
|
" # Find the top most ingredients for a particular cuisine\r\n",
|
|
" group_by(ingredients) %>% \r\n",
|
|
" summarise(n_instances = sum(count)) %>% \r\n",
|
|
" filter(n_instances != 0) %>% \r\n",
|
|
" # Arrange by descending order\r\n",
|
|
" arrange(desc(n_instances)) %>% \r\n",
|
|
" mutate(ingredients = factor(ingredients) %>% fct_inorder())\r\n",
|
|
" \r\n",
|
|
" \r\n",
|
|
" return(ingredient_df)\r\n",
|
|
"} # End of function"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "uB_0JR82HTPa"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Agora podemos usar a função para obter uma ideia dos dez ingredientes mais populares por cozinha. Vamos testá-la com `thai_df`.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "h9794WF8HWmc"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Call create_ingredient and display popular ingredients\r\n",
|
|
"thai_ingredient_df <- create_ingredient(df = thai_df)\r\n",
|
|
"\r\n",
|
|
"thai_ingredient_df %>% \r\n",
|
|
" slice_head(n = 10)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "agQ-1HrcHaEA"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Na seção anterior, utilizámos `geom_col()`, vamos ver como pode usar `geom_bar` também, para criar gráficos de barras. Use `?geom_bar` para leitura adicional.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "kHu9ffGjHdcX"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Make a bar chart for popular thai cuisines\r\n",
|
|
"thai_ingredient_df %>% \r\n",
|
|
" slice_head(n = 10) %>% \r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"steelblue\") +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "fb3Bx_3DHj6e"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [],
|
|
"metadata": {
|
|
"id": "RHP_xgdkHnvM"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Japanese cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = japanese_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"darkorange\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "019v8F0XHrRU"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"E quanto às cozinhas chinesas?\n"
|
|
],
|
|
"metadata": {
|
|
"id": "iIGM7vO8Hu3v"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Chinese cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = chinese_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"cyan4\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "lHd9_gd2HyzU"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [],
|
|
"metadata": {
|
|
"id": "ir8qyQbNH1c7"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Indian cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = indian_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#041E42FF\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "ApukQtKjH5FO"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [],
|
|
"metadata": {
|
|
"id": "qv30cwY1H-FM"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Get popular ingredients for Korean cuisines and make bar chart\r\n",
|
|
"create_ingredient(df = korean_df) %>% \r\n",
|
|
" slice_head(n = 10) %>%\r\n",
|
|
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
|
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#852419FF\", alpha = 0.8) +\r\n",
|
|
" xlab(\"\") + ylab(\"\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "lumgk9cHIBie"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"A partir das visualizações de dados, podemos agora eliminar os ingredientes mais comuns que geram confusão entre diferentes cozinhas, utilizando `dplyr::select()`.\n",
|
|
"\n",
|
|
"Toda a gente adora arroz, alho e gengibre!\n"
|
|
],
|
|
"metadata": {
|
|
"id": "iO4veMXuIEta"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Drop id column, rice, garlic and ginger from our original data set\r\n",
|
|
"df_select <- df %>% \r\n",
|
|
" select(-c(1, rice, garlic, ginger))\r\n",
|
|
"\r\n",
|
|
"# Display new data set\r\n",
|
|
"df_select %>% \r\n",
|
|
" slice_head(n = 5)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "iHJPiG6rIUcK"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## Pré-processamento de dados usando receitas 👩🍳👨🍳 - Lidando com dados desequilibrados ⚖️\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/recipes.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Ilustração por @allison_horst</figcaption>\n",
|
|
"\n",
|
|
"Dado que esta lição é sobre culinárias, temos de colocar `recipes` em contexto.\n",
|
|
"\n",
|
|
"O Tidymodels oferece mais um pacote interessante: `recipes` - um pacote para pré-processamento de dados.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "kkFd-JxdIaL6"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Vamos dar uma olhada novamente na distribuição das nossas culinárias.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "6l2ubtTPJAhY"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Distribution of cuisines\r\n",
|
|
"old_label_count <- df_select %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(desc(n))\r\n",
|
|
"\r\n",
|
|
"old_label_count"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "1e-E9cb7JDVi"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Como pode ver, há uma distribuição bastante desigual no número de cozinhas. As cozinhas coreanas são quase 3 vezes mais numerosas do que as tailandesas. Dados desequilibrados frequentemente têm efeitos negativos no desempenho do modelo. Pense numa classificação binária. Se a maior parte dos seus dados pertence a uma classe, um modelo de ML vai prever essa classe com mais frequência, simplesmente porque há mais dados disponíveis para ela. Equilibrar os dados corrige qualquer desvio e ajuda a eliminar esse desequilíbrio. Muitos modelos têm o melhor desempenho quando o número de observações é igual e, por isso, tendem a ter dificuldades com dados desequilibrados.\n",
|
|
"\n",
|
|
"Existem principalmente duas formas de lidar com conjuntos de dados desequilibrados:\n",
|
|
"\n",
|
|
"- adicionar observações à classe minoritária: `Over-sampling`, por exemplo, utilizando um algoritmo SMOTE\n",
|
|
"\n",
|
|
"- remover observações da classe maioritária: `Under-sampling`\n",
|
|
"\n",
|
|
"Vamos agora demonstrar como lidar com conjuntos de dados desequilibrados utilizando uma `recipe`. Uma recipe pode ser vista como um plano que descreve quais passos devem ser aplicados a um conjunto de dados para prepará-lo para análise de dados.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "soAw6826JKx9"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Load themis package for dealing with imbalanced data\r\n",
|
|
"library(themis)\r\n",
|
|
"\r\n",
|
|
"# Create a recipe for preprocessing data\r\n",
|
|
"cuisines_recipe <- recipe(cuisine ~ ., data = df_select) %>% \r\n",
|
|
" step_smote(cuisine)\r\n",
|
|
"\r\n",
|
|
"cuisines_recipe"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "HS41brUIJVJy"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Vamos analisar os nossos passos de pré-processamento.\n",
|
|
"\n",
|
|
"- A chamada para `recipe()` com uma fórmula indica à receita os *papéis* das variáveis usando os dados de `df_select` como referência. Por exemplo, a coluna `cuisine` foi atribuída ao papel de `outcome`, enquanto as restantes colunas foram atribuídas ao papel de `predictor`.\n",
|
|
"\n",
|
|
"- [`step_smote(cuisine)`](https://themis.tidymodels.org/reference/step_smote.html) cria uma *especificação* de um passo da receita que gera sinteticamente novos exemplos da classe minoritária utilizando os vizinhos mais próximos desses casos.\n",
|
|
"\n",
|
|
"Agora, se quisermos ver os dados pré-processados, teremos de [**`prep()`**](https://recipes.tidymodels.org/reference/prep.html) e [**`bake()`**](https://recipes.tidymodels.org/reference/bake.html) a nossa receita.\n",
|
|
"\n",
|
|
"`prep()`: estima os parâmetros necessários a partir de um conjunto de treino que podem ser posteriormente aplicados a outros conjuntos de dados.\n",
|
|
"\n",
|
|
"`bake()`: aplica uma receita preparada às operações em qualquer conjunto de dados.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "Yb-7t7XcJaC8"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Prep and bake the recipe\r\n",
|
|
"preprocessed_df <- cuisines_recipe %>% \r\n",
|
|
" prep() %>% \r\n",
|
|
" bake(new_data = NULL) %>% \r\n",
|
|
" relocate(cuisine)\r\n",
|
|
"\r\n",
|
|
"# Display data\r\n",
|
|
"preprocessed_df %>% \r\n",
|
|
" slice_head(n = 5)\r\n",
|
|
"\r\n",
|
|
"# Quick summary stats\r\n",
|
|
"preprocessed_df %>% \r\n",
|
|
" introduce()"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "9QhSgdpxJl44"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Vamos agora verificar a distribuição das nossas culinárias e compará-las com os dados desequilibrados.\n"
|
|
],
|
|
"metadata": {
|
|
"id": "dmidELh_LdV7"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Distribution of cuisines\r\n",
|
|
"new_label_count <- preprocessed_df %>% \r\n",
|
|
" count(cuisine) %>% \r\n",
|
|
" arrange(desc(n))\r\n",
|
|
"\r\n",
|
|
"list(new_label_count = new_label_count,\r\n",
|
|
" old_label_count = old_label_count)"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "aSh23klBLwDz"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Yum! Os dados estão limpos, equilibrados e muito deliciosos 😋!\n",
|
|
"\n",
|
|
"> Normalmente, uma receita é usada como um pré-processador para modelagem, onde define quais passos devem ser aplicados a um conjunto de dados para prepará-lo para a modelagem. Nesse caso, um `workflow()` é geralmente utilizado (como já vimos nas nossas lições anteriores) em vez de estimar manualmente uma receita.\n",
|
|
">\n",
|
|
"> Assim, normalmente não é necessário **`prep()`** e **`bake()`** receitas quando se utiliza tidymodels, mas estas são funções úteis para ter na sua caixa de ferramentas para confirmar que as receitas estão a fazer o que espera, como no nosso caso.\n",
|
|
">\n",
|
|
"> Quando se **`bake()`** uma receita preparada com **`new_data = NULL`**, obtém-se de volta os dados que foram fornecidos ao definir a receita, mas que passaram pelos passos de pré-processamento.\n",
|
|
"\n",
|
|
"Vamos agora guardar uma cópia destes dados para usar em lições futuras:\n"
|
|
],
|
|
"metadata": {
|
|
"id": "HEu80HZ8L7ae"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Save preprocessed data\r\n",
|
|
"write_csv(preprocessed_df, \"../../../data/cleaned_cuisines_R.csv\")"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {
|
|
"id": "cBmCbIgrMOI6"
|
|
}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Este novo CSV pode agora ser encontrado na pasta raiz de dados.\n",
|
|
"\n",
|
|
"**🚀Desafio**\n",
|
|
"\n",
|
|
"Este currículo contém vários conjuntos de dados interessantes. Explore as pastas `data` e veja se alguma contém conjuntos de dados que seriam apropriados para classificação binária ou multi-classe. Que perguntas faria sobre este conjunto de dados?\n",
|
|
"\n",
|
|
"## [**Questionário pós-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/20/)\n",
|
|
"\n",
|
|
"## **Revisão & Estudo Individual**\n",
|
|
"\n",
|
|
"- Veja o [pacote themis](https://github.com/tidymodels/themis). Que outras técnicas poderíamos usar para lidar com dados desbalanceados?\n",
|
|
"\n",
|
|
"- Site de referência dos [modelos tidy](https://www.tidymodels.org/start/).\n",
|
|
"\n",
|
|
"- H. Wickham e G. Grolemund, [*R for Data Science: Visualize, Model, Transform, Tidy, and Import Data*](https://r4ds.had.co.nz/).\n",
|
|
"\n",
|
|
"#### OBRIGADO A:\n",
|
|
"\n",
|
|
"[`Allison Horst`](https://twitter.com/allison_horst/) 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",
|
|
"\n",
|
|
"[Cassie Breviu](https://www.twitter.com/cassieview) e [Jen Looper](https://www.twitter.com/jenlooper) por criarem a versão original em Python deste módulo ♥️\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Arte por @allison_horst</figcaption>\n"
|
|
],
|
|
"metadata": {
|
|
"id": "WQs5621pMGwf"
|
|
}
|
|
},
|
|
{
|
|
"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, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. 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 incorretas decorrentes da utilização desta tradução.\n"
|
|
]
|
|
}
|
|
]
|
|
} |