diff --git a/SYNTHESE.md b/SYNTHESE.md new file mode 100644 index 0000000..037ae6f --- /dev/null +++ b/SYNTHESE.md @@ -0,0 +1,200 @@ +# TP02 - Synthèse : comparer et tracer des expérimentations ML + +Fil rouge : prédiction de la consommation électrique (kWh). Datasets versionnés avec **DVC** +(remote S3 = Garage), expériences tracées avec **MLflow** (expérience `tp02_electricity_consumption`, +13 runs : 10 régressions linéaires + 3 Ridge). + +Deux versions de dataset produites et versionnées (tags git + DVC) : + +| Version DVC | Tag git | Train | Validation | Test | +|---|---|---|---|---| +| v1 `full_history` | `dataset-v1-full-history` | 2011-2012 | 2013 | 2014 | +| v2 `recent_history` | `dataset-v2-recent-history` | 2013 | jan-mai 2014 | juin-déc 2014 | + +Métriques comparées : **RMSE** et **MAE** sur la **validation** (le test reste réservé). + +--- + +## Partie 1 - Comparaison de stratégies de features (split `full_history`) + +Stratégies testées (hypothèse -> features) : + +| Stratégie | Hypothèse | Features | +|---|---|---| +| `short_memory` | la conso dépend surtout de la veille | lag_1d | +| `seasonality` | conso plus saisonnière que journalière | lag_7d, lag_30d | +| `tendency` | conso surtout tendancielle | rolling_mean_7d, rolling_mean_30d | +| `mixed` | mémoire courte + tendance | lag_1d, lag_7d, lag_30d, rolling_mean_30d | +| `full` | toutes les features | les 6 | + +Résultats (validation, `full_history`) : + +| Stratégie | RMSE | MAE | +|---|---|---| +| `full` | **7.41** | **4.07** | +| `mixed` | 7.53 | 4.11 | +| `short_memory` | 8.82 | 4.58 | +| `seasonality` | 9.14 | 5.04 | +| `tendency` | 20.79 | 14.66 | + +**1.1 - Quelle stratégie obtient les meilleures performances ?** +`full` (6 features) puis `mixed` (4 features), quasi à égalité. Toutes deux combinent lags courts +et tendance. `tendency` (moyennes glissantes seules) est de loin la pire. + +**1.2 - Ajouter davantage de features améliore-t-il systématiquement le modèle ?** +Non. `short_memory` (1 feature) fait 8.82 alors que `tendency` (2 features) fait 20.79 : c'est la +**pertinence** des features, pas leur nombre, qui compte. Et `full` (6) n'améliore `mixed` (4) que +marginalement (7.41 vs 7.53) : rendements décroissants, les features supplémentaires apportent peu. + +**1.3 - Quelles hypothèses semblent validées ?** +- « La conso dépend de la veille » : validée, `lag_1d` est le prédicteur dominant (voir coefficients). +- « Plutôt tendancielle » (moyennes glissantes seules) : **invalidée** (pire modèle). +- La conso combine **mémoire court terme + tendance** : validée (mixed/full gagnants). + +--- + +## Partie 2 - Comparaison des stratégies d'entraînement (split) + +Chaque stratégie ré-entraînée sur `recent_history`. Matrice RMSE (validation) : + +| Stratégie | `full_history` | `recent_history` | +|---|---|---| +| `short_memory` | 8.82 | 8.30 | +| `seasonality` | 9.14 | 7.60 | +| `tendency` | 20.79 | 18.56 | +| `mixed` | 7.53 | 6.67 | +| `full` | 7.41 | **6.58** | + +La stratégie `full` a été relancée sur **la première version du dataset (v1) restaurée via DVC** +(`git checkout dataset-v1-full-history -- ... && dvc checkout`), illustrant la reproductibilité. + +**2.1 - Quel split obtient les meilleures performances ?** +`recent_history` : RMSE plus bas pour **les 5 stratégies** (env. -12 %). + +**2.2 - Davantage d'historique ou données plus récentes ?** +Ici, **données plus récentes**. Nuance importante : la comparaison n'est pas strictement iso car les +fenêtres de validation diffèrent (2013 pour `full_history` vs début 2014 pour `recent_history`). +Prédire début 2014 à partir de 2013 (année adjacente) est plus « facile » que prédire 2013 à partir +de 2011-2012. Enseignement : la **proximité temporelle train/validation** (moins de dérive) prime sur +le simple volume d'historique ancien. + +**2.3 - Avantages / inconvénients de chaque approche ?** +- `full_history` : + capte les cycles longs (saisonnalité annuelle), robustesse au bruit ponctuel ; + - inclut des données anciennes possiblement obsolètes (data/concept drift), plus coûteux, validation lointaine. +- `recent_history` : + colle au régime actuel (moins de drift), moins coûteux ; + - moins de données (variance accrue), saisonnalités longues moins fiables (`lag_365d`), sensible aux + événements récents atypiques. + +**2.4 - Bonus : coefficients du modèle** (linéaire `full`, `recent_history`), par influence décroissante : + +| Feature | Coefficient | +|---|---| +| lag_1d | +0.460 | +| lag_7d | +0.371 | +| rolling_mean_7d | +0.288 | +| rolling_mean_30d | -0.268 | +| lag_365d | +0.090 | +| lag_30d | +0.058 | + +- Les plus influentes : `lag_1d` (la veille) et `lag_7d` (semaine dernière), puis la paire + `rolling_mean_7d` (+) / `rolling_mean_30d` (-) qui agit en **différentiel de tendance** court/moyen terme. +- Les peu utilisées : `lag_30d` et `lag_365d` (mensuel/annuel apportent peu une fois les autres présentes). +- Cela **confirme les hypothèses de la Partie 1** : mémoire court terme + tendance courte dominent. + +--- + +## Partie 3 - Influence des hyperparamètres avec Ridge + +Sur le meilleur couple (features `full`, split `recent_history`), alphas `[1, 1e3, 1e9]` : + +| alpha | RMSE (val) | MAE (val) | RMSE (train) | +|---|---|---|---| +| 1 | **6.576** | **3.677** | 7.397 | +| 1e3 | **6.576** | **3.677** | 7.397 | +| 1e9 | 7.059 | 4.185 | 8.115 | + +Coefficients selon alpha : + +| Feature | alpha=1 | alpha=1e3 | alpha=1e9 | +|---|---|---|---| +| lag_1d | 0.460 | 0.460 | 0.284 | +| lag_7d | 0.371 | 0.371 | 0.263 | +| lag_30d | 0.058 | 0.058 | 0.158 | +| lag_365d | 0.090 | 0.090 | 0.174 | +| rolling_mean_7d | 0.288 | 0.287 | 0.069 | +| rolling_mean_30d | -0.268 | -0.268 | 0.043 | + +**3.1 - Quelle valeur d'alpha obtient les meilleures performances ?** +`alpha=1` (identique à `alpha=1e3`). `alpha=1e9` dégrade nettement (RMSE 7.06). + +**3.2 - Que se passe-t-il sur les coefficients quand alpha augmente ?** +Ils sont **contraints vers zéro** (régularisation L2). À `alpha=1` et `1e3` : quasi identiques, car la +pénalité reste négligeable devant ~4,5 M d'échantillons. À `alpha=1e9` : forte contraction, les +coefficients dominants s'écrasent (`lag_1d` 0.46 -> 0.28, `rolling_mean_7d` 0.29 -> 0.07, +`rolling_mean_30d` -0.27 -> +0.04) ; le modèle devient plus « plat » (biais accru) -> RMSE augmente. + +**3.3 - Pourquoi est-il indispensable de logger les hyperparamètres ?** +Pour la **reproductibilité et la comparabilité** : une métrique n'a de sens qu'associée à ses HP (alpha, +features, split). Sans, impossible de reproduire un run, d'expliquer un écart de performance ou de +comparer objectivement. MLflow lie chaque métrique à ses paramètres -> traçabilité complète. + +**3.4 - Bonus : que représente le bruit ? Faut-il l'apprendre ?** +Le bruit = variations aléatoires non reproductibles (erreurs de mesure, aléas ponctuels). Il **ne faut +pas** l'apprendre : le modèle mémoriserait des accidents particuliers (overfitting) au lieu de la relation +générale, et généraliserait mal. Exemple : un pic de conso dû à une canicule exceptionnelle un 15 août +ne doit pas devenir une règle. + +**3.5 - L'ordre de grandeur des coefficients a-t-il un effet ? Et avec du bruit ?** +Oui : de grands coefficients rendent la prédiction très sensible aux petites variations des features +(amplification). En présence de bruit, ils **amplifient ce bruit** -> prédictions instables, variance +élevée (overfitting). Des coefficients plus petits lissent la réponse. + +**3.6 - Rôle de l'hyperparamètre alpha ?** +alpha règle le **compromis biais/variance** en pénalisant la magnitude des coefficients : alpha faible -> +modèle libre (variance élevée, risque d'overfitting) ; alpha élevé -> coefficients contraints (biais +élevé, risque d'underfitting). C'est le levier de régularisation pour améliorer la généralisation face +au bruit. + +**3.7 - Comment utiliser un dataset de test dans le choix d'un hyperparamètre ?** +On ne choisit **jamais** alpha sur le test. On règle alpha sur la **validation** (comparaison des alphas), +puis on mesure **une seule fois** le modèle retenu sur le **test** (jamais vu) pour une estimation non +biaisée de la généralisation. Utiliser le test pour régler alpha revient à le « fuiter » -> estimation +trop optimiste. + +--- + +## Partie 4 - Réflexion en production + +**4.1 - Sur quelles données entraîner ?** +Sur une **fenêtre glissante de données récentes** représentatives du régime actuel (ici `recent_history` +l'emporte), en réintégrant régulièrement les dernières observations, tout en gardant assez d'historique +pour capter les saisonnalités utiles (semaine, éventuellement année si stable). Compromis récence/volume. + +**4.2 - À quelle fréquence réentraîner ?** +Réentraînement **périodique** (hebdomadaire à mensuel selon le coût et la vitesse de dérive) **et** +déclenché **par événement** (dégradation des métriques ou détection de drift). La forte saisonnalité de +la conso justifie au minimum un rythme régulier accompagné d'une surveillance. + +**4.3 - Quels indicateurs signalent un nouvel entraînement ?** +- **Dégradation des métriques** en production (RMSE/MAE qui remontent vs baseline). +- **Data drift** : la distribution des features d'entrée s'éloigne de celle d'entraînement. +- **Concept drift** : la relation features -> cible change (nouveaux usages, réglementation, météo extrême). +- Écart croissant entre distributions **train vs production** (surveillance type Evidently/Grafana). + +--- + +## Livrables - synthèse finale + +- **Stratégies de features testées** : `short_memory`, `seasonality`, `tendency`, `mixed`, `full`. +- **Résultats** : voir matrices ci-dessus (validation RMSE/MAE). +- **Meilleur run MLflow** : features `full` sur le split `recent_history` (RMSE **6.576**, MAE **3.677**) ; + en linéaire comme en Ridge `alpha` ≤ 1e3 (résultats indistinguables ; run Ridge `alpha=1e3` + `id 57cac1f5...`). +- **Impact du changement de split** : `recent_history` améliore **toutes** les stratégies (~ -12 % RMSE), + résultat à nuancer (fenêtres de validation différentes -> proximité temporelle avantageuse). +- **Stratégie recommandée en production** : features **`mixed`** (parcimonie : quasi identique à `full` + mais 4 features au lieu de 6, `lag_30d`/`lag_365d` contribuant peu), entraînée sur une **fenêtre de + données récentes**, avec **Ridge `alpha` modéré (1 à 1e3)**. +- **Raisons** : meilleure performance en validation, modèle plus simple donc plus robuste et + maintenable, données récentes = moins de dérive, régularisation légère = filet de sécurité contre le + bruit sans coût de performance. diff --git a/lab/modeling_ridge/cli.py b/lab/modeling_ridge/cli.py index 3fe235b..8735444 100644 --- a/lab/modeling_ridge/cli.py +++ b/lab/modeling_ridge/cli.py @@ -74,12 +74,6 @@ def main( ): mlflow.log_metric(f"coef_{feature_name}", float(coefficient)) - mlflow.sklearn.log_model( - sk_model=model, - name="electricity_consumption_model", - registered_model_name="electricity_consumption_model", - ) - if __name__ == "__main__": app()