<- c("forecast", "ggplot2", "plotly")
packages_to_install
<- packages_to_install[! packages_to_install %in% installed.packages()[,"Package"]]
packages if (length(packages) > 0) {
install.packages(packages)
}<- c("rjd3toolkit", "rjd3highfreq", "rjd3filters", "rjd3x11plus")
packages_to_install_git <- packages_to_install_git[! packages_to_install_git %in% installed.packages()[,"Package"]]
packages_git
if (length(packages_git) > 0) {
# # Configurer si besoin le proxy
# proxy <- "proxy_a_definir"
# Sys.setenv(HTTPS_PROXY = proxy)
::install_github(
remotessprintf("rjdemetra/%s", packages_git),
# option utile dans certaines installations portables de Java :
INSTALL_opts = "--no-multiarch")
}if (! "ggdemetra3" %in% installed.packages()[,"Package"])
::install_github("AQLT/ggdemetra3") remotes
6 - Désaisonnalisation à haute-fréquence
Désaisonnaliser une série temporelle
L’objectif de ce TP est de montrer un exemple de désaisonnalisation de séries haute-fréquence.
Pour installer tous les packages utiles de ce TP, lancer le programme :
Nous utiliserons la base forecast::taylor
de demande d’électricité par demi-heure en Angleterre et au Pays de Galles du lundi 5 juin 2000 au dimanche 27 août 2000.
library(rjd3highfreq)
library(forecast)
library(plotly)
library(ggplot2)
<- function(x, p0, p1, np= p1 - p0 + 1, original = TRUE, interactive = FALSE) {
trace_ch <- rjd3toolkit::seasonality_canovahansen(
sa_tests
x,p0 = p0, p1 = p1, np = np,
original = original)
<- seq.int(from = p0, length.out = length(sa_tests))
x if (interactive) {
plot_ly() |>
add_trace(
type = "scatter",
mode = "lines",
x = x,
y = sa_tests
)else {
} plot(x, sa_tests, type = "l")
}
}<- function(data) {
graph_comp <- reshape2::melt(data, id="x")
dataGraph ggplot(data = dataGraph, aes(x = x, y = value, color = variable)) +
geom_line()
}<- seq(as.POSIXct("2020-06-05 00:00:00"), as.POSIXct("2020-08-27 23:30:00"), by="30 min") x
La saisonnalité est clairement identifiable sur la série brute :
plot(x, taylor, type = "l")
On peut effectuer un test pour Canova-Hansen pour le vérifier :
trace_ch(taylor, p0 = 2, p1 = 2*24*7, np = 2*24*7-1)
On observe deux pics, pour des périodicités faibles (horaire ? cela ne s’explique pas) et autour de 48 (saisonnalité journalière). En faisant une différenciation journalière, on remarque qu’il reste de la saisonnalité qui est hebdomadaire (\(2\times24\times7\)) :
plot(x[-(1:48)], rjd3toolkit::differences(taylor, 48), type = "l")
lines(x[-(1:48)][-(1:(2*24*7))], rjd3toolkit::differences(taylor, c(48, 2*24*7)), col = "red")
La première méthode que nous utiliserons est la méthode mSTL. Elle prend en entrée des objets msts
qui peuvent être créés avec la fonction forecast::msts()
pour spécifier les différentes saisonnalités. Ici la base taylor
est déjà au bon format mais on aurait pu la créer avec le code msts(taylor, seasonal.periods = c(2 * 24, 2*24*7))
.
<- mstl(taylor,)
mstl_mod autoplot(mstl_mod)
Par défaut, une moyenne mobile de longueur 11 est utilisée pour la saisonnalité journalière et de longueur 15 pour la saisonnalité hebdomadaire (paramètre s.window
) mais cette hypothèse peut être changée.
On pourrait également estimer le modèle avec TBATS mais le temps de calcul est long et les résultats n’étaient pas satisfaisants. Ci-dessous le code qui pourrait être utilisé :
<- tbats(taylor, seasonal.periods = c(2 * 24, 2*24*7)) tbats_mod
Utilisons maintenant les méthodes de rjd3highfreq
. La série brute est très peu bruitée donc le préajustement n’est pas nécessaire. Par ailleurs pas de tendance marquée et le schéma additif parait adapté :
<- fractionalAirlineEstimation(
pre_pro y = taylor,
periods = c(2*24, 2*24*7),
# pas utile de faire de détection des LS
outliers = c("ao", "wo"),
log = FALSE, y_time = x)
pre_pro
Number of observations: 4032
Start: 2020-06-05
End: 2020-08-27 23:30:00
Estimate MA parameters:
MA_parameter Coef Coef_SE Tstat
Theta(1) -0.8100819 0.007010398 -115.55433
Theta(period = 48) 0.3883132 0.020280074 19.14752
Theta(period = 336) 0.7760373 0.018278218 42.45694
Number of calendar regressors: 0 , Number of outliers : 1
Outliers coefficients:
Variable Coef Coef_SE Tstat
AO.2020-06-12 21:00:00 -1234.44 139.3048 -8.8614
Sum of square residuals: 3.063e+08 on 3643 degrees of freedom
Log likelihood = -2.602e+04,
aic = 5.204e+04,
aicc = 5.204e+04,
bic(corrected for length) = 11.35
Hannan–Quinn information criterion = 5.205e+04
Il n’y a que 1 point atypique détecté. On va désaisonnaliser la série linéarisée de plusieurs façons : - Désaisonnalisation en deux étapes (journalière puis hebdomadaire) avec rjd3highfreq::fractionalAirlineDecomposition()
Désaisonnalisation en une étape des deux saisonnalités en une étape avec
rjd3highfreq::multiAirlineDecomposition()
.Désaisonnalisation uniquement de la saisonnalité hebdomadaire.
<- rjd3highfreq::fractionalAirlineDecomposition(
amb.p1 y = pre_pro$model$linearized, # linearized series from preprocessing
period = 2 * 24,
log = FALSE)
# Il reste de la saisonnalité
# plot(ggdemetra3::seasonaladj(amb.p1), type = "l")
# On ajuste maintenant la saisonnalité hebdomadaire :
<- rjd3highfreq::fractionalAirlineDecomposition(
amb.p2 y = amb.p1$decomposition$sa,
period = 2*24*7,
log = FALSE,)
plot(ggdemetra3::seasonaladj(amb.p2), type = "l")
# Si on estime directement la saisonnalité hebdo le résultat semble proche
<- rjd3highfreq::fractionalAirlineDecomposition(
amb.sem y = pre_pro$model$linearized,
period = 2*24*7,
log = FALSE)
<- rjd3highfreq::multiAirlineDecomposition(
amb.multi y = pre_pro$model$linearized,
periods = c(2 * 24, 2*24*7),
log = FALSE, ndiff = 2, y_time = x)
Nous allons maintenant construire des tables pour comparer les méthodes. Dans les désaisonnalisations avec rjd3highfreq
il faut ajouter les points atypiques du préajustement (pre_pro$model$component_outliers
) :
<- pre_pro$model$component_outliers
preaj <- data.frame(x = x,
data_sa # on utilise c() pour enlever le type "msts"
mstl = c(forecast::seasadj(mstl_mod)),
amb_sem = ggdemetra3::seasonaladj(amb.sem) + preaj,
amb_2step = ggdemetra3::seasonaladj(amb.p2) + preaj,
amb_multi = ggdemetra3::seasonaladj(amb.multi) + preaj)
<- data.frame(x = x,
data_t mstl = c(forecast::trendcycle(mstl_mod)),
amb_sem = ggdemetra3::trendcycle(amb.sem),
amb_2step = ggdemetra3::trendcycle(amb.p2),
amb_multi = ggdemetra3::trendcycle(amb.multi))
<- data.frame(x = x,
data_i mstl = c(forecast::remainder(mstl_mod)),
amb_sem = ggdemetra3::irregular(amb.sem) + preaj,
amb_2step = ggdemetra3::irregular(amb.p2) + preaj,
# Ici on récupère i d'une autre façon car petit bug sur la version actuelle
amb_multi = amb.multi$decomposition[[length(amb.multi$decomposition)]] + preaj)
<- data.frame(x = x,
data_s mstl = c(mstl_mod[, "Seasonal48"] + mstl_mod[, "Seasonal336"]),
amb_sem = ggdemetra3::seasonal(amb.sem) ,
amb_2step = ggdemetra3::seasonal(amb.p1) + ggdemetra3::seasonal(amb.p2),
amb_multi = amb.multi$decomposition$s_48 + amb.multi$decomposition$s_336)
Les composantes saisonnières sont toutes proches :
graph_comp(data_s)
Mais plus de différences sur la tendance et l’irrégulier. La tendance est très erratique avec l’estimation en deux étapes et l’estimation de la saisonnalité hebdomadaire (amb_sem
et amb_2step
) :
ggplotly(graph_comp(data_t))
À part pour le modèle amb_multi
, les séries désaisonnalisées semblent proches. On observent notamment plusieurs pics à des fréquences qui semblent journalières ce qui peut amener à penser qu’il faudrait changer les paramètres.
ggplotly(graph_comp(data_sa))