Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

Classification de Consommateurs Électriques pour l'Affectation Tarifaire

Python scikit-learn Streamlit Status

Projet EDF MAD EDVANCE — Classification automatique multi-classes de consommateurs électriques industriels
Auteur : Emmanuel TSAGUE
Résultat : 91 % de précision en validation croisée — modèle exporté en production (.joblib)


Sommaire

  1. Contexte
  2. Problème métier
  3. Pourquoi ce problème est difficile
  4. Méthodes
  5. Résultats
  6. Valeur métier
  7. Architecture du projet
  8. Guide d'utilisation
  9. Notions clés expliquées
  10. Auteur

Contexte

EDF MAD EDVANCE gère un portefeuille de grands comptes industriels : usines, datacenters, hôpitaux, collectivités, sites de production. Chaque consommateur est rattaché à une gamme tarifaire qui détermine ses conditions contractuelles, son pricing et les engagements de qualité de service.

Historiquement, l'affectation d'un consommateur à sa gamme était réalisée manuellement par des chargés de clientèle, à partir de fichiers Excel hétérogènes reçus des fournisseurs et des systèmes internes. Ce processus était :

  • Lent : plusieurs jours de traitement pour un lot de dossiers
  • Subjectif : les règles d'affectation variaient selon les experts
  • Risqué : une mauvaise classification entraîne un tarif incorrect, un litige contractuel ou une perte de marge

Le jeu de données traité contient les consommateurs listés dans le registre officiel 2016, avec leurs caractéristiques techniques et contractuelles.

Ce projet existe parce que le volume de dossiers à traiter croît chaque année et que la saisie manuelle ne passe plus à l'échelle.


Problème métier

Comment automatiser et fiabiliser la classification de consommateurs électriques industriels dans 19 gammes métier, en éliminant les risques de biais et de fuite de données, afin de produire un modèle directement utilisable en production ?

La tâche est une classification multiclasse supervisée :

  • Entrée : caractéristiques d'un consommateur (puissance souscrite, type de site, historique de consommation, données contractuelles...)
  • Sortie : une des 19 gammes métier (ex. : BT ≤ 36 kVA, HTA, HTB, C5, C4, C3...)
  • Contrainte : le modèle doit être fiable, traçable, et déployable sans refonte de l'infrastructure

Pourquoi ce problème est difficile

1. La fuite de données (data leakage) — le piège principal

Définition : La fuite de données se produit quand des informations de la variable cible "contaminent" les variables explicatives pendant l'entraînement. Le modèle apprend à tricher plutôt qu'à vraiment comprendre.

Dans ce projet, 38 colonnes ont été identifiées et supprimées parce qu'elles contenaient des informations directement dérivées de la gamme cible — comme si on donnait la réponse avant l'examen.

Exemple concret :

❌ Colonne supprimée : "code_tarif_applique"
   → Cette colonne EST la gamme, formulée différemment.
   → Un modèle entraîné avec elle aurait 99% de précision... mais ne prédirait rien de réel.

✅ Colonne conservée : "puissance_souscrite_kva"
   → C'est une caractéristique physique du client, observable AVANT de connaître sa gamme.

Leçon clé : Un bon modèle doit apprendre à partir d'informations qui existeraient dans un cas réel AVANT de connaître la réponse.

2. Le déséquilibre des classes

Certaines gammes ont des milliers de clients, d'autres en ont quelques dizaines. Un modèle naïf "apprend" à toujours prédire la classe majoritaire et obtient une précision apparente élevée — mais échoue sur les classes rares.

3. Les données hétérogènes

Le fichier source mélange : variables numériques continues, variables catégorielles, variables ordinales, valeurs manquantes. Un pipeline de prétraitement robuste est indispensable.


Méthodes

Pipeline sklearn complet

Le cœur du projet est un pipeline scikit-learn qui enchaîne toutes les étapes de manière reproductible et sans fuite :

from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OrdinalEncoder
from sklearn.impute import SimpleImputer
from sklearn.ensemble import HistGradientBoostingClassifier

# Étape 1 : Prétraitement séparé par type de variable
preprocessor = ColumnTransformer([
    ("num", Pipeline([
        ("imputer", SimpleImputer(strategy="median")),
        ("scaler", StandardScaler())
    ]), colonnes_numeriques),
    ("cat", Pipeline([
        ("imputer", SimpleImputer(strategy="most_frequent")),
        ("encoder", OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=-1))
    ]), colonnes_categorielles),
])

# Étape 2 : Classification
pipeline = Pipeline([
    ("preprocessor", preprocessor),
    ("classifier", HistGradientBoostingClassifier(
        max_iter=300,
        learning_rate=0.05,
        max_leaf_nodes=31,
        random_state=42
    ))
])

Pourquoi un pipeline ? Un pipeline garantit que le prétraitement (scaling, encodage) est appris uniquement sur les données d'entraînement et appliqué de manière identique sur les données de test. Sans pipeline, on risque la fuite de données.

