Séries temporelles avec pandas et matplotlib
En matière d’analyse de données, le langage Python est très bien équipé, avec des bibliothèques open source de grande qualité comme NumPy, pandas ou matplotlib. Dans cet article, je vais montrer comment utiliser ces bibliothèques pour manipuler et visualiser des séries temporelles.
Qu’est-ce qu’une série temporelle ?
Une série temporelle est simplement une suite de données associées à des dates (ou à des heures, selon la précision souhaitée). Quelques exemples typiques de séries temporelles:
- la température maximale quotidienne dans une ville
- le temps de réponse des requêtes HTTP traitées par un serveur web
- le cours de clôture d’une action en bourse
- la population d’un pays (mesurée chaque année par exemple)
L’intervalle entre deux points d’une série temporelle peut être fixe, comme dans le premier exemple (l’intervalle est toujours d’un jour), ou variable, comme dans le deuxième exemple (l’intervalle entre deux requêtes HTTP dépend du trafic du serveur).
Comme une série temporelle peut contenir beaucoup de points, il est généralement peu pratique de travailler directement sur ces données. On explore plutôt les séries temporelles de deux façons :
- L’extraction de statistiques, c’est-à-dire de nombres qui résument des caractéristiques importantes des données, comme la moyenne ou la dispersion (variance).
- La visualisation des données sous forme de graphes, d’histogrammes, de cartes de chaleur (heatmaps), de diagrammes, ou de toute autre représentation graphique qui aide à comprendre ce que représentent réellement les données.
Les deux peuvent se faire avec un tableur comme MS Excel, mais dès qu’on commence à manipuler de gros volumes de données avec des centaines de milliers de valeurs, passer à Python devient beaucoup plus pratique.
Présentation de NumPy, pandas et matplotlib

NumPy est le package fondamental du calcul scientifique en Python. C’est une bibliothèque qui offre des fonctions efficaces pour manipuler des vecteurs et des matrices, avec la facilité d’utilisation de Python et les performances du code C natif.
pandas est une bibliothèque d’analyse de données construite au-dessus de NumPy, performante et facile à utiliser. pandas fournit des fonctions pour lire facilement des données depuis des fichiers CSV, réorganiser les données, calculer des agrégats ou des statistiques, manipuler des séries temporelles, et bien plus encore.
matplotlib est une bibliothèque de tracé pour Python, capable de produire des graphiques de grande qualité de toutes sortes : histogrammes, courbes, histogrammes 2D, diagrammes, nuages de points, etc.
Ces bibliothèques fonctionnent très bien ensemble, et font d’ailleurs toutes partie de la pile SciPy, un ensemble de bibliothèques Python dédiées au calcul scientifique.
Si elles ne font pas partie de votre distribution Python, vous pouvez installer la dernière version de ces bibliothèques avec pip :
pip install numpy pandas matplotlib
En cas de problème, cherchez d’autres méthodes d’installation sur SciPy.org.
Tracer le cours de l’action Google
Voyons maintenant sur un exemple concret comment tracer le graphique suivant :

Ce graphique affiche le cours de clôture quotidien de l’action Google en bourse sur l’année écoulée, ainsi qu’une moyenne mobile sur 30 jours.
Voici le code Python utilisé pour produire ce graphique, grâce à pandas et matplotlib :
from datetime import datetime, timedelta
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.finance as finance
# Get Google stock price from Yahoo! Finance
end = datetime.now()
begin = end - timedelta(days=365)
with finance.fetch_historical_yahoo('GOOG', begin, end) as fh:
df = pd.read_csv(fh, parse_dates=True, index_col=0)
# Keep only the closing price, and sort by date
price = df['Close'].sort_index()
# Compute the 30-day moving average
price_avg = pd.rolling_mean(price, 30)
# Plot the stock price
price_plot = price.plot()
# And plot the average on the same graph, using a line width of 3
price_avg.plot(ax=price_plot, lw=3)
plt.title('Google Stock Price')
plt.show()
Bien qu’il paraisse assez simple, ce code mérite quelques explications.
matplotlib fournit une fonction intégrée pour récupérer l’historique des cours depuis Yahoo! Finance (ligne 9), qui renvoie un fichier CSV comme celui-ci :
Date,Open,High,Low,Close,Volume,Adj Close
2015-05-08,536.65002,541.15002,525.00,538.21997,1510700,538.21997
2015-05-07,523.98999,533.46002,521.75,530.70001,1546300,530.70001
2015-05-06,531.23999,532.38,521.08502,524.21997,1567000,524.21997
2015-05-05,538.21002,539.73999,530.39099,530.79999,1383100,530.79999
...
Grâce à la fonction pandas.read_csv, ce fichier CSV est directement transformé en un objet pandas appelé DataFrame, qui est un tableau indexé par lignes et par colonnes.
Si on affiche ce data frame (le contenu de la variable df), on obtient :
>>> df
Open High Low Close Volume Adj Close
Date
2015-05-08 536.65002 541.15002 525.00000 538.21997 1510700 538.21997
2015-05-07 523.98999 533.46002 521.75000 530.70001 1546300 530.70001
2015-05-06 531.23999 532.38000 521.08502 524.21997 1567000 524.21997
...
On voit que les colonnes ont été nommées automatiquement à partir de l’en-tête du fichier CSV, et que la date a été utilisée comme index des lignes (pandas l’a fait grâce au paramètre index_col=0).
Grâce à ces index, on peut accéder à une cellule du data frame comme ceci :
>>> df['2014-06-13']['Close']
Date
2014-06-13 551.76251
Name: Close, dtype: float64
Comme notre data frame est trié dans le mauvais sens, il faut appeler sort_index pour le trier par ordre chronologique.
Ensuite, pandas.rolling_mean calcule la moyenne mobile sur 30 jours et renvoie un autre data frame. C’est aussi simple que ça !
Il ne reste plus qu’à appeler la méthode plot sur nos data frames pour les tracer avec matplotlib, et le tour est joué !
Notez que plt.show() lance une visionneuse d’images directement depuis le programme. Si vous voulez enregistrer le graphique dans un fichier png, vous pouvez appeler plt.savefig(‘google.png’) à la place.
Tracer des données aléatoires
Voici maintenant un autre exemple montrant comment utiliser NumPy en combinaison avec pandas :
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Generate a series of 2000 dates, starting from 2015-01-01, with an interval
# of 1 hour
dates = pd.date_range('20150101', periods=2000, freq='1H')
# Generate a NumPy array of 2000 values, from a sinusoidal function
values = 2 * np.fromfunction(lambda i: np.sin(4*i/1000), (2000,))
# Add random values (with a gaussian distribution) to the previous array
values += np.random.normal(6, size=2000)
# Build a data frame associating the array of dates to the array of random
# values (indexed by dates). Give the "Value" name to the value column.
# The resulting data frame will look like:
# Value
#2015-01-01 00:00:00 5.790988
#2015-01-01 01:00:00 7.180237
#2015-01-01 02:00:00 5.248410
#2015-01-01 03:00:00 4.830652
#...
df = pd.DataFrame(values, index=dates, columns=['Value'])
# Compute the moving average on 48 hours
avg = pd.rolling_mean(df, 48)
# Plot the data frame in green. By default the legend is the name of
# the column (here "Value")
values_plot = df.plot(color='g')
# Plot the moving average on the same graph, in black
avg.plot(color='k', ax=values_plot, legend=0)
plt.show()
Ce programme génère une série temporelle de valeurs aléatoires centrées sur une sinusoïde, et trace la série avec sa moyenne mobile :

