Introduction
Le module prophet de Facebook permet de modeliser des series temporelles de maniere pragmatique :
- modelisation ‘a la scikit-learn’ en 2 lignes
- plusieurs saisonnalites disponibles (jour, semaine, annee)
- tendance lineaire par morceaux (et pas seulement …)
- possibilite de definir des journees de conges qui affectent la serie
- plusieurs sorties graphiques dont des intervalles de confiance pour la prevision
- on peut ajouter des predicteurs supplementaires
- gestion des valeurs manquantes, la documentation suggere meme de remplacer les valeurs atypiques par des valeurs manquantes : https://facebook.github.io/prophet/docs/outliers.html
L’installation du module necessite la dependance PyStan, cf les documents officiels :
Pour une introduction a prophet et une description precise des fonctions, de leurs arguments et de leurs valeurs par defaut :
- https://facebook.github.io/prophet/docs/quick_start.html#python-api
- https://cran.r-project.org/web/packages/prophet/prophet.pdf#page.14. En repassant sous Python, ne pas oublier de remplacer les ‘.’ par des ’_’.
library("reticulate")
# on a installe prophet dans l'environnement vituel conda "env_prophet"
use_condaenv(condaenv = "env_prophet", required = TRUE)Modules
import numpy as np
import pandas as pd
pd.set_option('display.max_columns', None)
import math
import sys
import pkg_resources
import os
from os import path
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
from sklearn.metrics import mean_squared_error
import statsmodels.api as sm
from prophet import Prophet
from prophet.plot import plot_plotly, add_changepoints_to_plot
# pour regler un bug graphique assez courant avec Anaconda,
# adapter le chemin vers le dossier 'plugins/platforms'
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = 'C:/Users/Sebastien/Anaconda3/envs/env_prophet/Library/plugins/platforms'
os.chdir(".")Les versions Python et prophet utilisees.
sys.version
# prophet.__version__
pkg_resources.get_distribution('prophet').version'3.9.7 (default, Sep 16 2021, 16:59:28) [MSC v.1916 64 bit (AMD64)]'
'1.0.1'
Description des donnees ‘Airline Passengers’
Il s’agit du nombre mensuel de passagers du secteur aerien de 1949 a 1960.
donnees_r = data.frame(AirPassengers)
mois = as.character(1:12)
mois[nchar(mois) == 1] = paste0('0', mois[nchar(mois) == 1])
donnees_r["Month"] = c(sapply(1949:1960, \(x) paste(x, mois, sep = "-")))
donnees_r = donnees_r[c("Month", "AirPassengers")]On met la serie au format attendu par prophet : une colonne ds de datetimes et une colonne y numerique.
donnees = r.donnees_r
donnees["Month"] = pd.to_datetime(donnees["Month"] + "-01")
donnees.rename(columns = {'Month': 'ds', 'AirPassengers':'y'}, inplace = True)
donnees.reset_index(drop = True);
donnees ds y
0 1949-01-01 112.0
1 1949-02-01 118.0
2 1949-03-01 132.0
3 1949-04-01 129.0
4 1949-05-01 121.0
.. ... ...
139 1960-08-01 606.0
140 1960-09-01 508.0
141 1960-10-01 461.0
142 1960-11-01 390.0
143 1960-12-01 432.0
[144 rows x 2 columns]
La serie est clairement multiplicative avec une saisonnalite de periode 12. La tendance est lineaire avec plusieurs changements de pente.
periode = 12
decomposition = sm.tsa.seasonal_decompose(donnees.y, model='multiplicative', period = 12)
decomposition.plot()
plt.show()Modelisation
On cree une colonne train / test : l’apprentissage correspond a donnees.partition == True.
donnees["partition"] = pd.Series(donnees.index) <= 0.6 * len(donnees)
donnees["partition"].value_counts()True 87
False 57
Name: partition, dtype: int64
Parametrage et entrainement du modele
On indique que la serie est multiplicative avec une saisonnalite annuelle, on suggere 3 points de changements de tendance et on rend les tendances et saisonnalite moins flexibles qu’avec les valeurs par defaut.
model = Prophet(yearly_seasonality = True,
seasonality_mode = 'multiplicative',
n_changepoints = 3,
changepoint_prior_scale = 0.03,
seasonality_prior_scale = 0.1)
model.fit(donnees[donnees.partition])<prophet.forecaster.Prophet object at 0x0000000035D528B0>
INFO:prophet:Disabling weekly seasonality. Run prophet with weekly_seasonality=True to override this.
INFO:prophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
Qualite de la prevision
On applique le modele a tout le jeu de donnees.
prev = model.predict(donnees[["ds"]])
prev["partition"] = donnees["partition"]
prev["y"] = donnees["y"]Graphique sur l’echantillon test.
prev.loc[~prev.partition, ["y", "yhat"]].plot(colormap = "viridis");
plt.show()Valeur du RMSE :
int(mean_squared_error(prev.yhat[~prev.partition], prev.y[~prev.partition])**1/2)227
Intervalles de confiance des previsions sur toutes les donnees.
prev[["y", "yhat_lower", "yhat_upper", "yhat",]].plot(colormap = "viridis");
plt.show()Sorties graphiques de prophet
Qualite du modele sur l’echantillon d’apprentissage.
model.plot(prev[prev.partition])
plt.show()Tendance et saisonnalite sur toutes les donnees.
model.plot_components(prev)
plt.show()Les changements de regime de la tendance, le modele n’a finalemet retenu que 2 des 3 points detectes.
model.changepoints
fig = model.plot(prev)
add_changepoints_to_plot(fig.gca(), model, prev);
plt.show()23 1950-12-01
45 1952-10-01
68 1954-09-01
Name: ds, dtype: datetime64[ns]
Version interactive sur toutes les donnees avec plotly.
plot_plotly(model, prev)
plt.show()