{ "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-09-04T01:06:43+00:00", "source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb", "language_code": "fr" } }, "cells": [ { "cell_type": "markdown", "source": [], "metadata": { "id": "EgQw8osnsUV-" } }, { "cell_type": "markdown", "source": [ "## Régression linéaire et polynomiale pour le prix des citrouilles - Leçon 3\n", "

\n", " \n", "

Infographie par Dasani Madipalli
\n", "\n", "\n", "#### Introduction\n", "\n", "Jusqu'à présent, vous avez exploré ce qu'est la régression avec des données d'exemple issues du jeu de données sur les prix des citrouilles que nous utiliserons tout au long de cette leçon. Vous l'avez également visualisée en utilisant `ggplot2`. 💪\n", "\n", "Vous êtes maintenant prêt à approfondir la régression pour l'apprentissage automatique. Dans cette leçon, vous allez en apprendre davantage sur deux types de régression : *la régression linéaire de base* et *la régression polynomiale*, ainsi que sur certaines notions mathématiques sous-jacentes à ces techniques.\n", "\n", "> Tout au long de ce programme, nous supposons une connaissance minimale des mathématiques et cherchons à les rendre accessibles aux étudiants venant d'autres domaines. Soyez attentif aux notes, 🧮 aux encadrés, aux diagrammes et à d'autres outils pédagogiques pour faciliter la compréhension.\n", "\n", "#### Préparation\n", "\n", "Pour rappel, vous chargez ces données afin de poser des questions à leur sujet.\n", "\n", "- Quel est le meilleur moment pour acheter des citrouilles ?\n", "\n", "- Quel prix puis-je attendre pour une caisse de citrouilles miniatures ?\n", "\n", "- Devrais-je les acheter dans des paniers d'un demi-boisseau ou dans des boîtes de 1 1/9 boisseau ? Continuons à explorer ces données.\n", "\n", "Dans la leçon précédente, vous avez créé un `tibble` (une réinvention moderne du tableau de données) et l'avez rempli avec une partie du jeu de données original, en standardisant les prix par boisseau. Cependant, en faisant cela, vous n'avez pu recueillir qu'environ 400 points de données et uniquement pour les mois d'automne. Peut-être pouvons-nous obtenir un peu plus de détails sur la nature des données en les nettoyant davantage ? Nous verrons... 🕵️‍♀️\n", "\n", "Pour cette tâche, nous aurons besoin des packages suivants :\n", "\n", "- `tidyverse` : Le [tidyverse](https://www.tidyverse.org/) est une [collection de packages R](https://www.tidyverse.org/packages) conçue pour rendre la science des données plus rapide, plus facile et plus amusante !\n", "\n", "- `tidymodels` : Le [framework tidymodels](https://www.tidymodels.org/) est une [collection de packages](https://www.tidymodels.org/packages/) pour la modélisation et l'apprentissage automatique.\n", "\n", "- `janitor` : Le [package janitor](https://github.com/sfirke/janitor) fournit de petits outils simples pour examiner et nettoyer des données désordonnées.\n", "\n", "- `corrplot` : Le [package corrplot](https://cran.r-project.org/web/packages/corrplot/vignettes/corrplot-intro.html) offre un outil visuel exploratoire sur les matrices de corrélation qui prend en charge le réordonnancement automatique des variables pour aider à détecter des motifs cachés entre les variables.\n", "\n", "Vous pouvez les installer avec la commande suivante :\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"corrplot\"))`\n", "\n", "Le script ci-dessous vérifie si vous avez les packages nécessaires pour compléter ce module et les installe pour vous s'ils sont manquants.\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": [ "Nous allons ensuite charger ces formidables packages et les rendre disponibles dans notre session R actuelle. (Ceci est simplement une illustration, `pacman::p_load()` l'a déjà fait pour vous)\n", "\n", "## 1. Une ligne de régression linéaire\n", "\n", "Comme vous l'avez appris dans la Leçon 1, l'objectif d'un exercice de régression linéaire est de pouvoir tracer une *ligne* *de* *meilleur ajustement* pour :\n", "\n", "- **Montrer les relations entre les variables**. Illustrer la relation entre les variables.\n", "\n", "- **Faire des prédictions**. Réaliser des prédictions précises sur la position d'un nouveau point de données par rapport à cette ligne.\n", "\n", "Pour tracer ce type de ligne, nous utilisons une technique statistique appelée **Régression des Moindres Carrés**. Le terme `moindres carrés` signifie que tous les points de données entourant la ligne de régression sont élevés au carré, puis additionnés. Idéalement, cette somme finale est aussi petite que possible, car nous voulons un faible nombre d'erreurs, ou `moindres carrés`. Ainsi, la ligne de meilleur ajustement est celle qui nous donne la valeur la plus basse pour la somme des erreurs au carré - d'où le nom *régression des moindres carrés*.\n", "\n", "Nous procédons ainsi car nous souhaitons modéliser une ligne ayant la plus faible distance cumulative par rapport à tous nos points de données. Nous élevons également les termes au carré avant de les additionner, car nous nous intéressons à leur magnitude plutôt qu'à leur direction.\n", "\n", "> **🧮 Montrez-moi les calculs**\n", ">\n", "> Cette ligne, appelée *ligne de meilleur ajustement*, peut être exprimée par [une équation](https://fr.wikipedia.org/wiki/R%C3%A9gression_lin%C3%A9aire_simple) :\n", ">\n", "> Y = a + bX\n", ">\n", "> `X` est la '`variable explicative` ou `prédicteur`'. `Y` est la '`variable dépendante` ou `résultat`'. La pente de la ligne est `b` et `a` est l'ordonnée à l'origine, qui correspond à la valeur de `Y` lorsque `X = 0`.\n", ">\n", "\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/slope.png \"pente = $y/x$\")\n", " Infographie par Jen Looper\n", ">\n", "> Tout d'abord, calculez la pente `b`.\n", ">\n", "> En d'autres termes, et en se référant à la question initiale sur les données des citrouilles : \"prédire le prix d'une citrouille par boisseau selon le mois\", `X` ferait référence au prix et `Y` au mois de vente.\n", ">\n", "> ![](../../../../../../translated_images/calculation.989aa7822020d9d0ba9fc781f1ab5192f3421be86ebb88026528aef33c37b0d8.fr.png)\n", " Infographie par Jen Looper\n", "> \n", "> Calculez la valeur de Y. Si vous payez environ 4 $, cela doit être en avril !\n", ">\n", "> Les calculs qui déterminent la ligne doivent démontrer la pente de la ligne, qui dépend également de l'ordonnée à l'origine, ou de la position de `Y` lorsque `X = 0`.\n", ">\n", "> Vous pouvez observer la méthode de calcul de ces valeurs sur le site [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html). Consultez également [ce calculateur des moindres carrés](https://www.mathsisfun.com/data/least-squares-calculator.html) pour voir comment les valeurs des nombres influencent la ligne.\n", "\n", "Pas si effrayant, n'est-ce pas ? 🤓\n", "\n", "#### Corrélation\n", "\n", "Un autre terme à comprendre est le **Coefficient de Corrélation** entre les variables X et Y données. À l'aide d'un nuage de points, vous pouvez rapidement visualiser ce coefficient. Un graphique avec des points de données alignés de manière nette présente une forte corrélation, tandis qu'un graphique avec des points dispersés partout entre X et Y présente une faible corrélation.\n", "\n", "Un bon modèle de régression linéaire sera celui qui a un Coefficient de Corrélation élevé (proche de 1 plutôt que de 0) en utilisant la méthode de Régression des Moindres Carrés avec une ligne de régression.\n" ], "metadata": { "id": "cdX5FRpvsoP5" } }, { "cell_type": "markdown", "source": [ "## **2. Une danse avec les données : créer un tableau de données pour la modélisation**\n", "\n", "

\n", " \n", "

Illustration par @allison_horst
\n", "\n", "\n", "\n" ], "metadata": { "id": "WdUKXk7Bs8-V" } }, { "cell_type": "markdown", "source": [ "Chargez les bibliothèques nécessaires et le jeu de données. Convertissez les données en un tableau contenant un sous-ensemble des données :\n", "\n", "- Ne sélectionnez que les citrouilles dont le prix est indiqué par boisseau\n", "\n", "- Convertissez la date en mois\n", "\n", "- Calculez le prix comme une moyenne des prix élevés et bas\n", "\n", "- Ajustez le prix pour refléter la tarification par quantité de boisseaux\n", "\n", "> Nous avons couvert ces étapes dans la [leçon précédente](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": [ "Dans l'esprit de l'aventure pure, explorons le [`package janitor`](../../../../../../2-Regression/3-Linear/solution/R/github.com/sfirke/janitor) qui offre des fonctions simples pour examiner et nettoyer des données désordonnées. Par exemple, examinons les noms de colonnes de nos données :\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": [ "🤔 Nous pouvons faire mieux. Transformons ces noms de colonnes en `friendR` en les convertissant au format [snake_case](https://en.wikipedia.org/wiki/Snake_case) à l'aide de `janitor::clean_names`. Pour en savoir plus sur cette fonction : `?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": [ "Beaucoup de tidyR 🧹 ! Maintenant, une danse avec les données en utilisant `dplyr` comme dans la leçon précédente ! 💃\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": [ "Bon travail ! 👌 Vous avez maintenant un ensemble de données propre et bien organisé sur lequel vous pouvez construire votre nouveau modèle de régression !\n", "\n", "Que diriez-vous d'un nuage de points ?\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": [ "Un nuage de points nous rappelle que nous n'avons des données mensuelles que d'août à décembre. Nous aurons probablement besoin de plus de données pour pouvoir tirer des conclusions de manière linéaire.\n", "\n", "Rejetons un coup d'œil à nos données de modélisation :\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": [ "Que faire si nous voulions prédire le `prix` d'une citrouille en fonction des colonnes `ville` ou `emballage`, qui sont de type caractère ? Ou encore plus simplement, comment pourrions-nous trouver la corrélation (qui nécessite que ses deux entrées soient numériques) entre, par exemple, `emballage` et `prix` ? 🤷🤷\n", "\n", "Les modèles d'apprentissage automatique fonctionnent mieux avec des caractéristiques numériques plutôt que des valeurs textuelles, il est donc généralement nécessaire de convertir les caractéristiques catégorielles en représentations numériques.\n", "\n", "Cela signifie que nous devons trouver un moyen de reformater nos prédicteurs pour les rendre plus faciles à utiliser efficacement par un modèle, un processus connu sous le nom de `ingénierie des caractéristiques`.\n" ], "metadata": { "id": "7hsHoxsStyjJ" } }, { "cell_type": "markdown", "source": [ "## 3. Prétraitement des données pour la modélisation avec recipes 👩‍🍳👨‍🍳\n", "\n", "Les activités qui reformattent les valeurs des prédicteurs pour les rendre plus faciles à utiliser efficacement par un modèle sont appelées `ingénierie des caractéristiques`.\n", "\n", "Différents modèles ont des exigences de prétraitement différentes. Par exemple, les moindres carrés nécessitent `l'encodage des variables catégorielles` telles que le mois, la variété et city_name. Cela consiste simplement à `traduire` une colonne avec des `valeurs catégorielles` en une ou plusieurs `colonnes numériques` qui remplacent la colonne d'origine.\n", "\n", "Par exemple, supposons que vos données incluent la caractéristique catégorielle suivante :\n", "\n", "| ville |\n", "|:--------:|\n", "| Denver |\n", "| Nairobi |\n", "| Tokyo |\n", "\n", "Vous pouvez appliquer un *encodage ordinal* pour substituer une valeur entière unique à chaque catégorie, comme ceci :\n", "\n", "| ville |\n", "|:-----:|\n", "| 0 |\n", "| 1 |\n", "| 2 |\n", "\n", "Et c'est ce que nous allons faire avec nos données !\n", "\n", "Dans cette section, nous allons explorer un autre package incroyable de Tidymodels : [recipes](https://tidymodels.github.io/recipes/) - conçu pour vous aider à prétraiter vos données **avant** d'entraîner votre modèle. Au cœur de ce package, une recette est un objet qui définit les étapes à appliquer à un ensemble de données afin de le préparer à la modélisation.\n", "\n", "Maintenant, créons une recette qui prépare nos données à la modélisation en substituant un entier unique à toutes les observations dans les colonnes des prédicteurs :\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": [ "Super ! 👏 Nous venons de créer notre première recette qui spécifie un résultat (prix) et ses prédicteurs correspondants, et qui encode toutes les colonnes prédicteurs en un ensemble d'entiers 🙌 ! Décomposons cela rapidement :\n", "\n", "- L'appel à `recipe()` avec une formule indique à la recette les *rôles* des variables en utilisant les données `new_pumpkins` comme référence. Par exemple, la colonne `price` a été assignée au rôle de `outcome`, tandis que le reste des colonnes ont été assignées au rôle de `predictor`.\n", "\n", "- `step_integer(all_predictors(), zero_based = TRUE)` spécifie que tous les prédicteurs doivent être convertis en un ensemble d'entiers, avec une numérotation commençant à 0.\n", "\n", "Nous sommes sûrs que vous vous posez des questions comme : \"C'est tellement génial !! Mais que faire si je voulais vérifier que les recettes font exactement ce que je m'attends à ce qu'elles fassent ? 🤔\"\n", "\n", "C'est une excellente réflexion ! Vous voyez, une fois votre recette définie, vous pouvez estimer les paramètres nécessaires pour prétraiter les données, puis extraire les données traitées. Vous n'avez généralement pas besoin de faire cela lorsque vous utilisez Tidymodels (nous verrons la convention normale dans un instant -> `workflows`), mais cela peut être utile si vous voulez effectuer une sorte de vérification pour confirmer que les recettes fonctionnent comme prévu.\n", "\n", "Pour cela, vous aurez besoin de deux autres verbes : `prep()` et `bake()`. Et comme toujours, nos petits amis R par [`Allison Horst`](https://github.com/allisonhorst/stats-illustrations) vous aident à mieux comprendre cela !\n", "\n", "

\n", " \n", "

Illustration par @allison_horst
\n" ], "metadata": { "id": "KEiO0v7kuC9O" } }, { "cell_type": "markdown", "source": [ "[`prep()`](https://recipes.tidymodels.org/reference/prep.html) : estime les paramètres nécessaires à partir d'un ensemble d'entraînement qui peuvent ensuite être appliqués à d'autres ensembles de données. Par exemple, pour une colonne prédictive donnée, quelle observation sera assignée à l'entier 0, 1, 2, etc.\n", "\n", "[`bake()`](https://recipes.tidymodels.org/reference/bake.html) : prend une recette préparée et applique les opérations à n'importe quel ensemble de données.\n", "\n", "Cela dit, préparons et appliquons nos recettes pour vraiment confirmer qu'en coulisses, les colonnes prédictives seront d'abord encodées avant qu'un modèle ne soit ajusté.\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": [ "Youpi ! 🥳 Les données traitées `baked_pumpkins` ont tous leurs prédicteurs encodés, confirmant que les étapes de prétraitement définies comme notre recette fonctionnent comme prévu. Cela les rend plus difficiles à lire pour vous, mais beaucoup plus compréhensibles pour Tidymodels ! Prenez un moment pour découvrir quelle observation a été associée à un entier correspondant.\n", "\n", "Il est également important de mentionner que `baked_pumpkins` est un tableau de données sur lequel nous pouvons effectuer des calculs.\n", "\n", "Par exemple, essayons de trouver une bonne corrélation entre deux points de vos données afin de potentiellement construire un bon modèle prédictif. Nous utiliserons la fonction `cor()` pour cela. Tapez `?cor()` pour en savoir plus sur cette fonction.\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": [ "Il s'avère qu'il n'y a qu'une faible corrélation entre la Ville et le Prix. Cependant, il existe une meilleure corrélation entre le Colis et son Prix. Cela a du sens, n'est-ce pas ? En général, plus la boîte de produits est grande, plus le prix est élevé.\n", "\n", "Pendant qu'on y est, essayons également de visualiser une matrice de corrélation de toutes les colonnes en utilisant le package `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": [ "🤩🤩 Bien mieux.\n", "\n", "Une bonne question à poser maintenant à propos de ces données serait : '`Quel prix puis-je attendre d'un lot de citrouilles donné ?`' Allons-y !\n", "\n", "> Note : Lorsque vous **`bake()`** la recette préparée **`pumpkins_prep`** avec **`new_data = NULL`**, vous extrayez les données d'entraînement traitées (c'est-à-dire encodées). Si vous aviez un autre ensemble de données, par exemple un ensemble de test, et que vous souhaitiez voir comment une recette le prétraiterait, vous pourriez simplement cuire **`pumpkins_prep`** avec **`new_data = test_set`**.\n", "\n", "## 4. Construire un modèle de régression linéaire\n", "\n", "

\n", " \n", "

Infographie par Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "YqXjLuWavNxW" } }, { "cell_type": "markdown", "source": [ "Maintenant que nous avons créé une recette et confirmé que les données seront prétraitées correctement, construisons un modèle de régression pour répondre à la question : `Quel prix puis-je attendre d'un paquet de citrouilles donné ?`\n", "\n", "#### Entraîner un modèle de régression linéaire en utilisant l'ensemble d'entraînement\n", "\n", "Comme vous l'avez probablement déjà compris, la colonne *price* est la variable `outcome`, tandis que la colonne *package* est la variable `predictor`.\n", "\n", "Pour ce faire, nous allons d'abord diviser les données de manière à ce que 80 % soient utilisées pour l'entraînement et 20 % pour le test, puis définir une recette qui encodera la colonne prédictive en un ensemble d'entiers, et enfin construire une spécification de modèle. Nous ne préparerons ni ne ferons cuire notre recette, car nous savons déjà qu'elle prétraitera les données comme prévu.\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": [ "Bon travail ! Maintenant que nous avons une recette et une spécification de modèle, nous devons trouver un moyen de les regrouper dans un objet qui prétraitera d'abord les données (prep+bake en coulisses), ajustera le modèle sur les données prétraitées et permettra également des activités de post-traitement potentielles. De quoi vous rassurer, non ? 🤩\n", "\n", "Dans Tidymodels, cet objet pratique s'appelle un [`workflow`](https://workflows.tidymodels.org/) et regroupe commodément vos composants de modélisation ! C'est ce que nous appellerions des *pipelines* en *Python*.\n", "\n", "Alors, regroupons tout dans un 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": [ "👌 De plus, un workflow peut être ajusté/entraîné de manière très similaire à un modèle.\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": [ "À partir des résultats du modèle, nous pouvons observer les coefficients appris lors de l'entraînement. Ils représentent les coefficients de la droite de meilleure ajustement qui minimise l'erreur globale entre les variables réelles et prédites.\n", "\n", "#### Évaluer les performances du modèle avec le jeu de test\n", "\n", "Il est temps de voir comment le modèle s'en est sorti 📏 ! Comment procéder ?\n", "\n", "Maintenant que nous avons entraîné le modèle, nous pouvons l'utiliser pour faire des prédictions sur le `test_set` en utilisant `parsnip::predict()`. Ensuite, nous pouvons comparer ces prédictions aux valeurs réelles des étiquettes pour évaluer à quel point le modèle fonctionne bien (ou pas !).\n", "\n", "Commençons par faire des prédictions pour le jeu de test, puis associons les colonnes au jeu de test.\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": [ "Oui, vous venez de former un modèle et de l'utiliser pour faire des prédictions ! 🔮 Est-il performant ? Évaluons les résultats du modèle !\n", "\n", "Dans Tidymodels, nous faisons cela en utilisant `yardstick::metrics()` ! Pour la régression linéaire, concentrons-nous sur les métriques suivantes :\n", "\n", "- `Root Mean Square Error (RMSE)` : La racine carrée de la [MSE](https://en.wikipedia.org/wiki/Mean_squared_error). Cela donne une métrique absolue dans la même unité que la variable cible (dans ce cas, le prix d'une citrouille). Plus la valeur est petite, meilleur est le modèle (de manière simpliste, cela représente le prix moyen par lequel les prédictions sont erronées !).\n", "\n", "- `Coefficient of Determination (souvent appelé R-squared ou R2)` : Une métrique relative où une valeur plus élevée indique un meilleur ajustement du modèle. Essentiellement, cette métrique représente la proportion de la variance entre les valeurs prédites et réelles que le modèle est capable d'expliquer.\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à va la performance du modèle. Voyons si nous pouvons obtenir une meilleure indication en visualisant un nuage de points du package et du prix, puis en utilisant les prédictions pour superposer une ligne de tendance.\n", "\n", "Cela signifie que nous devrons préparer et transformer le jeu de test afin de coder la colonne package, puis l'associer aux prédictions faites par notre modèle.\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": [ "Super ! Comme vous pouvez le constater, le modèle de régression linéaire ne généralise pas vraiment bien la relation entre un colis et son prix correspondant.\n", "\n", "🎃 Félicitations, vous venez de créer un modèle qui peut aider à prédire le prix de quelques variétés de citrouilles. Votre champ de citrouilles pour les fêtes sera magnifique. Mais vous pouvez probablement créer un meilleur modèle !\n", "\n", "## 5. Construire un modèle de régression polynomiale\n", "\n", "

\n", " \n", "

Infographie par Dasani Madipalli
\n", "\n", "\n", "\n" ], "metadata": { "id": "HOCqJXLTwtWI" } }, { "cell_type": "markdown", "source": [ "Parfois, nos données peuvent ne pas avoir une relation linéaire, mais nous souhaitons tout de même prédire un résultat. La régression polynomiale peut nous aider à faire des prédictions pour des relations non linéaires plus complexes.\n", "\n", "Prenons par exemple la relation entre le colis et le prix dans notre ensemble de données sur les citrouilles. Bien qu'il y ait parfois une relation linéaire entre les variables - plus le volume de la citrouille est grand, plus le prix est élevé - ces relations ne peuvent parfois pas être représentées par un plan ou une ligne droite.\n", "\n", "> ✅ Voici [quelques exemples supplémentaires](https://online.stat.psu.edu/stat501/lesson/9/9.8) de données qui pourraient utiliser la régression polynomiale\n", ">\n", "> Regardez à nouveau la relation entre la variété et le prix dans le graphique précédent. Ce nuage de points semble-t-il devoir nécessairement être analysé par une ligne droite ? Peut-être pas. Dans ce cas, vous pouvez essayer la régression polynomiale.\n", ">\n", "> ✅ Les polynômes sont des expressions mathématiques qui peuvent comporter une ou plusieurs variables et coefficients\n", "\n", "#### Entraîner un modèle de régression polynomiale en utilisant l'ensemble d'entraînement\n", "\n", "La régression polynomiale crée une *courbe* pour mieux ajuster les données non linéaires.\n", "\n", "Voyons si un modèle polynomial sera plus performant pour faire des prédictions. Nous suivrons une procédure quelque peu similaire à celle utilisée précédemment :\n", "\n", "- Créer une recette qui spécifie les étapes de prétraitement à effectuer sur nos données pour les préparer à la modélisation, c'est-à-dire : encoder les prédicteurs et calculer les polynômes de degré *n*\n", "\n", "- Construire une spécification de modèle\n", "\n", "- Regrouper la recette et la spécification de modèle dans un workflow\n", "\n", "- Créer un modèle en ajustant le workflow\n", "\n", "- Évaluer les performances du modèle sur les données de test\n", "\n", "Allons-y !\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": [ "#### Évaluer les performances du modèle\n", "\n", "👏👏 Vous avez construit un modèle polynomial, passons maintenant à la prédiction sur le jeu de test !\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": [ "Woo-hoo, évaluons les performances du modèle sur le test_set en utilisant `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": [ "🤩🤩 Bien meilleure performance.\n", "\n", "Le `rmse` est passé d'environ 7 à environ 3, ce qui indique une réduction de l'erreur entre le prix réel et le prix prédit. Vous pouvez *grossièrement* interpréter cela comme signifiant qu'en moyenne, les prédictions incorrectes se trompent d'environ 3 $. Le `rsq` est passé d'environ 0,4 à 0,8.\n", "\n", "Tous ces indicateurs montrent que le modèle polynomial fonctionne bien mieux que le modèle linéaire. Beau travail !\n", "\n", "Voyons si nous pouvons visualiser cela !\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": [ "Vous pouvez voir une courbe qui correspond mieux à vos données ! 🤩\n", "\n", "Vous pouvez la rendre encore plus lisse en passant une formule polynomiale à `geom_smooth` comme ceci :\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": [ "Tout comme une courbe fluide !🤩\n", "\n", "Voici comment faire une nouvelle prédiction :\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": [ "La prédiction du `modèle polynomial` est logique, étant donné les diagrammes de dispersion de `price` et `package` ! Et, si ce modèle est meilleur que le précédent, en regardant les mêmes données, vous devez prévoir un budget pour ces citrouilles plus coûteuses !\n", "\n", "🏆 Bravo ! Vous avez créé deux modèles de régression en une seule leçon. Dans la section finale sur la régression, vous apprendrez la régression logistique pour déterminer des catégories.\n", "\n", "## **🚀Défi**\n", "\n", "Testez plusieurs variables différentes dans ce notebook pour voir comment la corrélation correspond à la précision du modèle.\n", "\n", "## [**Quiz après la leçon**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/14/)\n", "\n", "## **Révision & Étude personnelle**\n", "\n", "Dans cette leçon, nous avons appris la régression linéaire. Il existe d'autres types importants de régression. Lisez à propos des techniques Stepwise, Ridge, Lasso et Elasticnet. Un bon cours pour approfondir est le [cours de Stanford sur l'apprentissage statistique](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).\n", "\n", "Si vous souhaitez en savoir plus sur l'utilisation du formidable framework Tidymodels, veuillez consulter les ressources suivantes :\n", "\n", "- Site web de Tidymodels : [Commencez avec Tidymodels](https://www.tidymodels.org/start/)\n", "\n", "- Max Kuhn et Julia Silge, [*Tidy Modeling with R*](https://www.tmwr.org/)*.*\n", "\n", "###### **MERCI À :**\n", "\n", "[Allison Horst](https://twitter.com/allison_horst?lang=en) pour avoir créé les illustrations incroyables qui rendent R plus accueillant et engageant. Retrouvez plus d'illustrations dans sa [galerie](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**Avertissement** : \nCe document a été traduit à l'aide du service de traduction automatique [Co-op Translator](https://github.com/Azure/co-op-translator). Bien que nous nous efforcions d'assurer l'exactitude, veuillez noter que les traductions automatisées peuvent contenir des erreurs ou des inexactitudes. Le document original dans sa langue d'origine doit être considéré comme la source faisant autorité. Pour des informations critiques, il est recommandé de faire appel à une traduction humaine professionnelle. Nous déclinons toute responsabilité en cas de malentendus ou d'interprétations erronées résultant de l'utilisation de cette traduction.\n" ] } ] }