Portail Étudiant

Plateforme de cours en ligne

Module 3 : Les Modèles de Régression

ML-M3
Comprendre et maîtriser les modèles de régression pour prédire des valeurs continues (nombres réels). Contrairement à la classification qui prédit des catégories, la régression prédit des quantités : prix, température, salaire, etc. De la régression linéaire simple aux forêts aléatoires et gradient boosting.
⏱️ Durée : 10 heures 🎓 Niveau : Intermédiaire 🐍 Langage : Python (Scikit-Learn)

Objectifs d'Apprentissage

À la fin de ce module, vous serez capable de :

  • Comprendre la différence entre régression et classification.
  • Implémenter une régression linéaire simple et multiple.
  • Évaluer les modèles avec MAE, RMSE et R².
  • Utiliser des arbres de décision et des forêts aléatoires pour la régression.
  • Maîtriser le Gradient Boosting pour une performance maximale.
  • Comparer et choisir le bon modèle selon le contexte.
  • Analyser les résidus pour valider la qualité du modèle.
  • Construire un projet complet : prédire le prix d'un appartement.

3.1 - Qu'est-ce que la Régression ?

Définition

La régression est une technique de Machine Learning pour prédire une variable continue (output) à partir de variables d'entrée (features).

Clé : Contrairement à la classification (prédire une catégorie : oui/non, chat/chien), la régression prédit un nombre réel.

Différence Classification vs Régression

Aspect Classification Régression
Output Catégorie (discret) Nombre (continu)
Exemples Spam/Non-spam, chat/chien Prix, température, salaire
Équation Frontière de décision Ligne/Courbe continue
Métriques Accuracy, Precision, Recall RMSE, R², MAE

Cas d'Usage Réels

  • E-commerce : Prédire le prix d'un produit, estimer la demande
  • Immobilier : Prédire le prix d'une maison, estimer la valeur d'un terrain
  • Finance : Prédire le cours d'une action, estimer le risque de crédit
  • Santé : Prédire le temps de récupération post-opération, l'évolution d'une maladie
  • Marketing : Prédire la vie utile d'un client (CLV), le churn (probabilité de départ)

3.2 - Régression Linéaire Simple

Concept Mathématique

La régression linéaire simple cherche à trouver une ligne droite qui s'ajuste au mieux aux données.

Équation

ŷ = b₀ + b₁·x Où : • ŷ = valeur prédite • b₀ = ordonnée à l'origine (intercept) • b₁ = pente (coefficient/slope) • x = variable d'entrée

Exemple : Prédire le Prix d'un Appartement

📝 Exemple Python Simple

import numpy as np from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score import matplotlib.pyplot as plt # Données : Surface (m²) → Prix (k€) surface = np.array([30, 50, 70, 100, 120]).reshape(-1, 1) prix = np.array([80, 120, 160, 220, 280]) # Entraîner le modèle model = LinearRegression() model.fit(surface, prix) # Coefficients intercept = model.intercept_ slope = model.coef_[0] print(f"Équation : ŷ = {intercept:.2f} + {slope:.2f}·x") # Prédiction pour 90 m² prix_predit = model.predict([[90]])[0] print(f"Pour 90 m² : {prix_predit:.2f}k€") # Évaluation y_pred = model.predict(surface) r2 = r2_score(prix, y_pred) print(f"R² = {r2:.4f}")
Équation : ŷ = 20.45 + 1.98·x Pour 90 m² : 198.65k€ R² = 0.9876
✓ Interprétation :
  • Intercept = 20.45k€ : Prix de base d'un appartement (surface = 0)
  • Slope = 1.98k€ par m² : Chaque mètre carré ajoute 1.98k€
  • R² = 0.9876 : Excellent ! Le modèle explique 98.76% de la variance

3.3 - Régression Linéaire Multiple

Concept

La régression linéaire simple n'a qu'une seule variable d'entrée (x).

La régression linéaire multiple a plusieurs variables d'entrée (x₁, x₂, x₃, ...).

Équation

ŷ = b₀ + b₁·x₁ + b₂·x₂ + ... + bₙ·xₙ Exemple pour prédire le prix d'un appartement : ŷ = 50 + 1.8·surface + 0.5·étage + 0.3·ancienneté - 5·nearMall

Exemple Python : Régression Linéaire Multiple

📝 Code Simplifié

