⚡ Consommation énergétique des bâtiments — Seattle (CatBoost multi-cible)
Projet de formation AI Engineer (OpenClassrooms) — P5 — Déployez un modèle de Machine Learning, réalisé par William Derue.
Deux régresseurs CatBoost entraînés sur le jeu de données ouvert de la ville de Seattle, qui prédisent la consommation d'énergie et les émissions de gaz à effet de serre d'un bâtiment à partir de ses 17 caractéristiques.
🎓 Projet de formation « AI Engineer »
| Formation | AI Engineer — OpenClassrooms (parcours) |
| Étape du projet | P5 — Déployez un modèle de Machine Learning |
| Auteur | William Derue |
| Client fictif | Futurisys |
| Code source | github.com/WillIsback/OC-P5_Deployez_un_modele_de_Machine_Learning |
| Démo en ligne | Space Hugging Face — interface Gradio (johndoe / secret) |
| MLflow run | 9c4a71a8c47e4f0fa4bbebf320e51ede |
Ce dépôt ne contient que le modèle entraîné. Tout le reste du projet (service d'API FastAPI, base PostgreSQL, ingestion des données, suivi MLflow, supervision Grafana, interface Gradio, CI/CD et sécurité) vit dans le dépôt GitHub.
🎯 Contexte et problématique
Le Buildings Performance Alliance publie chaque année, pour chaque bâtiment non résidentiel de Seattle, la consommation d'énergie et les émissions constatées. Cette publication sert d'abord d'inventaire : elle identifie les bâtiments les plus énergivores, mais elle est produite avec un an ou deux de retard et ne permet pas encore d'anticiper la performance d'un bâtiment rénové ou d'un nouveau programme immobilier.
La question posée est donc : peut-on estimer la consommation et les émissions d'un bâtiment à partir de sa seule morphologie, avant que la mesure ne soit disponible ?
C'est un problème de régression tabulaire multi-sortie : une seule ligne de 17 features, deux cibles numériques, toutes deux fortement asymétriques (quelques ordres de grandeur entre le plus petit et le plus grand bâtiment).
Le parti pris du projet
Le modèle ne sert pas à vérifier une facture, mais à donner un ordre de grandeur avant mesure. C'est ce que dit la métrique de sélection : MedAPE (erreur absolue en pourcentage médiane), robuste aux valeurs extrêmes, plutôt que la MAE ou le R², qui sont toutes deux dominées par une poignée de très grands bâtiments.
📊 Données
Source : Building Energy Benchmarking Data — Seattle Office of Sustainability & Office of Energy & Environment, data.seattle.gov.
| Année | Rôle | Lignes dans le périmètre |
|---|---|---|
| 2016 | Entraînement (split 80 / 20) | 1 668 |
| 2017 → 2019 | Bâtiments jamais vus (démonstration) | 238 consultables |
Le périmètre du modèle exclut le résidentiel (Multifamily*) et toute ligne
comportant une feature obligatoire manquante. Les années 2017 à 2019 sont publiées
dans un format différent de 2016 (renommage de colonnes, EPAPropertyType,
regroupement des BuildingType) : elles sont réalignées sur le schéma 2016 par une
couche d'harmonisation avant tout traitement.
Les 17 features
| # | Feature | Type | Rôle |
|---|---|---|---|
| 1 | BuildingType |
catégorielle | grand type de bâtiment |
| 2 | PrimaryPropertyType |
catégorielle | usage principal (EPA) |
| 3 | Neighborhood |
catégorielle | quartier |
| 4 | Latitude / 5. Longitude |
numérique | localisation |
| 6 | YearBuilt |
numérique | année de construction |
| 7 | NumberofBuildings |
numérique | nombre de bâtiments du site |
| 8 | NumberofFloors |
numérique | étages |
| 9 | PropertyGFAParking |
numérique | surface de parking |
| 10 | PropertyGFABuilding(s) |
numérique | surface bâtie |
| 11 | LargestPropertyUseType |
catégorielle | 1ᵉʳ usage |
| 12 | SecondLargestPropertyUseType + 13. sa surface |
mixte | 2ᵉ usage |
| 14 | ThirdLargestPropertyUseType + 15. sa surface |
mixte | 3ᵉ usage |
| 16 | Has_NaturalGas |
flag 0/1 | NaturalGas(kBtu) > 0 |
| 17 | Has_Steam |
flag 0/1 | SteamUse(kBtu) > 0 |
Les 6 catégorielles manquantes sont remplacées par "UNKNOWN" ; les numériques
restent NaN, ce que CatBoost traite nativement.
Prétraitement
Aucune transformation n'est appliquée aux features — pas de log, pas de ratio,
pas d'imputation. Les deux seules opérations sont la normalisation du quartier et
le passage de NumberofBuildings == 0 à 1. Les deux cibles en revanche sont
entraînées sur log1p(y), et la prédiction est repassée en unités réelles par
expm1 à l'inférence.
📈 Métriques
Évaluation sur le split test de l'année d'entraînement (310 bâtiments de 2016, jamais vus à l'entraînement), en unités réelles.
| Cible | Modèle | R² | MAE | MedAE | MedAPE |
|---|---|---|---|---|---|
| Énergie (kBtu/an) | CatBoost | 0,236 | 5 171 124 | 857 047 | 35,0 % |
| Énergie (kBtu/an) | Kumo-Tabular (zero-shot) | 0,447 | 4 710 104 | 883 031 | 35,1 % |
| Émissions (t CO2e/an) | CatBoost | 0,106 | 146 | 19,0 | 43,7 % |
| Émissions (t CO2e/an) | Kumo-Tabular (zero-shot) | 0,207 | 137 | 24,2 | 48,3 % |
Lecture honnête de ces chiffres
Le modèle est modeste, et il faut le dire.
- Le R² de 0,24 (énergie) et 0,11 (émissions) paraît faible. Il ne faut pas y lire un échec du modèle : le R² est calculé sur des valeurs réelles très asymétriques, quelques bâtiments très extrêmes écrivent à eux seuls la majeure partie de la variance. Le MedAPE — la métrique de sélection retenue par le projet — est de 35 % : l'erreur typique est d'un facteur ~1,5, ce qui est cohérent avec un usage de fourchette.
- Sur les émissions, l'écart est plus net (43,7 %). Le signal est plus faible : les émissions dépendent surtout du mix énergétique et du combustible. Les features n'en donnent que la présence (gaz naturel, vapeur), pas la part.
- Kumo-Tabular, le modèle de fondation tabulaire de NVIDIA utilisé sans entraînement, affiche un meilleur R² et une meilleure MAE sur les deux cibles, à MedAPE comparable sur l'énergie. Les expériences de la section suivante montrent que cet écart tient à un ou deux bâtiments extrêmes et n'est pas statistiquement significatif.
Ce que cela dit de l'usage
Une erreur médiane d'un tiers interdit toute automatisation de décision énergétique (déclencher des travaux, certifier une performance). L'usage réaliste est un ordre de grandeur : comparer deux scénarios, vérifier qu'un bâtiment ne sort pas de la norme, préremplir une étude de faisabilité — toujours avec un contrôle métrologique avant toute communication.
🔬 Comparaison avec Kumo-Tabular
Le projet compare ce CatBoost à nvidia/Kumo-Tabular, un modèle de fondation tabulaire qui prédit par in-context learning : il ne s'entraîne pas, il reçoit à chaque appel des exemples étiquetés (le contexte, ici exactement le jeu d'entraînement de CatBoost). Quatre expériences complètent les scores ci-dessus. Le détail est dans l'article « Prédire sans entraîner ».
| Question | Résultat |
|---|---|
| L'écart de R² est-il significatif ? | Non. Bootstrap apparié (2 000 tirages) : écart de R² énergie entre −0,23 et +0,52 (IC 95 %). Un bâtiment porte 65 à 76 % de l'erreur quadratique ; sans le site industriel et le data center du test, CatBoost repasse devant (R² 0,58 contre 0,53). |
| Kumo est-il stable ? | Son inférence est aléatoire : R² énergie de 0,42 à 0,46 selon la graine, contexte identique. |
| Que se passe-t-il avec plus ou moins de données (100 → 4 700 lignes) ? | Kumo garde le meilleur R², mais CatBoost a la meilleure erreur médiane avec peu de données (émissions à 100 lignes : 55 % contre 71 %). Kumo plafonne dès 1 236 lignes. |
| Combien coûte une prédiction ? | CPU, 4 threads : 0,8 ms pour CatBoost, ~25 s pour Kumo, quel que soit le nombre de lignes prédites dans l'appel (1 000 lignes : 42,5 s). La durée croît linéairement avec la taille du contexte. |
| Sur quoi s'appuient les modèles ? | Importance par permutation : surface bâtie puis usage pour les deux ; CatBoost lit PrimaryPropertyType, Kumo LargestPropertyUseType. Sur les émissions, Has_NaturalGas arrive juste après la surface. |
Pour un ordre de grandeur sur un bâtiment typique, ce qui est l'usage visé, ce CatBoost reste le modèle servi : il est au moins aussi précis en MedAPE, et environ 30 000 fois plus rapide à l'unité.
🚀 Utilisation
import json
import numpy as np
import pandas as pd
from catboost import CatBoostRegressor
from huggingface_hub import hf_hub_download
repo = "Willisback/seattle-energy-catboost"
config = json.load(open(hf_hub_download(repo, "config.json", repo_type="model")))
FEATURES = config["feature_columns"]
CATS = config["cat_features"]
# Une ligne du jeu de données, au format du CSV Seattle 2016.
row = pd.DataFrame([{
"BuildingType": "SPS-District K-12",
"PrimaryPropertyType": "K-12 School",
"Neighborhood": "SOUTHEAST",
"Latitude": 47.54576,
"Longitude": -122.26853,
"YearBuilt": 1961,
"NumberofBuildings": 1,
"NumberofFloors": 2,
"PropertyGFAParking": 0,
"PropertyGFABuilding(s)": 56228,
"LargestPropertyUseType": "K-12 School",
"SecondLargestPropertyUseType": "UNKNOWN",
"SecondLargestPropertyUseTypeGFA": np.nan,
"ThirdLargestPropertyUseType": "UNKNOWN",
"ThirdLargestPropertyUseTypeGFA": np.nan,
"Has_NaturalGas": 1,
"Has_Steam": 0,
}])
# Catégorielles : aucune valeur manquante ne doit atteindre CatBoost.
for col in CATS:
row[col] = row[col].astype("string").fillna("UNKNOWN").astype(str)
row = row[FEATURES]
energy = CatBoostRegressor()
energy.load_model(hf_hub_download(repo, "data/energy.cbm", repo_type="model"))
print(np.expm1(energy.predict(row))[0])
# 3088219.812954494 kBtu/an
⚠️ L'ordre des colonnes est significatif. Les
.cbmembarquent leur proprefeature_names_, mais il doit correspondre àFEATURESci-dessus. La transformationexpm1est obligatoire : le modèle préditlog1p(y).
📁 Contenu du dépôt
| Fichier | Rôle |
|---|---|
config.json |
contrat d'inférence : features, catégorielles, hyperparamètres, prétraitement |
data/energy.cbm |
régresseur énergie (299 arbres) |
data/emissions.cbm |
régresseur émissions (813 arbres) |
data/scores.json |
métriques de validation, par cible et par modèle |
data/scores.csv |
mêmes métriques, à plat |
data/version.json |
version servie et mlflow_run_id |
⚖️ Limites connues
- Un seul climat, une seule ville, une seule année d'entraînement (Seattle, 2016). Aucune généralisation à d'autres climates n'a été testée.
- Pas d'incertitude prédictive : le modèle renvoie un point, sans intervalle. Sur des données aussi asymétriques, un intervalle serait plus utile qu'un point.
- Pas d'explicabilité par building au-delà des importances de features globales : la surface bâtie et l'usage du bâtiment dominent, le raccordement au gaz pèse sur les émissions, le quartier presque pas.
- La moitié du parc n'est pas couverte : 1 668 des 3 376 lignes de 2016 seulement entrent dans le périmètre (hors résidentiel, features obligatoires complètes).
📄 Licence et provenance
Code et modèle : MIT. Données d'origine : Seattle Building Energy Benchmarking Data, open data sous CC BY 4.0.
- Downloads last month
- 21