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.
650 lines
26 KiB
650 lines
26 KiB
{
|
|
"nbformat": 4,
|
|
"nbformat_minor": 0,
|
|
"metadata": {
|
|
"colab": {
|
|
"name": "lesson_12-R.ipynb",
|
|
"provenance": [],
|
|
"collapsed_sections": []
|
|
},
|
|
"kernelspec": {
|
|
"name": "ir",
|
|
"display_name": "R"
|
|
},
|
|
"language_info": {
|
|
"name": "R"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "fab50046ca413a38939d579f8432274f",
|
|
"translation_date": "2025-09-03T20:30:42+00:00",
|
|
"source_file": "4-Classification/3-Classifiers-2/solution/R/lesson_12-R.ipynb",
|
|
"language_code": "pt"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "jsFutf_ygqSx"
|
|
},
|
|
"source": [
|
|
"# Construir um modelo de classificação: Deliciosas Cozinhas Asiáticas e Indianas\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "HD54bEefgtNO"
|
|
},
|
|
"source": [
|
|
"## Classificadores de culinária 2\n",
|
|
"\n",
|
|
"Nesta segunda lição sobre classificação, vamos explorar `mais formas` de classificar dados categóricos. Também aprenderemos sobre as implicações de escolher um classificador em vez de outro.\n",
|
|
"\n",
|
|
"### [**Questionário pré-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/23/)\n",
|
|
"\n",
|
|
"### **Pré-requisitos**\n",
|
|
"\n",
|
|
"Assumimos que você completou as lições anteriores, já que vamos utilizar alguns conceitos aprendidos anteriormente.\n",
|
|
"\n",
|
|
"Para esta lição, 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 aprendizagem de máquina.\n",
|
|
"\n",
|
|
"- `themis`: O [pacote themis](https://themis.tidymodels.org/) fornece passos extras de receitas para lidar com dados desbalanceados.\n",
|
|
"\n",
|
|
"Você pode instalá-los com o seguinte comando:\n",
|
|
"\n",
|
|
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"kernlab\", \"themis\", \"ranger\", \"xgboost\", \"kknn\"))`\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",
|
|
"metadata": {
|
|
"id": "vZ57IuUxgyQt"
|
|
},
|
|
"source": [
|
|
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n",
|
|
"\n",
|
|
"pacman::p_load(tidyverse, tidymodels, themis, kernlab, ranger, xgboost, kknn)"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "z22M-pj4g07x"
|
|
},
|
|
"source": [
|
|
"## **1. Um mapa de classificação**\n",
|
|
"\n",
|
|
"Na nossa [lição anterior](https://github.com/microsoft/ML-For-Beginners/tree/main/4-Classification/2-Classifiers-1), tentámos responder à pergunta: como escolher entre vários modelos? Em grande parte, isso depende das características dos dados e do tipo de problema que queremos resolver (por exemplo, classificação ou regressão?).\n",
|
|
"\n",
|
|
"Anteriormente, aprendemos sobre as várias opções disponíveis para classificar dados utilizando o guia da Microsoft. O framework de Machine Learning em Python, Scikit-learn, oferece um guia semelhante, mas mais detalhado, que pode ajudar ainda mais a restringir os seus estimadores (outro termo para classificadores):\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/map.png\"\n",
|
|
" width=\"700\"/>\n",
|
|
" <figcaption></figcaption>\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "u1i3xRIVg7vG"
|
|
},
|
|
"source": [
|
|
"> Dica: [visite este mapa online](https://scikit-learn.org/stable/tutorial/machine_learning_map/) e clique ao longo do caminho para ler a documentação.\n",
|
|
">\n",
|
|
"> O [site de referência do Tidymodels](https://www.tidymodels.org/find/parsnip/#models) também oferece uma excelente documentação sobre diferentes tipos de modelos.\n",
|
|
"\n",
|
|
"### **O plano** 🗺️\n",
|
|
"\n",
|
|
"Este mapa é muito útil quando se tem uma compreensão clara dos seus dados, pois pode 'percorrer' os seus caminhos até chegar a uma decisão:\n",
|
|
"\n",
|
|
"- Temos \\>50 amostras\n",
|
|
"\n",
|
|
"- Queremos prever uma categoria\n",
|
|
"\n",
|
|
"- Temos dados rotulados\n",
|
|
"\n",
|
|
"- Temos menos de 100K amostras\n",
|
|
"\n",
|
|
"- ✨ Podemos escolher um Linear SVC\n",
|
|
"\n",
|
|
"- Se isso não funcionar, como temos dados numéricos\n",
|
|
"\n",
|
|
" - Podemos tentar um ✨ KNeighbors Classifier\n",
|
|
"\n",
|
|
" - Se isso não funcionar, tentar ✨ SVC e ✨ Ensemble Classifiers\n",
|
|
"\n",
|
|
"Este é um caminho muito útil para seguir. Agora, vamos direto ao assunto utilizando o framework de modelagem [tidymodels](https://www.tidymodels.org/): uma coleção consistente e flexível de pacotes R desenvolvidos para incentivar boas práticas estatísticas 😊.\n",
|
|
"\n",
|
|
"## 2. Dividir os dados e lidar com conjuntos de dados desequilibrados.\n",
|
|
"\n",
|
|
"Nas nossas lições anteriores, aprendemos que havia um conjunto de ingredientes comuns entre as nossas cozinhas. Além disso, havia uma distribuição bastante desigual no número de cozinhas.\n",
|
|
"\n",
|
|
"Vamos lidar com isso da seguinte forma:\n",
|
|
"\n",
|
|
"- Eliminando os ingredientes mais comuns que criam confusão entre cozinhas distintas, usando `dplyr::select()`.\n",
|
|
"\n",
|
|
"- Utilizando uma `recipe` que pré-processa os dados para prepará-los para a modelagem, aplicando um algoritmo de `over-sampling`.\n",
|
|
"\n",
|
|
"Já vimos isso na lição anterior, então deve ser tranquilo 🥳!\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "6tj_rN00hClA"
|
|
},
|
|
"source": [
|
|
"# Load the core Tidyverse and Tidymodels packages\n",
|
|
"library(tidyverse)\n",
|
|
"library(tidymodels)\n",
|
|
"\n",
|
|
"# Load the original cuisines data\n",
|
|
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv\")\n",
|
|
"\n",
|
|
"# Drop id column, rice, garlic and ginger from our original data set\n",
|
|
"df_select <- df %>% \n",
|
|
" select(-c(1, rice, garlic, ginger)) %>%\n",
|
|
" # Encode cuisine column as categorical\n",
|
|
" mutate(cuisine = factor(cuisine))\n",
|
|
"\n",
|
|
"\n",
|
|
"# Create data split specification\n",
|
|
"set.seed(2056)\n",
|
|
"cuisines_split <- initial_split(data = df_select,\n",
|
|
" strata = cuisine,\n",
|
|
" prop = 0.7)\n",
|
|
"\n",
|
|
"# Extract the data in each split\n",
|
|
"cuisines_train <- training(cuisines_split)\n",
|
|
"cuisines_test <- testing(cuisines_split)\n",
|
|
"\n",
|
|
"# Display distribution of cuisines in the training set\n",
|
|
"cuisines_train %>% \n",
|
|
" count(cuisine) %>% \n",
|
|
" arrange(desc(n))"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "zFin5yw3hHb1"
|
|
},
|
|
"source": [
|
|
"### Lidar com dados desequilibrados\n",
|
|
"\n",
|
|
"Dados desequilibrados frequentemente têm efeitos negativos no desempenho do modelo. Muitos modelos funcionam melhor 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 que gera novos exemplos sintéticos da classe minoritária com base nos vizinhos mais próximos desses casos.\n",
|
|
"\n",
|
|
"- remover observações da classe majoritária: `Under-sampling`\n",
|
|
"\n",
|
|
"Na nossa lição anterior, demonstrámos 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. No nosso caso, queremos ter uma distribuição igual no número de nossas cozinhas para o nosso `training set`. Vamos começar!\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "cRzTnHolhLWd"
|
|
},
|
|
"source": [
|
|
"# Load themis package for dealing with imbalanced data\n",
|
|
"library(themis)\n",
|
|
"\n",
|
|
"# Create a recipe for preprocessing training data\n",
|
|
"cuisines_recipe <- recipe(cuisine ~ ., data = cuisines_train) %>%\n",
|
|
" step_smote(cuisine) \n",
|
|
"\n",
|
|
"# Print recipe\n",
|
|
"cuisines_recipe"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "KxOQ2ORhhO81"
|
|
},
|
|
"source": [
|
|
"Agora estamos prontos para treinar modelos 👩💻👨💻!\n",
|
|
"\n",
|
|
"## 3. Para além dos modelos de regressão multinomial\n",
|
|
"\n",
|
|
"Na nossa lição anterior, analisámos os modelos de regressão multinomial. Vamos explorar alguns modelos mais flexíveis para classificação.\n",
|
|
"\n",
|
|
"### Máquinas de Vetores de Suporte\n",
|
|
"\n",
|
|
"No contexto de classificação, `Máquinas de Vetores de Suporte` são uma técnica de aprendizagem automática que tenta encontrar um *hiperplano* que \"melhor\" separa as classes. Vamos observar um exemplo simples:\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/svm.png\"\n",
|
|
" width=\"300\"/>\n",
|
|
" <figcaption>https://commons.wikimedia.org/w/index.php?curid=22877598</figcaption>\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "C4Wsd0vZhXYu"
|
|
},
|
|
"source": [
|
|
"H1~ não separa as classes. H2~ separa, mas apenas com uma margem pequena. H3~ separa-as com a margem máxima.\n",
|
|
"\n",
|
|
"#### Classificador Linear de Vetores de Suporte\n",
|
|
"\n",
|
|
"O clustering de Vetores de Suporte (SVC) é uma técnica derivada da família de máquinas de Vetores de Suporte (SVM) em Aprendizagem Automática. No SVC, o hiperplano é escolhido para separar corretamente `a maioria` das observações de treino, mas `pode classificar incorretamente` algumas observações. Ao permitir que alguns pontos fiquem do lado errado, o SVM torna-se mais robusto a outliers, proporcionando assim uma melhor generalização para novos dados. O parâmetro que regula esta violação é chamado de `cost`, que tem um valor padrão de 1 (consulte `help(\"svm_poly\")`).\n",
|
|
"\n",
|
|
"Vamos criar um SVC linear definindo `degree = 1` num modelo SVM polinomial.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "vJpp6nuChlBz"
|
|
},
|
|
"source": [
|
|
"# Make a linear SVC specification\n",
|
|
"svc_linear_spec <- svm_poly(degree = 1) %>% \n",
|
|
" set_engine(\"kernlab\") %>% \n",
|
|
" set_mode(\"classification\")\n",
|
|
"\n",
|
|
"# Bundle specification and recipe into a worklow\n",
|
|
"svc_linear_wf <- workflow() %>% \n",
|
|
" add_recipe(cuisines_recipe) %>% \n",
|
|
" add_model(svc_linear_spec)\n",
|
|
"\n",
|
|
"# Print out workflow\n",
|
|
"svc_linear_wf"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "rDs8cWNkhoqu"
|
|
},
|
|
"source": [
|
|
"Agora que capturámos os passos de pré-processamento e a especificação do modelo num *workflow*, podemos avançar e treinar o SVC linear, avaliando os resultados ao mesmo tempo. Para métricas de desempenho, vamos criar um conjunto de métricas que avalie: `accuracy`, `sensitivity`, `Positive Predicted Value` e `F Measure`.\n",
|
|
"\n",
|
|
"> `augment()` irá adicionar coluna(s) com as previsões aos dados fornecidos.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "81wiqcwuhrnq"
|
|
},
|
|
"source": [
|
|
"# Train a linear SVC model\n",
|
|
"svc_linear_fit <- svc_linear_wf %>% \n",
|
|
" fit(data = cuisines_train)\n",
|
|
"\n",
|
|
"# Create a metric set\n",
|
|
"eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)\n",
|
|
"\n",
|
|
"\n",
|
|
"# Make predictions and Evaluate model performance\n",
|
|
"svc_linear_fit %>% \n",
|
|
" augment(new_data = cuisines_test) %>% \n",
|
|
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "0UFQvHf-huo3"
|
|
},
|
|
"source": [
|
|
"#### Máquina de Vetores de Suporte\n",
|
|
"\n",
|
|
"A máquina de vetores de suporte (SVM) é uma extensão do classificador de vetores de suporte para acomodar uma fronteira não linear entre as classes. Essencialmente, as SVMs utilizam o *truque do kernel* para ampliar o espaço de características e assim se adaptar a relações não lineares entre as classes. Uma função kernel popular e extremamente flexível usada pelas SVMs é a *função de base radial.* Vamos ver como ela se comporta com os nossos dados.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "-KX4S8mzhzmp"
|
|
},
|
|
"source": [
|
|
"set.seed(2056)\n",
|
|
"\n",
|
|
"# Make an RBF SVM specification\n",
|
|
"svm_rbf_spec <- svm_rbf() %>% \n",
|
|
" set_engine(\"kernlab\") %>% \n",
|
|
" set_mode(\"classification\")\n",
|
|
"\n",
|
|
"# Bundle specification and recipe into a worklow\n",
|
|
"svm_rbf_wf <- workflow() %>% \n",
|
|
" add_recipe(cuisines_recipe) %>% \n",
|
|
" add_model(svm_rbf_spec)\n",
|
|
"\n",
|
|
"\n",
|
|
"# Train an RBF model\n",
|
|
"svm_rbf_fit <- svm_rbf_wf %>% \n",
|
|
" fit(data = cuisines_train)\n",
|
|
"\n",
|
|
"\n",
|
|
"# Make predictions and Evaluate model performance\n",
|
|
"svm_rbf_fit %>% \n",
|
|
" augment(new_data = cuisines_test) %>% \n",
|
|
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "QBFSa7WSh4HQ"
|
|
},
|
|
"source": [
|
|
"Muito melhor 🤩!\n",
|
|
"\n",
|
|
"> ✅ Por favor veja:\n",
|
|
">\n",
|
|
"> - [*Support Vector Machines*](https://bradleyboehmke.github.io/HOML/svm.html), Hands-on Machine Learning with R\n",
|
|
">\n",
|
|
"> - [*Support Vector Machines*](https://www.statlearning.com/), An Introduction to Statistical Learning with Applications in R\n",
|
|
">\n",
|
|
"> para leitura adicional.\n",
|
|
"\n",
|
|
"### Classificadores de Vizinhos Mais Próximos\n",
|
|
"\n",
|
|
"O algoritmo *K*-nearest neighbor (KNN) prevê cada observação com base na sua *semelhança* com outras observações.\n",
|
|
"\n",
|
|
"Vamos ajustar um ao nosso conjunto de dados.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "k4BxxBcdh9Ka"
|
|
},
|
|
"source": [
|
|
"# Make a KNN specification\n",
|
|
"knn_spec <- nearest_neighbor() %>% \n",
|
|
" set_engine(\"kknn\") %>% \n",
|
|
" set_mode(\"classification\")\n",
|
|
"\n",
|
|
"# Bundle recipe and model specification into a workflow\n",
|
|
"knn_wf <- workflow() %>% \n",
|
|
" add_recipe(cuisines_recipe) %>% \n",
|
|
" add_model(knn_spec)\n",
|
|
"\n",
|
|
"# Train a boosted tree model\n",
|
|
"knn_wf_fit <- knn_wf %>% \n",
|
|
" fit(data = cuisines_train)\n",
|
|
"\n",
|
|
"\n",
|
|
"# Make predictions and Evaluate model performance\n",
|
|
"knn_wf_fit %>% \n",
|
|
" augment(new_data = cuisines_test) %>% \n",
|
|
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "HaegQseriAcj"
|
|
},
|
|
"source": [
|
|
"Parece que este modelo não está a ter um desempenho muito bom. Provavelmente, alterar os argumentos do modelo (ver `help(\"nearest_neighbor\")`) irá melhorar o desempenho do modelo. Certifique-se de experimentar.\n",
|
|
"\n",
|
|
"> ✅ Por favor veja:\n",
|
|
">\n",
|
|
"> - [Hands-on Machine Learning with R](https://bradleyboehmke.github.io/HOML/)\n",
|
|
">\n",
|
|
"> - [An Introduction to Statistical Learning with Applications in R](https://www.statlearning.com/)\n",
|
|
">\n",
|
|
"> para aprender mais sobre classificadores *K*-Nearest Neighbors.\n",
|
|
"\n",
|
|
"### Classificadores em ensemble\n",
|
|
"\n",
|
|
"Os algoritmos de ensemble funcionam combinando múltiplos estimadores base para produzir um modelo otimizado, seja através de:\n",
|
|
"\n",
|
|
"`bagging`: aplicação de uma *função de média* a uma coleção de modelos base\n",
|
|
"\n",
|
|
"`boosting`: construção de uma sequência de modelos que se complementam para melhorar o desempenho preditivo.\n",
|
|
"\n",
|
|
"Vamos começar por experimentar um modelo Random Forest, que constrói uma grande coleção de árvores de decisão e depois aplica uma função de média para obter um modelo geral melhor.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "49DPoVs6iK1M"
|
|
},
|
|
"source": [
|
|
"# Make a random forest specification\n",
|
|
"rf_spec <- rand_forest() %>% \n",
|
|
" set_engine(\"ranger\") %>% \n",
|
|
" set_mode(\"classification\")\n",
|
|
"\n",
|
|
"# Bundle recipe and model specification into a workflow\n",
|
|
"rf_wf <- workflow() %>% \n",
|
|
" add_recipe(cuisines_recipe) %>% \n",
|
|
" add_model(rf_spec)\n",
|
|
"\n",
|
|
"# Train a random forest model\n",
|
|
"rf_wf_fit <- rf_wf %>% \n",
|
|
" fit(data = cuisines_train)\n",
|
|
"\n",
|
|
"\n",
|
|
"# Make predictions and Evaluate model performance\n",
|
|
"rf_wf_fit %>% \n",
|
|
" augment(new_data = cuisines_test) %>% \n",
|
|
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "RGVYwC_aiUWc"
|
|
},
|
|
"source": [
|
|
"Bom trabalho 👏!\n",
|
|
"\n",
|
|
"Vamos também experimentar com um modelo de Árvore Reforçada.\n",
|
|
"\n",
|
|
"Árvore Reforçada define um método de conjunto que cria uma série de árvores de decisão sequenciais, onde cada árvore depende dos resultados das árvores anteriores, numa tentativa de reduzir o erro de forma incremental. Este método foca-se nos pesos dos itens classificados incorretamente e ajusta o modelo do próximo classificador para corrigir.\n",
|
|
"\n",
|
|
"Existem diferentes formas de ajustar este modelo (veja `help(\"boost_tree\")`). Neste exemplo, vamos ajustar Árvores Reforçadas através do motor `xgboost`.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "Py1YWo-micWs"
|
|
},
|
|
"source": [
|
|
"# Make a boosted tree specification\n",
|
|
"boost_spec <- boost_tree(trees = 200) %>% \n",
|
|
" set_engine(\"xgboost\") %>% \n",
|
|
" set_mode(\"classification\")\n",
|
|
"\n",
|
|
"# Bundle recipe and model specification into a workflow\n",
|
|
"boost_wf <- workflow() %>% \n",
|
|
" add_recipe(cuisines_recipe) %>% \n",
|
|
" add_model(boost_spec)\n",
|
|
"\n",
|
|
"# Train a boosted tree model\n",
|
|
"boost_wf_fit <- boost_wf %>% \n",
|
|
" fit(data = cuisines_train)\n",
|
|
"\n",
|
|
"\n",
|
|
"# Make predictions and Evaluate model performance\n",
|
|
"boost_wf_fit %>% \n",
|
|
" augment(new_data = cuisines_test) %>% \n",
|
|
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "zNQnbuejigZM"
|
|
},
|
|
"source": [
|
|
"> ✅ Por favor veja:\n",
|
|
">\n",
|
|
"> - [Machine Learning for Social Scientists](https://cimentadaj.github.io/ml_socsci/tree-based-methods.html#random-forests)\n",
|
|
">\n",
|
|
"> - [Hands-on Machine Learning with R](https://bradleyboehmke.github.io/HOML/)\n",
|
|
">\n",
|
|
"> - [An Introduction to Statistical Learning with Applications in R](https://www.statlearning.com/)\n",
|
|
">\n",
|
|
"> - <https://algotech.netlify.app/blog/xgboost/> - Explora o modelo AdaBoost, que é uma boa alternativa ao xgboost.\n",
|
|
">\n",
|
|
"> para aprender mais sobre classificadores Ensemble.\n",
|
|
"\n",
|
|
"## 4. Extra - comparando múltiplos modelos\n",
|
|
"\n",
|
|
"Testámos vários modelos neste laboratório 🙌. Pode tornar-se cansativo ou trabalhoso criar muitos fluxos de trabalho a partir de diferentes conjuntos de pré-processadores e/ou especificações de modelos e depois calcular as métricas de desempenho uma a uma.\n",
|
|
"\n",
|
|
"Vamos ver se conseguimos resolver isso criando uma função que ajusta uma lista de fluxos de trabalho no conjunto de treino e depois retorna as métricas de desempenho com base no conjunto de teste. Vamos usar `map()` e `map_dfr()` do pacote [purrr](https://purrr.tidyverse.org/) para aplicar funções a cada elemento de uma lista.\n",
|
|
"\n",
|
|
"> As funções [`map()`](https://purrr.tidyverse.org/reference/map.html) permitem substituir muitos ciclos \"for\" por código que é mais conciso e mais fácil de ler. O melhor lugar para aprender sobre as funções [`map()`](https://purrr.tidyverse.org/reference/map.html) é o [capítulo de iteração](http://r4ds.had.co.nz/iteration.html) em R for Data Science.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "Qzb7LyZnimd2"
|
|
},
|
|
"source": [
|
|
"set.seed(2056)\n",
|
|
"\n",
|
|
"# Create a metric set\n",
|
|
"eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)\n",
|
|
"\n",
|
|
"# Define a function that returns performance metrics\n",
|
|
"compare_models <- function(workflow_list, train_set, test_set){\n",
|
|
" \n",
|
|
" suppressWarnings(\n",
|
|
" # Fit each model to the train_set\n",
|
|
" map(workflow_list, fit, data = train_set) %>% \n",
|
|
" # Make predictions on the test set\n",
|
|
" map_dfr(augment, new_data = test_set, .id = \"model\") %>%\n",
|
|
" # Select desired columns\n",
|
|
" select(model, cuisine, .pred_class) %>% \n",
|
|
" # Evaluate model performance\n",
|
|
" group_by(model) %>% \n",
|
|
" eval_metrics(truth = cuisine, estimate = .pred_class) %>% \n",
|
|
" ungroup()\n",
|
|
" )\n",
|
|
" \n",
|
|
"} # End of function"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "Fwa712sNisDA"
|
|
},
|
|
"source": []
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "3i4VJOi2iu-a"
|
|
},
|
|
"source": [
|
|
"# Make a list of workflows\n",
|
|
"workflow_list <- list(\n",
|
|
" \"svc\" = svc_linear_wf,\n",
|
|
" \"svm\" = svm_rbf_wf,\n",
|
|
" \"knn\" = knn_wf,\n",
|
|
" \"random_forest\" = rf_wf,\n",
|
|
" \"xgboost\" = boost_wf)\n",
|
|
"\n",
|
|
"# Call the function\n",
|
|
"set.seed(2056)\n",
|
|
"perf_metrics <- compare_models(workflow_list = workflow_list, train_set = cuisines_train, test_set = cuisines_test)\n",
|
|
"\n",
|
|
"# Print out performance metrics\n",
|
|
"perf_metrics %>% \n",
|
|
" group_by(.metric) %>% \n",
|
|
" arrange(desc(.estimate)) %>% \n",
|
|
" slice_head(n=7)\n",
|
|
"\n",
|
|
"# Compare accuracy\n",
|
|
"perf_metrics %>% \n",
|
|
" filter(.metric == \"accuracy\") %>% \n",
|
|
" arrange(desc(.estimate))\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "KuWK_lEli4nW"
|
|
},
|
|
"source": [
|
|
"O pacote [**workflowset**](https://workflowsets.tidymodels.org/) permite aos utilizadores criar e ajustar facilmente um grande número de modelos, mas foi principalmente concebido para funcionar com técnicas de reamostragem, como a `validação cruzada`, uma abordagem que ainda iremos abordar.\n",
|
|
"\n",
|
|
"## **🚀Desafio**\n",
|
|
"\n",
|
|
"Cada uma destas técnicas tem um grande número de parâmetros que podem ser ajustados, como por exemplo `cost` em SVMs, `neighbors` em KNN, `mtry` (Preditores Selecionados Aleatoriamente) em Random Forest.\n",
|
|
"\n",
|
|
"Pesquise os parâmetros padrão de cada técnica e reflita sobre o que ajustar esses parâmetros significaria para a qualidade do modelo.\n",
|
|
"\n",
|
|
"Para saber mais sobre um modelo específico e os seus parâmetros, utilize: `help(\"model\")`, por exemplo, `help(\"rand_forest\")`.\n",
|
|
"\n",
|
|
"> Na prática, geralmente *estimamos* os *melhores valores* para estes parâmetros treinando vários modelos num `conjunto de dados simulado` e medindo o desempenho de todos esses modelos. Este processo é chamado de **otimização**.\n",
|
|
"\n",
|
|
"### [**Questionário pós-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/24/)\n",
|
|
"\n",
|
|
"### **Revisão & Estudo Individual**\n",
|
|
"\n",
|
|
"Há muito jargão nestas lições, por isso reserve um momento para rever [esta lista](https://docs.microsoft.com/dotnet/machine-learning/resources/glossary?WT.mc_id=academic-77952-leestott) de terminologia útil!\n",
|
|
"\n",
|
|
"#### AGRADECIMENTOS 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 deste módulo em Python ♥️\n",
|
|
"\n",
|
|
"Boas aprendizagens,\n",
|
|
"\n",
|
|
"[Eric](https://twitter.com/ericntay), Embaixador Estudante Gold da Microsoft Learn.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
|
" width=\"569\"/>\n",
|
|
" <figcaption>Arte por @allison_horst</figcaption>\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, é importante ter em conta 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"
|
|
]
|
|
}
|
|
]
|
|
} |