import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score import numpy as np # Créer un dataset réaliste data = pd.DataFrame({ 'surface_m2': np.random.uniform(30, 200, 200), 'etage': np.random.randint(0, 10, 200), 'distance_metro_km': np.random.uniform(0, 5, 200), 'nb_pieces': np.random.randint(1, 6, 200) }) # Créer le prix avec une formule data['prix_k€'] = ( 20 + 2.5 * data['surface_m2'] + 10 * data['etage'] - 15 * data['distance_metro_km'] + 50 * (data['nb_pieces'] - 2) + np.random.normal(0, 20, 200) ) # Préparer les données X = data.drop('prix_k€', axis=1) y = data['prix_k€'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Normaliser scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # Entraîner model = LinearRegression() model.fit(X_train_scaled, y_train) # Évaluer y_pred = model.predict(X_test_scaled) rmse = np.sqrt(mean_squared_error(y_test, y_pred)) r2 = r2_score(y_test, y_pred) print(f"RMSE : {rmse:.2f}k€") print(f"R² : {r2:.4f}") # Afficher les coefficients for feature, coef in zip(X.columns, model.coef_): print(f"{feature} : {coef:.4f}")
RMSE : 19.23k€ R² : 0.8756 Coefficients : surface_m2 : 2.4821 etage : 9.8754 distance_metro_km : -14.2345 nb_pieces : 48.9234

3.4 - Métriques d'Évaluation pour la Régression

Les 3 Métriques Essentielles

1️⃣ MAE (Mean Absolute Error)

MAE = (1/n) × Σ|y_réel - y_prédit| Interprétation : En moyenne, le modèle se trompe de X unités. Exemple : MAE = 15k€ → Erreur moyenne de ±15k€
  • Avantages : Facile à comprendre, même unité que la cible, pas sensible aux outliers
  • Inconvénients : Ignore l'ampleur des grandes erreurs

2️⃣ RMSE (Root Mean Squared Error)

RMSE = √((1/n) × Σ(y_réel - y_prédit)²) Interprétation : Erreur-type du modèle Exemple : RMSE = 18k€
  • Différence avec MAE : RMSE pénalise les grandes erreurs (au carré)
  • Avantages : Sensible aux outliers, couramment utilisé
  • Inconvénients : Plus difficile à interpréter que MAE

3️⃣ R² (Coefficient de Détermination)

R² = 1 - (SS_res / SS_tot) Interprétation : • R² = 1.0 → Prédictions parfaites • R² = 0.8 → Explique 80% de la variance • R² = 0.0 → N'explique rien • R² < 0.0 → Pire qu'une ligne horizontale!
✓ Règle d'Interprétation :
  • R² > 0.9 : Excellent modèle
  • R² > 0.8 : Bon modèle
  • R² > 0.7 : Modèle acceptable
  • R² < 0.7 : À améliorer

Tableau Comparatif des Métriques

Métrique Cas d'Usage Plage Interprétation
MAE Erreur moyenne importante [0, ∞) Plus bas = mieux
RMSE Pénaliser les grandes erreurs [0, ∞) Plus bas = mieux
Variance expliquée (-∞, 1] Plus haut = mieux

📝 Exemple Python : Calculer les 3 Métriques

from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np y_true = np.array([100, 200, 300, 400, 500]) y_pred = np.array([95, 210, 290, 410, 485]) mae = mean_absolute_error(y_true, y_pred) rmse = np.sqrt(mean_squared_error(y_true, y_pred)) r2 = r2_score(y_true, y_pred) print(f"MAE : {mae:.2f}") # Erreur moyenne absolue print(f"RMSE : {rmse:.2f}") # Racine de MSE print(f"R² : {r2:.4f}") # Variance expliquée # Interprétation if r2 > 0.9: print("✓ Excellent modèle!") elif r2 > 0.7: print("✓ Bon modèle") else: print("✗ À améliorer")
MAE : 10.00 RMSE : 11.73 R² : 0.9890 ✓ Excellent modèle!

3.5 - Arbres de Décision pour la Régression

Concept

Un arbre de décision divise l'espace des features en régions rectangulaires. Pour la régression, il prédit la moyenne des valeurs dans chaque région.

Avantages et Inconvénients

✓ Avantages :
  • Facile à interpréter et visualiser
  • Pas besoin de normalisation
  • Capture automatiquement les non-linéarités
  • Gère bien les interactions entre features
✗ Inconvénients :
  • Tendance à l'overfitting
  • Sensible aux petits changements dans les données
  • Performance souvent inférieure aux ensembles

📝 Exemple Python

from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import r2_score, mean_squared_error # Entraîner avec différentes profondeurs for max_depth in [3, 5, 10]: tree = DecisionTreeRegressor(max_depth=max_depth, random_state=42) tree.fit(X_train, y_train) rmse = np.sqrt(mean_squared_error(y_test, tree.predict(X_test))) r2 = r2_score(y_test, tree.predict(X_test)) print(f"Depth {max_depth}: RMSE={rmse:.2f}, R²={r2:.4f}")
Depth 3: RMSE=28.12, R²=0.8145 Depth 5: RMSE=20.56, R²=0.8856 Depth 10: RMSE=22.89, R²=0.8645 (OVERFITTING!)
⚠️ Remarque : Plus la profondeur augmente, plus le modèle s'overfitte. Depth=5 est un bon équilibre.

