Chat
Ask me anything
Ithy Logo

Prédire Votre Consommation Électrique: Guide Complet de Régression Linéaire Multiple pour Séries Temporelles

Exploitez vos données univariées pour anticiper la semaine suivante avec Python et Scikit-learn, même avec un modèle simple.

predict-power-consumption-mlr-python-zzbut3n9

Vous disposez d'une série chronologique de valeurs de puissance normalisées (437 796 mesures jusqu'au 31 octobre 2023) et souhaitez prédire son évolution pour la semaine suivante en utilisant un modèle de Régression Linéaire Multiple (RLM) en Python. Même si vous considérez la RLM comme un modèle potentiellement "simple" ou "mauvais" pour une tâche complexe de séries temporelles, il est possible d'obtenir les prédictions les plus logiques et correctes possibles *dans le cadre de ce modèle* en suivant une approche structurée. Ce guide vous montrera comment transformer vos données univariées, créer des caractéristiques pertinentes et utiliser LinearRegression ou SGDRegressor de Scikit-learn pour atteindre votre objectif.


Points Clés à Retenir

  • Transformation Cruciale : La clé pour utiliser la RLM sur des données univariées est le "feature engineering" : créer des variables explicatives (régresseurs) à partir de la série elle-même (valeurs passées, indicateurs de temps).
  • Choix du Modèle : LinearRegression (Moindres Carrés Ordinaires) est simple et efficace pour des données modérées. SGDRegressor (Descente de Gradient Stochastique) est plus adapté aux très grands jeux de données mais nécessite un ajustement des hyperparamètres.
  • Logique vs Précision : Même un modèle "simple" peut fournir des prédictions "logiques" à court terme si les caractéristiques sont bien choisies. La RLM capture les relations linéaires basées sur les entrées fournies, mais peut avoir du mal avec des dynamiques non linéaires complexes ou des changements soudains. L'objectif est d'obtenir la meilleure prédiction possible *avec cet outil*.

Comprendre la Régression Linéaire Multiple (RLM) pour les Séries Temporelles

Adapter un Modèle Classique à des Données Séquentielles

La Régression Linéaire Multiple cherche à modéliser une variable dépendante (votre consommation électrique future) comme une combinaison linéaire de plusieurs variables indépendantes (les caractéristiques que vous allez créer). Le défi avec une série temporelle *univariée* est qu'à première vue, vous n'avez qu'une seule variable. La solution réside dans la création de nouvelles variables à partir de votre unique série de données.

L'Art du Feature Engineering Temporel

