Prévoir et analyser les données temporelles font partie des challenges en data science (par exemple prévoir la valeur du cours d’un indice boursier).
C’est cette problématique que l’outil open source facebook prophet tente de résoudre.
Dans cet article, on dissèque la libraire prophet de Facebook et on terminera avec un cas pratique (prévoir le prix du bitcoin !).
C’est quoi facebook prophet ?
Prophet est une librairie open source (R et Python) de prévision des données de séries temporelles basée sur un modèle additif. Cette librairie permet d’analyser aisément des séries temporelles même pour des personnes n’ayant pas une grande expertise dans ce domaine.
Facebook prophet a pour but de résoudre les problématiques suivantes :
- La difficulté de créer des modèles de prévision fiables : Car cette discipline requiert une expérience particulière
- La rigidité et le manque de robustesse des techniques de prévisions automatiques
Comment fonctionne prophet ?
Comme présenté plus haut, facebook prophet est basée sur un modèle additif. Ce qui veut dire qu’une série temporelle est modélisée comme la somme de plusieurs composantes. On parle de modèle de décomposition d’une série temporelle.

Prophet rajoute une nouvelle composante qui correspond à l’impact des congés/vacances sur le modèle.
Bon, on essaie d’assimiler tout ça au travers d’un cas pratique : prédire le prix du bitcoin avec prophet 😎.
Prédire le cours du Bitcoin avec prophet
Installations et imports
Dans ce tutoriel nous utilisons l’API de python de prophet (les R-fans désolé 😗).
Avant d’aller, plus loin, je vous recommande la distribution Anaconda (cliquez ici savoir comment l’installer rapidement). Toutes les bibliothèques complémentaires de cet articles y sont déjà. Sinon vous pouvez utiliser google colab (il faudra installer les librairies manquantes par contre).
pip install fbprophet
Puis importer les libs
import warnings
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import set_matplotlib_formats
set_matplotlib_formats('retina')
import seaborn as sns
sns.set()
sns.set(rc={'figure.figsize':(14.7,10.27)})
from plotly import tools
import plotly.graph_objs as go
import gc
from datetime import datetime
# prophet model
from fbprophet import Prophet
# prophet preformance
from fbprophet.diagnostics import cross_validation
from fbprophet.diagnostics import performance_metrics
from fbprophet.plot import plot_cross_validation_metric
from IPython.display import set_matplotlib_formats
Ensuite, on télécharge ensuite le jeu de données comme suit
! wget https://raw.githubusercontent.com/lilstipher/daily-cryptocurrencies-data/master/Coinbase_BTCUSD_1h.csv
On a donc notre dataset qui est à présent disponible, chargeons le dans un dataFrame pandas.
bitcoin_usd_data = pd.read_csv("Coinbase_BTCUSD_1h.csv",skiprows=[0])
Nous passons à l’étape classique qui consiste à analyser le dataset : voir si on a des valeurs nulles…
Avec la fonction info()
de notre dataFrame on voit qu’on a environ 9 colonnes, 29061 lignes et aucune valeur nulle.
# info
bitcoin_usd_data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 29061 entries, 0 to 29060
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Unix Timestamp 29061 non-null float64
1 Date 29061 non-null object
2 Symbol 29061 non-null object
3 Open 29061 non-null float64
4 High 29061 non-null float64
5 Low 29061 non-null float64
6 Close 29061 non-null float64
7 Volume BTC 29061 non-null float64
8 Volume USD 29061 non-null float64
dtypes: float64(7), object(2)
memory usage: 2.0+ MB
Les colonnes Unix Timestamp
et Date
correspondent respectivement au timestamp et à la date du jour de la mesure. Ensuite, la colonne Symbol
correspond à la paire Bitcoin/Dollar (BTCUSD). Les colonnes Open, High,Low,Close
correspondent respectivement aux prix d’ouverture, prix haut, bas et de clôture pour une période donnée (1H dans notre cas). Enfin, les deux dernières colonnes correspondent aux volumes d’échange en BTC et USD.
Le volume ou volume d’échange est le nombre d’unités échangées sur un marché pendant une période donnée. Il s’agit d’une mesure du nombre d’unités individuelles d’un actif qui ont changé de mains au cours de cette période.
coinMarketCap
Avant d’arriver à la création de notre modèle avec prophet nous allons effectuer quelques transformations et visualiser nos données.
Pour ce faire, nous convertissons nos timestamp en datetime (qui équivaut grossièrement à la date suivie de l’heure).
date = bitcoin_usd_data['Unix Timestamp'].apply(lambda x: datetime.fromtimestamp(x))
On visualise alors nos données à l’aide d’un graphique en chandeliers japonnais (Candlestick). Le graphique en chandeliers japonais est un type de graphique utilisé en analyse technique boursière pour représenter les variations d’un cours.
fig = go.Figure(data=[go.Candlestick(x=date,
open=bitcoin_usd_data['Open'],
high=bitcoin_usd_data['High'],
low=bitcoin_usd_data['Low'],
close=bitcoin_usd_data['Close'])])
fig.update_layout(xaxis_rangeslider_visible=False)
fig.show()