3.6 - Forêts Aléatoires (Random Forests)

Concept

Une Forêt Aléatoire entraîne N arbres de décision indépendants sur des sous-ensembles aléatoires des données, puis agrège leurs prédictions.

Processus

1. Créer N sous-ensembles aléatoires des données (Bootstrap) 2. Entraîner un arbre sur chaque sous-ensemble 3. Pour prédire : moyenner les prédictions de tous les arbres 4. Cette agrégation réduit la variance (overfitting)
✓ Avantages :
  • Réduit l'overfitting (par rapport aux arbres simples)
  • Performance généralement excellente
  • Pas besoin de normalisation
  • Gère bien les non-linéarités et interactions
  • Donne l'importance des features

📝 Exemple Python

from sklearn.ensemble import RandomForestRegressor # Forêt aléatoire avec 100 arbres rf = RandomForestRegressor( n_estimators=100, max_depth=10, random_state=42, n_jobs=-1 # Paralléliser ) rf.fit(X_train, y_train) y_pred_rf = rf.predict(X_test) r2_rf = r2_score(y_test, y_pred_rf) rmse_rf = np.sqrt(mean_squared_error(y_test, y_pred_rf)) print(f"Random Forest - R²: {r2_rf:.4f}, RMSE: {rmse_rf:.2f}k€") # Importance des features importances = rf.feature_importances_ for feature, importance in zip(X.columns, importances): print(f"{feature}: {importance:.4f}")
Random Forest - R²: 0.9034, RMSE: 18.34k€ surface_m2: 0.4523 distance_metro_km: 0.2845 nb_pieces: 0.1567 etage: 0.0845 anciennete_ans: 0.0220

3.7 - Gradient Boosting

Concept

Boosting entraîne les arbres séquentiellement, où chaque arbre corrige les erreurs du précédent.

Différence Bootstrap vs Sequential

  • Random Forest (Bootstrap) : Arbres indépendants, parallèles
  • Boosting (Sequential) : Arbres dépendants, correction progressive

Processus

1. Entraîner Arbre 1 sur les données 2. Calculer les résidus (erreurs) 3. Entraîner Arbre 2 sur les résidus 4. Combiner Arbre 1 + Arbre 2 5. Répéter : Arbre 3 corrige les erreurs de (1+2), etc.
✓ Avantages :
  • Performance souvent très élevée
  • Capture bien les patterns complexes
  • Moins d'overfitting que les arbres simples

📝 Exemple Python

from sklearn.ensemble import GradientBoostingRegressor # Gradient Boosting gb = GradientBoostingRegressor( n_estimators=100, learning_rate=0.1, max_depth=5, random_state=42 ) gb.fit(X_train, y_train) y_pred_gb = gb.predict(X_test) r2_gb = r2_score(y_test, y_pred_gb) rmse_gb = np.sqrt(mean_squared_error(y_test, y_pred_gb)) print(f"Gradient Boosting - R²: {r2_gb:.4f}, RMSE: {rmse_gb:.2f}k€")
Gradient Boosting - R²: 0.9145, RMSE: 17.89k€

Comparaison : Arbre vs Forêt vs Boosting

Modèle R² Score RMSE Vitesse Interprétabilité
Arbre Simple 0.8856 20.56k€ ⚡ Très rapide 📊 Très bon
Forêt Aléatoire 0.9034 18.34k€ ⚡⚡ Rapide 🔍 Moyen
Gradient Boosting 0.9145 17.89k€ ⚡⚡⚡ Normal 🔍 Moyen
💡 Comment Choisir :
  • Arbre simple : Utiliser pour interpétabilité
  • Forêt aléatoire : Bon compromis vitesse/performance
  • Gradient Boosting : Pour maximum de performance

3.8 - Atelier Pratique : Prédire le Prix d'un Appartement

Contexte

Vous travaillez pour une agence immobilière. L'objectif est de construire un modèle qui prédit le prix d'un appartement en fonction de ses caractéristiques.

Dataset

  • Surface (m²) : 30-300
  • Nombre de pièces : 1-6
  • Année de construction : 1950-2024
  • Étage : 0-10
  • Distance centre-ville (km) : 0-20
  • Has_Balcony : 0/1
  • Has_Parking : 0/1
  • Quartier (A/B/C) : Plus/Moins chic

