Facebook prophet : La prévision à grande échelle

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.

Comment fonctionne prophet ?
Le Modèle additif se présente ainsi : \( y(t) = g(t) +𝑠(t) +𝜀(t) \)
où \( y(t) \) correspond à la modélisation de la série temporelle, \( g(t) \) la tendance, \( 𝑠(t) \) la composante saisonnière, \( 𝜀(t) \) la composante aléatoire ou erreur.

Prophet rajoute une nouvelle composante qui correspond à l'impact des congés/vacances sur le modèle.

Ainsi, le modèle de décomposition de prophet est le suivant : \[y(t) = g(t) + h(t) + 𝑠(t) +𝜀(t) \] où \( h(t) \) correspond à l'effet vacances (h comme holidays).

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()
Visualisation Cours BTC/USD

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)
Le modèle de prévision avec facebook prophet

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 différentes composantes du modèle

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.

cross validation facebook prophet illustratioon
Illustration de la validation croisée avec prophet

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')
plot_cross_validation_metric avec prophet

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.

Laisser un commentaire

Votre adresse email ne sera pas publiée.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

Voulez-vous en savoir plus sur la Data Science ?

Inscrivez-vous alors à notre newsletter et vous receverez gratuitement nos derniers articles et actualités ! 
S'INSCRIRE MAINTENANT 
close-link