C'est l'étape la plus critique. Vous devez extraire des informations prédictives du passé et de la structure temporelle de vos données. Voici les types de caractéristiques les plus courants :

  • Valeurs Décalées (Lags) : La consommation d'aujourd'hui est souvent liée à celle d'hier, d'avant-hier, ou même de la semaine dernière à la même heure. Créer des variables comme power(t-1), power(t-24), power(t-168) (pour une granularité horaire, 168 = 24*7) permet au modèle de capturer cette auto-dépendance. Le choix des décalages pertinents est crucial et peut nécessiter une analyse exploratoire (fonctions d'autocorrélation).
  • Caractéristiques Saisonnières : La consommation électrique suit souvent des cycles journaliers, hebdomadaires ou annuels. Créez des variables pour représenter :
    • L'heure du jour (0-23)
    • Le jour de la semaine (0-6)
    • Le jour du mois (1-31)
    • Le mois de l'année (1-12)
    • Le trimestre
    • Indicateurs de jours fériés ou week-ends
    Ces variables aident le modèle à comprendre et à reproduire les motifs répétitifs.
  • Tendance (Trend) : Y a-t-il une augmentation ou une diminution générale de la consommation sur le long terme ? Une simple variable de temps (un compteur qui augmente) peut capturer une tendance linéaire. Des termes polynomiaux (temps au carré) peuvent capturer des tendances non linéaires simples.
Visualisation d'une série temporelle avec Power BI

Visualisation typique d'une série temporelle, illustrant potentiellement tendances et saisonnalités.

Choisir Votre Modèle : LinearRegression vs. SGDRegressor

Scikit-learn propose deux implémentations principales pour la RLM :

Modèle Algorithme Avantages Inconvénients Quand l'utiliser ?
LinearRegression Moindres Carrés Ordinaires (OLS) Simple à utiliser, pas d'hyperparamètres à régler (sauf normalisation), solution exacte. Peut être lent/gourmand en mémoire pour de très très grands jeux de données (calcule l'inverse d'une grande matrice). Sensible aux outliers. Taille de données modérée (vos ~440k points devraient être gérables), première approche, besoin d'une solution simple et interprétable.
SGDRegressor Descente de Gradient Stochastique (SGD) Efficace pour les très grands jeux de données (traite les données par lots), permet la régularisation (L1, L2, ElasticNet) pour éviter le surajustement, peut être mis à jour avec de nouvelles données (apprentissage en ligne). Nécessite un réglage des hyperparamètres (taux d'apprentissage, terme de régularisation, nombre d'itérations). Sensible à la mise à l'échelle des caractéristiques (StandardScaler est quasi obligatoire). Les résultats peuvent varier légèrement (nature stochastique). Très grands jeux de données, besoin de régularisation, apprentissage en ligne, prêt à investir du temps dans le réglage des hyperparamètres.

Pour votre cas, avec environ 440 000 points, LinearRegression est probablement un bon point de départ et pourrait être suffisamment performant. Si vous rencontrez des problèmes de mémoire ou si vous souhaitez explorer la régularisation, SGDRegressor est une alternative viable. Commencer par LinearRegression est souvent plus direct.


Mise en Œuvre en Python

De la Théorie à la Pratique avec Scikit-learn

Voici un exemple de code Python illustrant le processus complet : chargement des données, création des caractéristiques, entraînement du modèle LinearRegression, et prédiction pour la semaine suivante.


import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression # Ou SGDRegressor
# from sklearn.linear_model import SGDRegressor
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import StandardScaler
import warnings

# Ignorer les avertissements futurs pour la propreté de la sortie (optionnel)
warnings.simplefilter(action='ignore', category=FutureWarning)

# --- 1. Chargement et Préparation Initiale ---
# Supposons que vos données sont dans un fichier CSV 'power_data.csv'
# avec les colonnes 'timestamp' et 'normalized_power'
# Assurez-vous que 'timestamp' est parsé comme une date
try:
    # Adaptez le chemin et le format de votre fichier
    df = pd.read_csv('power_data.csv', parse_dates=['timestamp'], index_col='timestamp')
    # Assurez-vous que les données sont triées par date
    df.sort_index(inplace=True)
    # Renommer la colonne pour la clarté
    df.rename(columns={'normalized_power': 'power'}, inplace=True)
    # Vérifier la fréquence (ex: 10 minutes) - Adaptez si nécessaire
    # Si la fréquence n'est pas fixe, il faudra peut-être ré-échantillonner
    inferred_freq = pd.infer_freq(df.index)
    if inferred_freq is None:
        print("Attention: Fréquence non détectée. Assurez-vous que les données sont régulières.")
        # Option: Ré-échantillonner à une fréquence fixe, ex: '10T' pour 10 minutes
        # df = df.resample('10T').mean().interpolate() # Ou une autre méthode d'agrégation/interpolation
        # Pour cet exemple, nous supposons une fréquence fixe après chargement
    else:
        print(f"Fréquence détectée: {inferred_freq}")

except FileNotFoundError:
    print("Fichier 'power_data.csv' non trouvé. Création de données d'exemple.")
    # Création de données d'exemple si le fichier n'existe pas
    date_rng = pd.date_range(start='2022-01-01', end='2023-10-31 23:59:59', freq='10min') # Exemple de fréquence
    df = pd.DataFrame(date_rng, columns=['timestamp'])
    df['power'] = np.abs(np.random.randn(len(date_rng)) * 50 + 100 + np.sin(np.arange(len(date_rng)) * 0.1) * 20) # Données simulées avec bruit et saisonnalité simple
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    df = df.set_index('timestamp')
    inferred_freq = '10T' # Fréquence des données d'exemple

print(f"Données chargées : {df.shape[0]} lignes.")
print(df.head())

# Déterminer la fréquence en objet Timedelta pour les calculs de décalage
freq_timedelta = pd.to_timedelta(inferred_freq or '10min') # Utilise '10min' par défaut si non inféré

# --- 2. Feature Engineering ---
def create_features(df, power_col='power', lags=[1, 2, 3], seasonal_lags=[24*6, 24*6*7]):
    """Crée des caractéristiques temporelles et de décalage."""
    df_feat = df.copy()
    
    # Lags simples
    for lag in lags:
        df_feat[f'power_lag_{lag}'] = df_feat[power_col].shift(lag)
        
    # Lags saisonniers (basés sur la fréquence, ex: 24*6 pour 10min = 1 jour)
    for lag in seasonal_lags:
         df_feat[f'power_seasonal_lag_{lag}'] = df_feat[power_col].shift(lag)

    # Caractéristiques temporelles
    df_feat['hour'] = df_feat.index.hour
    df_feat['dayofweek'] = df_feat.index.dayofweek # Lundi=0, Dimanche=6
    df_feat['dayofyear'] = df_feat.index.dayofyear
    df_feat['month'] = df_feat.index.month
    df_feat['weekofyear'] = df_feat.index.isocalendar().week.astype(int)
    df_feat['time_trend'] = np.arange(len(df_feat)) # Tendance linéaire simple

    # Supprimer les lignes avec NaN introduits par les décalages
    df_feat.dropna(inplace=True)
    return df_feat

# Définir les décalages (lags) à créer
# Exemple : 1, 2, 3 pas précédents + lag journalier + lag hebdomadaire
# Adaptez ces valeurs en fonction de votre fréquence et de l'analyse de vos données !
steps_per_hour = pd.Timedelta('1h') / freq_timedelta
steps_per_day = int(24 * steps_per_hour)
steps_per_week = int(7 * steps_per_day)

lags_to_create = [1, 2, 3]
seasonal_lags_to_create = [steps_per_day, steps_per_week] # Lag journalier et hebdomadaire

df_features = create_features(df, lags=lags_to_create, seasonal_lags=seasonal_lags_to_create)

# Séparer X (caractéristiques) et y (cible)
X = df_features.drop('power', axis=1)
y = df_features['power']

# --- 3. Mise à l'échelle des caractéristiques (Important pour SGD, recommandé pour LinearRegression) ---
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Convertir X_scaled en DataFrame pour garder les noms de colonnes et l'index
X_scaled_df = pd.DataFrame(X_scaled, index=X.index, columns=X.columns)


# --- 4. Entraînement du Modèle ---
# Utiliser toutes les données jusqu'au 31 Oct 2023 pour l'entraînement final
# Pas de division train/test ici car on veut le modèle final pour prédire le futur.
# Pour une évaluation robuste, vous devriez normalement faire une division train/test temporelle.

# Option 1: LinearRegression
model = LinearRegression()
model.fit(X_scaled_df, y)
print("\nModèle LinearRegression entraîné.")

# Option 2: SGDRegressor (décommentez pour l'utiliser)
# model = SGDRegressor(max_iter=1000, tol=1e-3, random_state=42, eta0=0.01, penalty='l2', alpha=0.0001)
# model.fit(X_scaled_df, y)
# print("\nModèle SGDRegressor entraîné.")


# --- 5. Préparation pour la Prédiction Future ---
# Déterminer la période de prédiction : la semaine après le 31 Oct 2023
last_timestamp = df.index[-1]
prediction_start_date = last_timestamp + freq_timedelta
prediction_end_date = prediction_start_date + pd.Timedelta(weeks=1) - freq_timedelta # 1 semaine complète

# Créer l'index de temps pour la période de prédiction
future_index = pd.date_range(start=prediction_start_date, end=prediction_end_date, freq=inferred_freq)
print(f"\nPériode de prédiction : {prediction_start_date} à {prediction_end_date}")

# Créer un DataFrame pour les caractéristiques futures
# Nous avons besoin des dernières données d'entraînement pour calculer les premiers lags futurs
max_lag = max(lags_to_create + seasonal_lags_to_create)
last_known_data = df.iloc[-max_lag:] # Prendre suffisamment de données passées

# DataFrame temporaire pour construire les caractéristiques futures pas à pas
future_df_builder = pd.DataFrame(index=future_index)
future_df_builder['power'] = np.nan # La colonne 'power' sera prédite

# Combiner les dernières données connues avec le squelette futur
combined_df = pd.concat([last_known_data, future_df_builder])

# --- 6. Prédiction Itérative ---
# La RLM nécessite toutes les caractéristiques pour prédire. Comme les futurs lags dépendent
# des prédictions précédentes, nous devons prédire pas à pas.

predictions = []
current_data_for_features = combined_df.copy() # Travailler sur une copie

for current_timestamp in future_index:
    # 1. Créer les caractéristiques pour l'instant 'current_timestamp'
    #    Utilise les données jusqu'à l'instant précédent (y compris les prédictions précédentes)
    temp_features_df = create_features(current_data_for_features.loc[:current_timestamp], 
                                        lags=lags_to_create, 
                                        seasonal_lags=seasonal_lags_to_create)
                                        
    # Extraire la dernière ligne de caractéristiques (celle pour current_timestamp)
    # Vérifier si la ligne existe (peut être manquante au tout début si pas assez d'historique)
    if current_timestamp not in temp_features_df.index:
        print(f"Attention: Impossible de créer les features pour {current_timestamp}, historique insuffisant?")
        # Stratégie de secours: utiliser la dernière prédiction ou une valeur par défaut?
        # Pour cet exemple, on saute ou met NaN. Une gestion plus robuste est nécessaire.
        predicted_value = np.nan 
    else:
        current_X = temp_features_df.drop('power', axis=1).loc[[current_timestamp]]
        
        # 2. Mettre à l'échelle les caractéristiques avec le scaler entraîné
        current_X_scaled = scaler.transform(current_X) # Utiliser transform(), pas fit_transform()!
        
        # 3. Prédire la valeur
        predicted_value = model.predict(current_X_scaled)[0]
    
    # Stocker la prédiction
    predictions.append(predicted_value)
    
    # Mettre à jour la colonne 'power' dans notre DataFrame de construction
    # pour que cette prédiction soit utilisée pour calculer les lags futurs
    current_data_for_features.loc[current_timestamp, 'power'] = predicted_value

# Créer le DataFrame final des prédictions
predictions_df = pd.DataFrame({'predicted_power': predictions}, index=future_index)

print("\nPrédictions pour la semaine suivante :")
print(predictions_df.head())
print("...")
print(predictions_df.tail())

# --- 7. Visualisation (Optionnelle mais recommandée) ---
import matplotlib.pyplot as plt

plt.figure(figsize=(15, 7))
# Afficher les dernières données d'entraînement
plt.plot(df.index[-steps_per_week*2:], df['power'].iloc[-steps_per_week*2:], label='Données historiques récentes')
# Afficher les prédictions
plt.plot(predictions_df.index, predictions_df['predicted_power'], label='Prédictions RLM', color='red')
plt.title('Prédiction de la Consommation Électrique Normalisée')
plt.xlabel('Date')
plt.ylabel('Puissance Normalisée')
plt.legend()
plt.grid(True)
plt.show()


  

Explication du Code Détaillée

  1. Chargement : Charge les données depuis un CSV (ou crée des données d'exemple), s'assure que l'index est temporel et trié, et tente d'inférer la fréquence.
  2. Feature Engineering (`create_features`) : Une fonction crée les colonnes de lags (simples et saisonniers basés sur la fréquence détectée) et les caractéristiques temporelles (heure, jour, mois, etc.). Les lignes avec des `NaN` dus aux décalages initiaux sont supprimées pour l'entraînement.
  3. Mise à l'échelle : `StandardScaler` est utilisé pour normaliser les caractéristiques (moyenne=0, écart-type=1). C'est crucial pour `SGDRegressor` et souvent bénéfique pour `LinearRegression`. Le `scaler` est "entraîné" (`fit_transform`) sur les données d'entraînement.
  4. Entraînement : Le modèle choisi (`LinearRegression` ou `SGDRegressor`) est entraîné sur l'ensemble des caractéristiques mises à l'échelle (`X_scaled_df`) et la variable cible (`y`).
  5. Préparation Future : Définit l'index temporel pour la semaine de prédiction. Crée un DataFrame temporaire (`combined_df`) qui inclut les dernières données d'entraînement (nécessaires pour calculer les premiers lags futurs) et le squelette de la période future.
  6. Prédiction Itérative : C'est la partie délicate. Comme les caractéristiques futures (en particulier les lags de `power`) dépendent des valeurs futures inconnues de `power`, on prédit pas à pas :
    • Pour chaque instant de la semaine future :
    • On utilise la fonction `create_features` sur les données connues *jusqu'à cet instant* (y compris les prédictions déjà faites pour les instants précédents).
    • On extrait la ligne de caractéristiques pour l'instant courant.
    • On met à l'échelle ces caractéristiques avec le `scaler` déjà entraîné (`transform`).
    • On fait la prédiction pour cet instant.
    • On stocke cette prédiction et on l'ajoute au DataFrame (`current_data_for_features`) pour qu'elle soit utilisée dans le calcul des caractéristiques des instants suivants.
  7. Résultats et Visualisation : Les prédictions sont stockées dans un DataFrame et affichées. Une visualisation compare les prédictions aux dernières données historiques.

Visualisation du Processus et Comparaison des Modèles

Cartographie du Flux de Travail

Cette carte mentale résume les étapes clés du processus de prédiction de séries temporelles avec la RLM que nous avons décrit :

mindmap root["Prédiction de Séries Temporelles avec RLM"] id1["1. Données"] id1_1["Chargement (CSV, DB...)"] id1_2["Nettoyage (NaNs, outliers?)"] id1_3["Index Temporel (DateTimeIndex)"] id1_4["Tri Chronologique"] id1_5["Vérification Fréquence"] id2["2. Feature Engineering (Crucial)"] id2_1["Lags (Décalages)"] id2_1_1["Simples (t-1, t-2...)"] id2_1_2["Saisonniers (t-jour, t-semaine...)"] id2_2["Caractéristiques Temporelles"] id2_2_1["Heure, Jour Semaine/Année"] id2_2_2["Mois, Trimestre"] id2_2_3["Indicateurs (Weekend, Férié)"] id2_3["Tendance (Trend)"] id2_3_1["Compteur Linéaire"] id2_3_2["Termes Polynomiaux"] id2_4["Suppression NaN initiaux"] id3["3. Préparation Modèle"] id3_1["Séparation X / y"] id3_2["Mise à l'Échelle (Scaler)"] id3_2_1["StandardScaler (recommandé)"] id3_2_2["Fit sur Train, Transform sur Train/Test/Futur"] id3_3["Division Train / Test (Optionnel pour évaluation)"] id4["4. Choix & Entraînement Modèle"] id4_1["LinearRegression (OLS)"] id4_1_1["Simple, pas d'hyperparamètres"] id4_2["SGDRegressor (Gradient Descent)"] id4_2_1["Grands datasets, Régularisation"] id4_2_2["Réglage Hyperparamètres (taux, alpha...)"] id4_3["Entraînement: model.fit(X_train_scaled, y_train)"] id5["5. Prédiction Future (Itérative)"] id5_1["Définir Période Future"] id5_2["Boucle sur chaque pas de temps futur"] id5_2_1["Créer Features pour l'instant t"] id5_2_2["(Utilise prédictions t-1, t-2...)"] id5_2_3["Scaler les Features (transform)"] id5_2_4["Prédire valeur pour t: model.predict()"] id5_2_5["Stocker prédiction & mettre à jour historique"] id6["6. Évaluation & Analyse"] id6_1["Métriques (RMSE, MAE, MAPE) sur Test Set"] id6_2["Visualisation (Historique vs Prédictions)"] id6_3["Analyse des Résidus (Autocorrélation?)"]

Cette structure met en évidence la dépendance de chaque étape par rapport à la précédente, soulignant l'importance du feature engineering et de la boucle de prédiction itérative pour générer des prévisions futures.

Comparaison Qualitative : LinearRegression vs. SGDRegressor

Le graphique radar suivant offre une comparaison qualitative des deux modèles sur des aspects clés pour la prévision de séries temporelles, basée sur leurs caractéristiques générales. Les scores sont sur une échelle indicative où plus élevé est généralement mieux (sauf pour le coût computationnel).

Ce radar illustre les compromis : `LinearRegression` brille par sa simplicité et son interprétabilité, tandis que `SGDRegressor` offre une meilleure scalabilité et des options de régularisation, au prix d'un réglage plus complexe.


Approfondir : Vidéo Explicative

Comprendre la Saisonnalité en Régression Multiple

La vidéo suivante (en anglais) explique comment intégrer la saisonnalité dans un modèle de régression multiple pour la prévision de séries temporelles. Bien que l'outil utilisé puisse différer, les concepts de création de variables indicatrices (dummy variables) pour les mois ou les jours sont directement applicables à notre approche avec Python et Scikit-learn. Comprendre comment modéliser explicitement ces cycles est essentiel pour améliorer la logique des prédictions de votre modèle RLM.

Cette vidéo montre comment, en ajoutant des variables qui capturent les motifs saisonniers (par exemple, une variable pour chaque mois, ou des termes sinusoïdaux/cosinusoïdaux), un modèle de régression linéaire peut apprendre à reproduire ces fluctuations périodiques, rendant les prédictions futures plus plausibles et "logiques", même si le modèle sous-jacent reste linéaire.


Limitations et "Logique" des Prédictions

Gérer les Attentes d'un Modèle RLM

Vous avez mentionné que le modèle pourrait être "mauvais". Il est important de comprendre pourquoi et comment obtenir les résultats "les plus logiques" malgré cela :

  • Hypothèses de la RLM : La RLM classique suppose l'indépendance et l'homoscédasticité (variance constante) des erreurs (résidus). Dans les séries temporelles, les erreurs sont souvent autocorrélées (l'erreur d'aujourd'hui dépend de celle d'hier) et la variance peut changer (hétéroscédasticité). La violation de ces hypothèses n'empêche pas la prédiction mais peut affecter la fiabilité des intervalles de confiance et des tests statistiques sur les coefficients.
  • Linéarité : La RLM capture uniquement les relations linéaires entre les caractéristiques créées et la cible. Si la dynamique réelle de votre consommation électrique est fortement non linéaire, la RLM aura du mal à la modéliser parfaitement.
  • Stationnarité : Idéalement, la relation entre vos variables devrait être stable dans le temps. Si votre série présente une tendance forte ou une saisonnalité qui évolue, un modèle RLM simple pourrait ne pas s'adapter correctement sur le long terme. Le feature engineering (variables de tendance, saisonnalité) aide à atténuer ce problème.
  • Qualité du Feature Engineering : Les prédictions "logiques" dépendent ENORMEMENT de la pertinence des caractéristiques que vous créez. Si vous omettez un lag important ou un cycle saisonnier clé, le modèle ne pourra pas les apprendre et les prédire. C'est là que réside la plus grande partie du travail pour améliorer un modèle RLM sur des séries temporelles.
  • Horizon de Prédiction : Les modèles basés sur des lags récents fonctionnent généralement mieux à court terme. Prédire une semaine entière est possible, mais l'incertitude et l'erreur potentielle augmentent avec l'horizon de prédiction, car les erreurs de prédiction se propagent dans le calcul des lags futurs.

Pour obtenir les prédictions "les plus logiques" :

  1. Investissez dans le Feature Engineering : Analysez vos données (graphiques, autocorrélation) pour identifier les lags et cycles pertinents.
  2. Validez Visuellement : Comparez les prédictions aux données historiques. Suivent-elles la tendance générale et les motifs saisonniers ?
  3. Soyez Conscient des Limites : Ne vous attendez pas à une précision parfaite, surtout si la série est très volatile ou subit des changements brusques non capturés par les caractéristiques. L'objectif est une prédiction *directionnellement correcte* et *saisonnièrement cohérente* basée sur les informations fournies au modèle.

FAQ : Questions Fréquentes

Comment choisir les bons lags (décalages) ? +

Dois-je rendre ma série stationnaire avant d'utiliser la RLM ? +

Comment gérer l'autocorrélation des résidus ? +

SGDRegressor demande beaucoup de réglages, par où commencer ? +


Recommandations pour Aller Plus Loin

Explorer d'autres approches et affiner votre modèle


Références

Sources et Lectures Complémentaires

stat.ethz.ch
HTTP redirect

Last updated April 29, 2025
Ask Ithy AI
Download Article
Delete Article