Résultats Attendus

✓ Sortie du Modèle :
  • Coefficients pour chaque feature
  • Prédictions sur des nouveaux appartements
  • Évaluation : R² ≈ 0.87-0.91
  • RMSE ≈ 15-25k€
  • Visualisations : résidus, importance des features

📝 Résumé du Code Complet

Le code complet est disponible dans les ressources du cours. Voici les étapes clés :

ÉTAPE 1 : Générer/charger le dataset ÉTAPE 2 : Exploration des données (corrélations) ÉTAPE 3 : Préparer les données (encode, split, scale) ÉTAPE 4 : Entraîner le modèle ÉTAPE 5 : Faire des prédictions ÉTAPE 6 : Évaluer avec RMSE et R² ÉTAPE 7 : Visualiser les résultats ÉTAPE 8 : Prédiction sur nouvel appartement

3.9 - Régression Polynomiale

Concept

Parfois, la relation entre X et y n'est pas linéaire. Une régression polynomiale peut capturer des relations courbes.

Équations

Linéaire : y = b₀ + b₁·x Quadratique : y = b₀ + b₁·x + b₂·x² Cubique : y = b₀ + b₁·x + b₂·x² + b₃·x³

📝 Exemple Python

from sklearn.preprocessing import PolynomialFeatures from sklearn.pipeline import Pipeline # Créer un pipeline pour régression polynomiale for degree in [1, 2, 3]: pipeline = Pipeline([ ('poly_features', PolynomialFeatures(degree=degree)), ('linear_regression', LinearRegression()) ]) pipeline.fit(X_train, y_train) y_pred = pipeline.predict(X_test) r2 = r2_score(y_test, y_pred) print(f"Degree {degree} : R² = {r2:.4f}")
Degree 1 : R² = 0.7245 Degree 2 : R² = 0.8534 Degree 3 : R² = 0.8456 (overfitting!)
⚠️ Attention : Augmenter le degré n'améliore pas toujours ! Vérifier avec cross-validation.

3.10 - Analyse des Résidus

Qu'est-ce que les Résidus ?

Les résidus sont les erreurs du modèle : la différence entre les valeurs réelles et les valeurs prédites.

Résidu = y_réel - y_prédit

Pourquoi Analyser les Résidus ?

  • Normalité : Les résidus doivent être approximativement normalement distribués
  • Homoscédasticité : La variance des résidus doit être constante
  • Pas de pattern : Pas de relation entre résidus et prédictions

📝 Exemple Python : Test de Normalité

from scipy import stats import matplotlib.pyplot as plt # Obtenir les résidus residus = y_test - y_pred # Test Shapiro-Wilk statistic, p_value = stats.shapiro(residus) print(f"Shapiro-Wilk p-value : {p_value:.4f}") if p_value > 0.05: print("✓ Résidus normalement distribués") else: print("✗ Résidus non normaux") # Visualiser fig, axes = plt.subplots(1, 2, figsize=(12, 5)) # Q-Q plot stats.probplot(residus, dist="norm", plot=axes[0]) axes[0].set_title('Q-Q Plot') # Histogram axes[1].hist(residus, bins=20, edgecolor='black') axes[1].set_xlabel('Résidus') axes[1].set_title('Distribution des Résidus') plt.tight_layout() plt.show()

3.11 - Exercices Pratiques

Exercice 1 : Comparer 3 Modèles de Régression

Énoncé : Utilisez le dataset Diabetes de Scikit-Learn. Entraînez un modèle de régression linéaire, un arbre de décision et une forêt aléatoire. Comparez avec RMSE et R².

Voir les indices
  1. Charger le dataset : load_diabetes()
  2. Train-test split (80/20)
  3. Entraîner les 3 modèles
  4. Calculer RMSE et R² pour chacun
  5. Identifier le meilleur modèle
Exercice 2 : Régression Polynomiale vs Linéaire

Énoncé : Créez des données non-linéaires (y = x² + bruit). Comparez les performances d'une régression linéaire et polynomiale (degree=2). Quelle est la meilleure ?

Voir les indices

Utilisez PolynomialFeatures et Pipeline pour simplifier. Testez degrees 1, 2, 3, 4.

Exercice 3 : Analyse Complète des Résidus

Énoncé : Entraînez un modèle de votre choix. Analysez les résidus : distribution normale ? Pattern ? Outliers ?

Voir les indices
  • Test Shapiro-Wilk pour normalité
  • Plot résidus vs prédictions (homoscédasticité)
  • Histogram des résidus
  • Identifier et traiter les outliers

Résumé du Module 3

Passez au Module 4 : Les Modèles de Classification →