Vous l’avez peut-être remarqué mais nous avons plusieurs valeurs par ligne. Laquelle correspond au prix du BTC ? Afin de répondre à cette question, nous allons plutôt utiliser un indicateur qui représentera le prix du BTC. Il existe plusieurs indicateurs, cependant nous utiliserons le plus basique dans notre tutoriel. Il s’agit du typical price.
En trading financier, le prix typique ou typical price (parfois appelé le point pivot ) fait référence à la moyenne arithmétique des prix haut, bas et de clôture pour une période donnée. En effet, il s’agit de faire la somme du High, Low et Close et diviser le résultat par 3, simple.
On ajoute alors une nouvelle colonne à notre jeu données correspondant au prix typique.
df = bitcoin_usd_data
df['typical_price'] = df.apply(lambda x : (x['Close']+ x['High'] + x['Low'])/3 ,axis=1)
# On rajoute aussi une colonne datetime
df['datetime'] = df['Unix Timestamp'].apply(lambda x: datetime.fromtimestamp(x))
Visualisons tout ça !
g1 = go.Scatter(
x = df['datetime'],
y = df['Open'],
mode = 'lines',
name = 'Open')
g2 = go.Scatter(
x = df['datetime'],
y = df['Close'],
mode = 'lines',
name = 'Close')
g3 = go.Scatter(
x = df['datetime'],
y = df['typical_price'],
mode = 'lines',
name = 'typical_price')
layout = dict(
title='Historical Bitcoin Prices By hour (2017-2020)',
xaxis=dict(
rangeslider=dict(visible = True),
type='date')
)
from plotly.offline import iplot
data = [g1,g2, g3]
fig = dict(data=data, layout=layout)
iplot(fig, filename = "Time Series with Rangeslider")

Effectuons maintenant des prévisions avec prophet !
Pour utiliser Prophet pour la prévision, il faut d’abord définir et configurer un objet Prophet(), puis l’ajuster sur l’ensemble de données avec la fonction fit() et en lui transmettant les données.
L’objet Prophet() prend plusieurs arguments (saisonnalité, holidays…).
Par défaut, le modèle cherchera automatiquement les meilleurs paramètres pour le modèle.
Aussi, La fonction fit() prend en entrée un DataFrame de séries temporelles. Le DataFrame doit avoir un format spécifique. La première colonne doit porter le nom « ds » et contenir les dates et heures. La deuxième colonne doit porter le nom « y » et contenir les observations.
# On récupère la colonne du prix
df = df.set_index('datetime')
df = df[['typical_price']]
df_model= df.reset_index().rename(columns={'datetime':'ds', 'typical_price':'y'})
# Création du modèle prophet
prophet_model = Prophet()
prophet_model.fit(df_model)
On utilise ensuite make_future_dataframe
afin de spécifier la période de prévision.
period_in_hours = 24*30 # Heure * Nb de jours
future = prophet_model.make_future_dataframe(periods=period_in_hours, freq='H')
Nous avons tout pour créer notre modèle avec facebook prophet.
forecast = prophet_model.predict(df=future)
fig1=prophet_model.plot(forecast)

Il est aussi possible de voir les composantes du modèle (tendance, saisonnalité) avec Prophet.plot_components
. Par défaut, on a la tendance, la saisonnalité annuelle et la saisonnalité hebdomadaire de la série.

Les performances du modèle
Prophet propose une fonctionnalité de validation croisée des séries temporelles pour mesurer l’erreur de prévision à l’aide des données historiques. Cela se fait en sélectionnant des points de coupure puis en ajustant le modèle pour qu’il utilise uniquement les données jusqu’à ce point de coupure. On peut alors comparer les valeurs prévues aux valeurs réelles.

L’idée sera d’entrainer notre modèle sur la période « initial » et de faire des prévisions sur la période « horizon« . Le point de coupure (Cutoff) correspond à la frontière entre les deux zones. Vu qu’on connait les vraies valeurs dans la période « hoziron« , on peut alors estimer l’erreur de prévision pour une période de temps donné.
Revenons à notre sujet.
# validation croisée
from fbprophet.diagnostics import cross_validation
df_cv = cross_validation(prophet_model, initial='366 days', period='90 days', horizon = '90 days')
df_cv.head()

La méthode cross_validation
nous renvoie un dataframe
contenant les valeurs réelles y et yhat les valeurs prédites. Nous utiliserons ce dataframe pour calculer les erreurs de prédiction.
df_p = performance_metrics(df_cv)
df_head()

On a un bon nombre de métriques d’erreurs. Intéressons-nous à erreur quadratique moyenne RMSE.
df_p = performance_metrics(df_cv)
from fbprophet.plot import plot_cross_validation_metric
fig = plot_cross_validation_metric(df_cv, metric='rmse')

Nous voyons que l’erreur augmente linéairement en fonction de la période de prévision. Ainsi, avec cette configuration nous pourrons avoir des prévisions fiables sur une période inférieure à 20j.
Ressources complémentaires
Notebook de l’article sur google colab
Cross-validation: evaluating estimator performance
Forecast KPI: RMSE, MAE, MAPE & Bias
Conclusion
En somme, nous avons présenté dans cet article la librairie de prévision des séries temporelles facebook prophet. Cette librairie propose un arsenal d’outils pour vaincre la complexité des séries temporelles. Aussi, le tutoriel sur la prédiction du cours du bitcoin est destiné uniquement à un usage éducatif.
N’hésitez pas à laisser des commentaires.