Tracer la fréquence d’apparition d’un événement
Il m’arrive très souvent de devoir tracer la fréquence d’apparition d’un événement donné sur une période, par exemple le nombre de requêtes par heure sur un serveur web.
Cela ressemble à un problème élémentaire, mais il est étonnamment difficile de trouver comment le faire simplement.
La première étape consiste à obtenir une série d’horodatages correspondant à l’événement que l’on veut compter. Supposons que ces horodatages soient stockés dans un fichier events.txt qui ressemble à ceci :
30/Apr/2015T06:25:06
30/Apr/2015T06:25:09
30/Apr/2015T06:25:09
30/Apr/2015T06:25:09
30/Apr/2015T06:25:10
...
29/Apr/2015T06:24:54
29/Apr/2015T06:24:57
29/Apr/2015T06:24:57
29/Apr/2015T06:24:58
L’objectif est maintenant de tracer le nombre d’événements par heure, comme ceci :

Voici un programme très simple utilisant pandas et matplotlib pour produire ce graphique :
import pandas as pd
import matplotlib.pyplot as plt
# Create a data frame from the file containing timestamps
# This data frame will look like:
# >>> df
# events
# 0 2015-04-30 06:25:06
# 1 2015-04-30 06:25:09
# 2 2015-04-30 06:25:09
# 3 2015-04-30 06:25:09
# ...
df = pd.read_csv('events.txt', header=None, parse_dates={'events': [0]})
# Aggregate number of events per hour, and plot the result
df.events.value_counts().resample('1h', how=sum).plot()
plt.show()
Alors, comment ça marche ?
Le data frame renvoyé par read_csv a une seule colonne de valeurs, que nous avons nommée « events », contenant les horodatages. Notez que contrairement aux exemples précédents, on n’utilise pas les dates comme index des lignes, mais on garde l’index par défaut (0, 1, 2, 3, etc.).
En appelant value_counts sur cette colonne, on obtient un nouveau data frame contenant le nombre d’événements pour chaque horodatage :
>>> df.events.value_counts()
2015-04-30 19:49:43 71
2015-04-28 18:58:16 64
2015-04-28 10:40:24 63
2015-04-28 13:56:39 56
...
2015-04-28 13:25:04 1
2015-04-28 16:02:37 1
2015-04-29 17:25:59 1
dtype: int64
Ce nouveau data frame contient donc en fait le nombre d’événements par seconde.
Pour obtenir le nombre d’événements par heure, il suffit d’appeler resample sur ce data frame, en demandant à la méthode de sommer les valeurs par périodes d’une heure :
>>> df.events.value_counts().resample('1h', how=sum)
2015-04-28 06:00:00 3615
2015-04-28 07:00:00 6868
2015-04-28 08:00:00 7504
2015-04-28 09:00:00 6700
...
2015-05-01 04:00:00 5702
2015-05-01 05:00:00 5509
2015-05-01 06:00:00 2856
Freq: H, dtype: int64
Très simple, non ?
À ce stade, il ne reste plus qu’à appeler plot sur le data frame, et pandas fait le reste !
Conclusion
Je n’ai fait qu’effleurer les possibilités offertes par pandas et matplotlib, mais j’espère que c’est suffisant pour vous montrer à quel point il est facile de manipuler et de visualiser des données avec ces bibliothèques ! N’hésitez pas à parcourir leur documentation, elle est très claire et complète.