HistGradientBoostingClassifier — Le modèle choisi

Intuition : Imaginez un jury de 300 experts qui votent en séquence. Chaque expert se spécialise sur les erreurs des précédents. Le résultat final est le consensus pondéré de tous.

Avantages pour ce projet :

  • Gère nativement les valeurs manquantes (pas besoin d'imputation)
  • Très efficace sur les données tabulaires hétérogènes
  • Moins sujet au surapprentissage que Random Forest sur des petits jeux de données
  • Rapide à entraîner même avec 300 estimateurs

Optimisation des hyperparamètres — GridSearchCV

from sklearn.model_selection import GridSearchCV

param_grid = {
    "classifier__max_iter": [100, 200, 300],
    "classifier__learning_rate": [0.01, 0.05, 0.1],
    "classifier__max_leaf_nodes": [15, 31, 63],
}

grid_search = GridSearchCV(
    pipeline,
    param_grid,
    cv=5,           # Validation croisée 5-fold
    scoring="balanced_accuracy",  # Adaptée au déséquilibre des classes
    n_jobs=-1       # Tous les cœurs CPU en parallèle
)

Pourquoi balanced_accuracy ? Avec des classes déséquilibrées, l'accuracy classique est trompeuse. La balanced accuracy donne le même poids à chaque classe, indépendamment de son effectif.

Étalonnage des probabilités (ECE — Expected Calibration Error)

Un modèle peut prédire "80% de chances d'être en gamme HTA" et se tromper 40% du temps. L'étalonnage corrige cette discordance.

from sklearn.calibration import CalibratedClassifierCV

calibrated_model = CalibratedClassifierCV(best_model, method="isotonic", cv=5)

Utilité pratique : les probabilités étalonnées permettent d'appliquer un seuil d'abstention τ — si le modèle n'est pas confiant à plus de τ%, il refuse de prédire plutôt que de risquer une erreur.

Interprétabilité — Valeurs SHAP

import shap

explainer = shap.TreeExplainer(best_model["classifier"])
shap_values = explainer.shap_values(X_test_transformed)
shap.summary_plot(shap_values, X_test_transformed)

Ce que SHAP apporte : pour chaque prédiction, SHAP explique quelle variable a le plus influencé la décision et dans quel sens. Un chargé de clientèle peut vérifier que la décision du modèle est cohérente avec son expertise métier.


Résultats

Métrique Valeur Interprétation
Précision globale 91 % 91 % des consommateurs correctement classés
Balanced Accuracy > 88 % Performance stable même sur les classes minoritaires
Proba max médiane > 0.82 Le modèle est confiant dans la majorité des cas
Couverture (seuil τ=0.5) > 95 % Moins de 5 % de dossiers renvoyés pour révision manuelle

Artefacts de production exportés :

  • production_pipeline.joblib — pipeline complet prêt à l'emploi
  • input_schema.json — schéma de validation des données d'entrée
  • production_columns.json — liste et ordre des colonnes attendues
  • production_classes.json — mapping index → label de gamme

Ce que ces artefacts permettent :

import joblib
import pandas as pd

# Chargement en 2 lignes
pipeline = joblib.load("models/production_pipeline.joblib")
predictions = pipeline.predict(df_nouveaux_clients)
# → Retourne directement les gammes prédites

Valeur métier

Pourquoi est-ce utile ? Ce modèle transforme une tâche manuelle chronophage (plusieurs jours par lot) en une opération automatique de quelques secondes, quelle que soit la taille du lot.

Quelle décision cela améliore ? L'affectation tarifaire des consommateurs industriels — une décision qui engage des contrats de plusieurs années et des montants significatifs. Une erreur de gamme peut entraîner un litige contractuel, un écart de facturation ou une perte de client.

Quel gain cela produit ?

  • Réduction du temps de traitement d'un lot : de plusieurs jours à quelques secondes
  • Standardisation des décisions : mêmes règles appliquées à tous les dossiers
  • Traçabilité complète : chaque décision est accompagnée d'une probabilité et des variables explicatives (SHAP)

Quel risque cela réduit ?

  • Risque d'erreur humaine sur des portefeuilles de plusieurs milliers de clients
  • Risque de litige contractuel lié à une mauvaise affectation tarifaire
  • Risque de non-conformité réglementaire (les gammes tarifaires répondent à des obligations légales)

Quelle activité cela automatise ? La classification initiale des nouveaux clients et la révision périodique du portefeuille existant. L'application Streamlit permet aux équipes métier d'utiliser le modèle sans compétence technique.


Architecture du projet

classification-gamme-electrique/
│
├── ml_conso_elec.py                  # Script principal — pipeline complet
├── app.py                            # Application Streamlit (point d'entrée)
├── app_demo_gamme.py                 # Démo interactive Streamlit
│
├── models/
│   ├── production_pipeline.joblib    # Pipeline de production (artefact principal)
│   ├── predict_cli.py                # CLI batch pour prédictions en masse
│   └── app_streamlit.py              # Interface web utilisateur
│
├── reports/
│   ├── input_schema.json             # Schéma de validation des entrées
│   ├── production_columns.json       # Colonnes attendues par le pipeline
│   ├── production_classes.json       # Mapping index → gamme
│   ├── abstention_tradeoff.png       # Courbe précision/couverture
│   ├── abstention_sweep.csv          # Tableau des seuils testés
│   └── requirements.txt             # Dépendances exactes
│
├── data/
│   └── Liste_consommateurs_electriques_2016.xlsx   # Données source
│
├── requirements.txt
└── README.md

Guide d'utilisation

Installation

git clone https://github.com/TSAGUE25/classification-gamme-electrique.git
cd classification-gamme-electrique
pip install -r requirements.txt

Prédiction batch (ligne de commande)

python models/predict_cli.py \
  -i "votre_fichier_clients.csv" \
  -o "predictions_output.csv"

Colonnes de sortie :

  • y_pred : gamme prédite
  • proba_max : confiance du modèle (0 à 1)
  • Si proba_max < τ : dossier renvoyé en révision manuelle

Application Streamlit

streamlit run app.py

L'application permet de :

  1. Déposer un fichier CSV de clients
  2. Obtenir les prédictions avec probabilités
  3. Visualiser les variables les plus influentes (SHAP)
  4. Exporter les résultats

API FastAPI (optionnelle)

uvicorn server:app --host 0.0.0.0 --port 8000

# Prédire via API
curl -X POST "http://localhost:8000/predict" \
  -H "Content-Type: application/json" \
  -d '{"rows": [{"puissance_souscrite_kva": 250, "type_site": "industrie"}], "top_k": 3, "threshold": 0.80}'

Monitoring en production

À chaque lot traité, journaliser dans reports/batch_metrics_log.csv :

  • Taille du lot
  • Couverture après seuil τ
  • Score de Brier (qualité de calibration)
  • Balanced accuracy si labels disponibles

Alertes recommandées :

  • Brier > 0.4 → dégradation de la calibration
  • Couverture < couverture_référence - 10% → dérive des données d'entrée

Notions clés expliquées

Fuite de données (Data Leakage)

La fuite de données, c'est comme préparer un étudiant à un examen en lui donnant les réponses à l'avance. Il obtient 100%, mais ne sait rien faire dans un cas réel.

En Machine Learning : si les données d'entraînement contiennent des informations qui ne seraient pas disponibles au moment de la prédiction réelle, le modèle apprend à "tricher". Il obtient d'excellentes performances sur les données de test... mais échoue en production.

Comment détecter la fuite :

  1. Score anormalement élevé (>99%) sur une tâche difficile → suspicion
  2. Analyse des corrélations entre les features et la cible
  3. Suppression progressive des variables et mesure de l'impact sur le score

Dans ce projet : 38 colonnes supprimées après audit complet de chaque variable.

Pipeline sklearn anti-fuite

Un pipeline sklearn garantit que toutes les transformations (normalisation, encodage) sont apprises sur les données d'entraînement uniquement et appliquées à l'identique sur les données de test.

SANS pipeline (dangereux) :
  scaler.fit_transform(X_train + X_test) → le scaler "voit" les données de test ❌

AVEC pipeline (correct) :
  pipeline.fit(X_train) → apprend sur X_train uniquement
  pipeline.transform(X_test) → applique la transformation apprise ✅

Seuil d'abstention (τ)

Le modèle ne doit pas toujours trancher. Si sa confiance est faible, mieux vaut renvoyer le dossier à un expert humain.

τ = 0.80 :
  proba_max = 0.92 → Prédiction automatique (confiance élevée) ✅
  proba_max = 0.65 → Renvoi en révision manuelle (trop incertain) ⚠️

Stack technique

Catégorie Outil Usage
ML scikit-learn 1.3 Pipeline, ColumnTransformer, GridSearchCV
Modèle HistGradientBoostingClassifier Classification multiclasse
Calibration CalibratedClassifierCV Probabilités fiables
Interprétabilité SHAP Explication des prédictions
Sérialisation joblib Export du pipeline de production
Interface Streamlit Application web utilisateur
API FastAPI Endpoint REST pour intégration SI
Données pandas, numpy Manipulation et prétraitement

Auteur

Emmanuel TSAGUE
Ingénieur — EDF MAD EDVANCE
Formation Data Scientist — Datascientest 2024
GitHub : TSAGUE25


Projet EDF MAD EDVANCE — Classification automatique de consommateurs électriques industriels

About

Classification de consommateurs électriques pour l'affectation tarifaire — EDF MAD EDVANCE — Précision : 91%

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors