Accéder au contenu principal

Moyennes mobiles avec pandas

Apprenez à capter les tendances et à interpréter des séries temporelles grâce aux moyennes mobiles (glissantes).
Actualisé 19 sept. 2026  · 8 min lire

Explorer avec l’IA

ChatGPTClaudePerplexity

Introduction

Une moyenne mobile, aussi appelée moyenne glissante ou roulante, sert à analyser des séries temporelles en calculant des moyennes de différents sous-ensembles d'un jeu de données. Comme elle consiste à prendre la moyenne des données au fil du temps, on parle également de moyenne mobile (MM) ou moyenne glissante.

Il existe plusieurs façons de calculer la moyenne glissante. L'une d'elles consiste à prendre un sous-ensemble de taille fixe d'une série de nombres. La première moyenne mobile est calculée en moyennant le premier sous-ensemble fixe, puis on avance à la fenêtre suivante (en incluant la valeur suivante et en excluant la valeur la plus ancienne).

La moyenne mobile est surtout utilisée avec des séries temporelles pour atténuer les fluctuations de court terme tout en faisant ressortir les tendances de fond.

Parmi les exemples de séries temporelles, on peut citer les cours de bourse, les relevés météo, la qualité de l'air, le produit intérieur brut, l'emploi, etc.

De manière générale, la moyenne mobile lisse les données.

La moyenne mobile est au cœur de nombreux algorithmes, notamment le modèle ARIMA (Autoregressive Integrated Moving Average), qui l'exploite pour prévoir des séries temporelles.

On distingue plusieurs types de moyennes mobiles :

  • Moyenne mobile simple (SMA) : la moyenne mobile simple utilise une fenêtre glissante pour calculer la moyenne sur un nombre défini de périodes. C'est une moyenne à poids égal des n dernières observations.

    Pour aller plus loin, prenons un exemple avec une séquence de n valeurs :

    sequence of n values

    la moyenne glissante pondérée à poids égal pour n points de données correspondra à la moyenne des M dernières valeurs, où M est la taille de la fenêtre glissante :

    simple moving average calculation 1

    De même, pour calculer les valeurs suivantes, on ajoute la nouvelle valeur à la somme et on retire la valeur la plus ancienne. Comme vous disposez déjà des moyennes des périodes précédentes, il n'est pas nécessaire de recalculer la somme complète à chaque fois :

    simple moving average calculation 2
  • Moyenne mobile cumulative (CMA) : contrairement à la moyenne mobile simple qui élimine l'observation la plus ancienne lorsque l'on ajoute une nouvelle valeur, la moyenne mobile cumulative prend en compte toutes les observations antérieures. La CMA n'est pas idéale pour analyser des tendances et lisser les données, car elle moyenne toutes les valeurs jusqu'au point courant. Ainsi, pour une moyenne à poids égal d'une séquence de n valeurs :
    sequence of n values 2
    jusqu'au temps courant, on obtient :
    cumulative moving average 1
    De même, la mise à jour de la moyenne cumulative à l'arrivée d'une nouvelle valeur peut se faire avec la formule suivante :
    cumulative moving average 2
  • Moyenne mobile exponentielle (EMA) : à la différence de la SMA et de la CMA, la moyenne mobile exponentielle accorde plus de poids aux observations récentes. Elle capte donc plus rapidement l'évolution de la tendance. La réaction de l'EMA est directement proportionnelle au motif de la série.

Puisque l'EMA met davantage l'accent sur les données récentes que sur les anciennes, elle réagit mieux aux variations les plus récentes que la SMA. Ses résultats sont donc plus réactifs, ce qui fait que l'EMA est souvent privilégiée.

Assez de théorie, non ? Passons à la mise en pratique de la moyenne mobile.

Mettre en œuvre une moyenne mobile sur des séries temporelles

Moyenne mobile simple (SMA)

Commençons par créer des données temporelles factices et implémenter une SMA uniquement avec Python.

Supposons qu'on observe la demande d'un produit sur 12 mois (1 an) et que vous deviez calculer des moyennes mobiles avec des fenêtres de 3 et 4 mois.

Importer les modules

import pandas as pd
import numpy as np
 
product = {'month' : [1,2,3,4,5,6,7,8,9,10,11,12],'demand':[290,260,288,300,310,303,329,340,316,330,308,310]}
df = pd.DataFrame(product)
df.head()
 

Exécutez et modifiez le code de ce tutoriel en ligne

Exécuter le code
  month demand
0 1 290
1 2 260
2 3 288
3 4 300
4 5 310

Calculons la SMA avec une fenêtre de 3 : vous prenez donc trois valeurs à chaque fois pour calculer la moyenne mobile, et à chaque nouvelle valeur, la plus ancienne est ignorée.

Pour l'implémenter, vous utiliserez la fonction iloc de pandas. Comme la colonne demand vous intéresse, vous fixez sa position dans iloc et laissez la ligne varier au moyen d'une variable i que vous ferez évoluer jusqu'à la fin du DataFrame.

for i in range(0,df.shape[0]-2):
    df.loc[df.index[i+2],'SMA_3'] = np.round(((df.iloc[i,1]+ df.iloc[i+1,1] +df.iloc[i+2,1])/3),1)
  month demand SMA_3
0 1 290 NaN
1 2 260 NaN
2 3 288 279.3
3 4 300 282.7
4 5 310 299.3

Pour vérifier, utilisons aussi la fonction native rolling de pandas et comparons avec notre moyenne mobile simple codée à la main.

df['pandas_SMA_3'] = df.iloc[:,1].rolling(window=3).mean()
df.head()
  month demand SMA_3 pandas_SMA_3
0 1 290 NaN NaN
1 2 260 NaN NaN
2 3 288 279.3 279.333333
3 4 300 282.7 282.666667
4 5 310 299.3 299.333333

Parfait ! Comme vous le voyez, les moyennes mobiles personnalisée et pandas coïncident, ce qui valide notre implémentation de la SMA.

Calculons aussi rapidement la moyenne mobile simple pour une window_size de 4.

for i in range(0,df.shape[0]-3):
    df.loc[df.index[i+3],'SMA_4'] = np.round(((df.iloc[i,1]+ df.iloc[i+1,1] +df.iloc[i+2,1]+df.iloc[i+3,1])/4),1)
df.head()
  month demand SMA_3 pandas_SMA_3 SMA_4
0 1 290 NaN NaN NaN
1 2 260 NaN NaN NaN
2 3 288 279.3 279.333333 NaN
3 4 300 282.7 282.666667 284.5
4 5 310 299.3 299.333333 289.5
df['pandas_SMA_4'] = df.iloc[:,1].rolling(window=4).mean()
df.head()
  month demand SMA_3 pandas_SMA_3 SMA_4 pandas_SMA_4
0 1 290 NaN NaN NaN NaN
1 2 260 NaN NaN NaN NaN
2 3 288 279.3 279.333333 NaN NaN
3 4 300 282.7 282.666667 284.5 284.5
4 5 310 299.3 299.333333 289.5 289.5

Représentons maintenant les moyennes mobiles calculées.

import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=[15,10])
plt.grid(True)
plt.plot(df['demand'],label='data')
plt.plot(df['SMA_3'],label='SMA 3 Months')
plt.plot(df['SMA_4'],label='SMA 4 Months')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x11fe15080>
calculated moving averages line graph

Moyenne mobile cumulative

Je pense que nous sommes prêts à passer à un jeu de données réel.

Pour la moyenne mobile cumulative, utilisons un jeu de données sur la qualité de l'air que vous pouvez télécharger via ce lien.

df = pd.read_csv("AirQualityUCI/AirQualityUCI.csv", sep = ";", decimal = ",")
df = df.iloc[ : , 0:14]
df.head()
  Date Time CO(GT) PT08.S1(CO) NMHC(GT) C6H6(GT) PT08.S2(NMHC) NOx(GT) PT08.S3(NOx) NO2(GT) PT08.S4(NO2) PT08.S5(O3) T RH
0 10/03/2004 18.00.00 2.6 1360.0 150.0 11.9 1046.0 166.0 1056.0 113.0 1692.0 1268.0 13.6 48.9
1 10/03/2004 19.00.00 2.0 1292.0 112.0 9.4 955.0 103.0 1174.0 92.0 1559.0 972.0 13.3 47.7
2 10/03/2004 20.00.00 2.2 1402.0 88.0 9.0 939.0 131.0 1140.0 114.0 1555.0 1074.0 11.9 54.0
3 10/03/2004 21.00.00 2.2 1376.0 80.0 9.2 948.0 172.0 1092.0 122.0 1584.0 1203.0 11.0 60.0
4 10/03/2004 22.00.00 1.6 1272.0 51.0 6.5 836.0 131.0 1205.0 116.0 1490.0 1110.0 11.2 59.6

Le prétraitement est une étape essentielle lorsque vous travaillez avec des données. Pour les données numériques, l'une des premières vérifications consiste à détecter les valeurs NaN (Null). En présence de NaN, vous pouvez les remplacer par 0, par la moyenne, par la valeur précédente ou suivante, ou encore les supprimer. Même si remplacer est souvent préférable, ce jeu de données ne contient que peu de valeurs NULL et elles se situent en fin de série : les supprimer ne nuira pas à la continuité.

df.isna().sum()
Date             114
Time             114
CO(GT)           114
PT08.S1(CO)      114
NMHC(GT)         114
C6H6(GT)         114
PT08.S2(NMHC)    114
NOx(GT)          114
PT08.S3(NOx)     114
NO2(GT)          114
PT08.S4(NO2)     114
PT08.S5(O3)      114
T                114
RH               114
dtype: int64

On observe environ 114 valeurs NaN dans toutes les colonnes, situées à la fin de la série : supprimons-les.

df.dropna(inplace=True)
df.isna().sum()
Date             0
Time             0
CO(GT)           0
PT08.S1(CO)      0
NMHC(GT)         0
C6H6(GT)         0
PT08.S2(NMHC)    0
NOx(GT)          0
PT08.S3(NOx)     0
NO2(GT)          0
PT08.S4(NO2)     0
PT08.S5(O3)      0
T                0
RH               0
dtype: int64

Nous allons appliquer la moyenne mobile cumulative à la colonne température (T). Séparons rapidement cette colonne du reste.

df_T = pd.DataFrame(df.iloc[:,-2])
df_T.head()
  T
0 13.6
1 13.3
2 11.9
3 11.0
4 11.2

Nous allons maintenant utiliser la méthode expanding de pandas pour obtenir la moyenne cumulative des données ci-dessus. Comme indiqué en introduction, à la différence de la moyenne mobile simple, la moyenne cumulative prend en compte toutes les valeurs précédentes.

df_T['CMA_4'] = df_T.expanding(min_periods=4).mean()
df_T.head(10)
  T CMA_4
0 13.6 NaN
1 13.3 NaN
2 11.9 NaN
3 11.0 12.450000
4 11.2 12.200000
5 11.2 12.033333
6 11.3 11.928571
7 10.7 11.775000
8 10.7 11.655556
9 10.3 11.520000

Les séries temporelles se tracent par rapport au temps. Fusionnons donc les colonnes de date et d'heure et convertissons le tout en objet datetime. Pour cela, nous utiliserons le module datetime de Python (Source : Time Series Tutorial).

import datetime

df['DateTime'] = (df.Date) + ' ' + (df.Time)
df.DateTime = df.DateTime.apply(lambda x: datetime.datetime.strptime(x, '%d/%m/%Y %H.%M.%S'))

Changeons l'index du DataFrame temperature avec ces datetimes.

df_T.index = df.DateTime

Traçons maintenant la température réelle et la moyenne mobile cumulative en fonction du temps.

plt.figure(figsize=[15,10])
plt.grid(True)
plt.plot(df_T['T'],label='temperature')
plt.plot(df_T['CMA_4'],label='CMA_4')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x1210a2d30>
time series data graph

Moyenne mobile exponentielle

df_T['EMA'] = df_T.iloc[:,0].ewm(span=40,adjust=False).mean()
df_T.head()
  T CMA_4 EMA
DateTime      
2004-03-10 18:00:00 13.6 NaN 13.600000
2004-03-10 19:00:00 13.3 NaN 13.585366
2004-03-10 20:00:00 11.9 NaN 13.503153
2004-03-10 21:00:00 11.0 12.45 13.381048
2004-03-10 22:00:00 11.2 12.20 13.274655
plt.figure(figsize=[15,10])
plt.grid(True)
plt.plot(df_T['T'],label='temperature')
plt.plot(df_T['CMA_4'],label='CMA_4')
plt.plot(df_T['EMA'],label='EMA')
plt.legend(loc=2)
<matplotlib.legend.Legend at 0x14b2a41d0>
time series data graph 2

Impressionnant ! Comme vous pouvez le voir sur le graphique ci-dessus, la moyenne mobile exponentielle (EMA) capture très bien le motif des données, alors que la moyenne mobile cumulative (CMA) est nettement en retrait.

Pour aller plus loin

Félicitations pour avoir terminé ce tutoriel.

Ce guide constitue un bon point de départ pour calculer des moyennes mobiles sur vos données et en tirer des enseignements.

Essayez d'écrire le code Python pour les moyennes mobiles cumulative et exponentielle sans utiliser la bibliothèque pandas. Vous comprendrez plus finement comment elles sont calculées et en quoi elles diffèrent.

Il reste encore beaucoup à expérimenter. Calculez, par exemple, la corrélation partielle entre les données d'entrée et la moyenne mobile, et tentez d'identifier des relations.

Pour en savoir plus sur les DataFrames dans pandas, suivez le cours interactif pandas Foundations de DataCamp.

Références :

N'hésitez pas à poser vos questions sur ce tutoriel dans les commentaires ci-dessous.

Sujets
Python
Visualisation des données
Analyse des données

Cours associés

Cours

Python intermédiaire

4 h
1.4M
Mettez à niveau vos compétences en science des données en créant des visualisations à l'aide de Matplotlib et en manipulant des DataFrame avec pandas.
Afficher les détailsRight Arrow
Commencer Le Cours
Voir plusRight Arrow