La question de la stationnarité et de l’autocorrélation font partie d’un thème plus large qui a rapport à l’endogénéité et l’exogénéité des variables dans une régression. On cherche à connaître le comportement d’une variable si elle n’était affectée que par ses propres chocs idiosyncratiques - donc si elle était totalement exogène au système. Il faut donc l’isoler de l’influence du temps, mais aussi des chocs provenant d’autres variables endogènes. Ici, on va faire uniquement des rappels de cours, et faire l’essentiel du code sur des données simulées afin de montrer que toutes les séries, même si elles peuvent avoir une dynamique similaire, ne peuvent et ne doivent pas être traitées de la même façon.
On va d’abord définir la stationnarité, et les implications liées à la non-stationnarité d’une série temporelle.
Il faut partir du postulat que n’importe quelle série qu’on observe est une suite de chocs idiosyncratiques, c’est-à-dire que son comportement ne change pas dans le temps (sa variance, sa moyenne, sont donc constantes). On parle souvent d’une suite de bruits blancs. Les seules choses qui impactent l’évolution d’une série sont des chocs idiosyncratiques, donc propre à la série uniquement. On parle alors généralement de processus stationnaire : l’évolution de la série est indépendante du temps. Généralement, ces hypothèses de départ sont formulées de la façon suivante: \[\begin{align} & E(y_t) = 0 \\ & E(y_t)=E(y_{t+h}) \\ & Var(y_t)=\sigma^2_y \end{align}\] Littéralement, la série a une espérance (moyenne) nulle \(E(y_t) = 0\) et constante (indépendente du temps) \(E(y_t)=E(y_{t+h})\) et a une variance constante (\(Var(y_t)=\sigma^2_y\)).
Dans ce cas précis, la série est purement aléatoire, et son évolution est uniquement le fruit de chocs idiosyncratiques eux-mêmes aléatoires (on dit qu’ils suivent une loi Normale de moyenne nulle et de variance \(\sigma^2_\varepsilon\)):
\[\begin{align} & y_t = \varepsilon_t \\ & \varepsilon \sim N(0,\sigma^2_\varepsilon) \end{align}\]On peut générer ce genre de variable dans R :
set.seed(123) # reproductibilité
n <- 200 # longueur des séries
t <- 1:n
df <- data.frame(
t = t, # crée une suite de 1 à 100
variable = rnorm(n, mean = 0, sd = 1) #distribution avec moyenne à 0, écart-type de 1
)
ggplot(df, aes(x = t, y = variable)) +
geom_line()+
theme_bw()
On peut voir que la moyenne et la variance sont relativement constantes dans le temps, et que la distribution est autour de 0.
Dans la réalité, on ne peut que très rarement observer ce processus pour des variables macro/micro-économiques. Par exemple, si on prend le PIB :
donnees <- read_excel("C:/users/fkraus/Desktop/data_schularick.xlsx")
data_pib <- donnees %>%
filter(country=="France") %>%
select(year, gdp)
ggplot(data_pib, aes(x=year, y=gdp))+
geom_line(lwd=1)+
theme_bw()
On se retrouve avec une série qui a une moyenne éloignée de 0, et ni sa moyenne, ni sa variance ne sont constantes dans le temps.
A partir du moment où une série est dépendante du temps, on parle alors de processus non-stationnaire. Le problème avec ce genre de séries est que - en économétrie des séries temporelles - les processus non-stationnaires rendent les estimations moins fiables. En effet, on essaye - lors d’une régression - d’identifier l’effet causal d’une variable sur une autre, un effet clairement identifié. Si l’influence d’autres variables (comme le temps) n’est pas prise en compte, alors l’identification sera critiquable (on va faire des régressions fallacieuses, les coefficients estimés seront faux).
En séries temporelles (1 individu, avec plusieurs observations dans le temps), l’essentiel est de bien isoler l’influence du temps sur les variables - ce qui explique tout le processus de stationnarisation. En panel (plusieurs individus, plusieurs observations dans le temps), on part du principe que l’influence du temps est absorbée par les effets fixes individuels (des variables qui sont communes à tous les individus et qui évoluent dans le temps), donc il y a moins ces questions de stationnarisation.
On peut dans un premier temps regarder si la série est influencée par elle-même, autrement dit si \(y_{t-1}\) a une influence sur \(y_t\). On parle d’autocorrélation lorsque la corrélation entre \(y_{t-1}\) et \(y_{t}\) est non-nulle (significativement différente de 0). Si cette autocorrélation est présente, alors il faudra la prendre en compte dans la régression, soit en retirant le trend (processus TS), soit en passant en différence première (processus DS) : ça sera la partie stationnarisation de la série.
On peut mesurer assez simplement l’autocorrélation d’ordre 1 d’une série, donc littéralement : \[\begin{equation} y_t=\alpha_0 + \beta y_{t-1}+\varepsilon_t \end{equation}\]
require(fixest)
reg <- feols(gdp ~ lag(gdp,1), data_pib)
etable(reg, se.below=TRUE)
reg
Dependent Var.: gdp
Constant 0e-16
(7.56e-14)
lag(gdp,1) 1.000***
(1.38e-17)
_______________ _____________
S.E. type IID
Observations 151
R2 1
Adj. R2 1
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Le résultat de la régression montre que le PIB à la période précendente explique parfaitement le PIB à la période actuelle. Le coefficient est significativement différent de 0, on en conclut donc que la série dépend du temps, et qu’il y a présence d’autocorrélation.
Potentiellement, ce n’est pas seulement le PIB à la période précédente qui explique l’évolution future du PIB, mais peut-être plusieurs délais. On peut le vérifier avec l’autocorrélogramme
acf(data_pib$gdp)
Chaque tiret vertical représente l’influence d’un délai (lag) particulier sur l’évolution de la série à la période \(t\). Le premier tiret peut être négligé ici, c’est l’influence de la série sur elle-même à la même période (donc c’est forcément 1). En l’absence d’autocorrélation en revanche, le reste des tirets est censé être non-significatif (donc les tirets ne doivent pas dépasser la ligne horizontale bleue). Ici, on voit bien que les délais jusqu’à 20 périodes (donc 20 ans avant) influencent la série à la période \(t\). C’est une indications très forte que la série n’est pas stationnaire. Mais ce n’est pas un test formel, c’est un moyen visuel d’identifier la non-stationnarité.
Une fois qu’on a identifié le fait que la série n’est pas stationnaire, il faut la rendre stationnaire. Il existe deux moyens principaux pour stationnariser une série, en fonction du type de non-stationnarité : passer la série en différence première, ou retirer la tendence (detrend).
Dans le cas des processus stationnaires en différence (DS), il suffit (en général) de passer la série en différence \(\Delta Y_t = Y_t - Y_{t-1}\) pour la rendre stationnaire.
set.seed(123)
n <- 200 # longueur des séries
t <- 1:n # variable qui va de 1 à 200
u <- rnorm(n, mean = 0, sd = 1) # pour la I(1)
e <- rnorm(n, mean = 0, sd = 1) # pour la I(2)
# 1) Série I(1) : Random Walk avec léger drift
# y_t = y_{t-1} + d + u_t
d <- 0.03
y1 <- cumsum(d + u)
difference <- data.frame(t, y1) %>%
mutate(dy1 = c(NA, diff(y1)))
ggplot(difference, aes(x=t, y=y1))+
geom_line()+
labs(title="Série Y1 en niveau")+
theme_bw()
ggplot(difference, aes(x=t, y=dy1))+
geom_line()+
labs(title="Série Y1 en différence première")+
theme_bw()
Ici, il a suffit de passer la série en différence première pour la stationnariser. On dit aussi que la série est intégrée d’ordre 1 \(I(1)\) (voir séance 7 ARIMA et Cointégration).
Dans certains cas, passer en différence première ne suffit pas à stationnariser une série non-stationnaire. Dans ce cas, on continue de différencier la série, avec autant d’ordres qu’il faut pour la stationnariser.
y2 <- cumsum(cumsum(e)) # série aléatoire
difference2 <- data.frame(t, y2)%>%
mutate(dy2 = c(NA, diff(y2)))%>% #différence première
mutate(ddy2 = c(NA, diff(dy2))) # deuxième différence
ggplot(difference2, aes(x=t, y=y2))+
geom_line()+
labs(title="Série Y2 en niveau")+
theme_bw()
ggplot(difference2, aes(x=t, y=dy2))+
geom_line()+
labs(title="Série Y2 en différence première")+
theme_bw()
ggplot(difference2, aes(x=t, y=ddy2))+
geom_line()+
labs(title="Série Y2 en deuxième différence")+
theme_bw()
Ici, la transformation en différence première ne suffit pas à rendre la série stationnaire a priori. En revanche, la deuxième différence semble suffire. On parle ici d’intégration d’ordre 2 \(I(2)\). Dans la majorité des cas, il n’y a pas besoin d’aller plus loin pour stationnariser, mais en théorie on peut répéter l’opération autant de fois que nécessaire.
Souvent, les chercheurs transforment directement leurs variable en différence de logarithme parce que ça permet de stationnariser une série tout en gardant une interprétation logique : la série en niveau (sans transformation) devient une série en taux de croissance (voir séance 1 pour faire une différence de log).
Dans le cas des processus stationnaires en tendance (TS), il suffit de retirer la tendance de la série pour la rendre stationnaire. Un processus TS peut suivre un processus additif, ou un processus multiplicatif. Il faut imaginer qu’une série \(Y_t\) est impactée par toutes sortes de chocs. Pour faire simple, on va simplement dire qu’il y a une tendance \(T\) et des chocs idiosyncratiques \(E_t\). Dans la réalité, d’autres composantes entrent en jeu : la saisonnalité S et le cycle C par exemple.
Dans le cas d’un processus additif, l’équation de la série est : \[\begin{equation} Y_t = T + E_t \end{equation}\]
Visuellement, une série qui suit un processus additif va ressembler à ceci :
# 1) Série à tendance ADDITIVE: Y_t = T_t + E_t
# - Tendance linéaire
# - Chocs idiosyncratiques ~ N(0, sigma^2)
T_add <- 0.5 * t + 5 # tendance (droite croissante) + constante
E_add <- rnorm(n, mean = 0, sd = 0.8) # "bruit" additif
Y_add <- T_add + E_add
additive <- data.frame(t, Y_add)
head(additive)
ggplot(additive, aes(x=t, y=Y_add))+
geom_line()+
labs(title="Série Y_add (processus additif) en niveau")+
theme_bw()
On voit bien que la série suit une tendance linéaire, et qu’elle est distribuée assez équitablement autour de cette tendance.
\[\begin{equation} y_t = a_0 + \beta t + \varepsilon_t \end{equation}\] Les résidus \(\varepsilon_t\) peuvent donc être écrits, en réorganisant l’équation : \[\begin{equation} \varepsilon_t = y_t - a_0 - \beta t \end{equation}\] Ils représentent donc la série \(y_t\), moins la constante \(a_0\) et moins l’influence de la tendence \(\beta t\).
detrend <- feols(Y_add ~ t, data=additive)
etable(detrend)
detrend
Dependent Var.: Y_add
Constant 5.080*** (0.1098)
t 0.4995*** (0.0009)
_______________ __________________
S.E. type IID
Observations 200
R2 0.99929
Adj. R2 0.99929
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
trend_hat_add <- fitted(detrend) # tendance estimée
resid_add <- resid(detrend) # résidus (série "dé-tendancée")
detrending_additive <- data.frame(additive, trend_hat_add, resid_add)
head(detrending_additive)
ggplot(detrending_additive, aes(x=t, y=Y_add))+
geom_line(lwd=1)+
geom_line(aes(y=trend_hat_add), lty=4, color="red", lwd=1)+
labs(title="Série Y_add (additive) et tendance associée")+
theme_bw()
ggplot(detrending_additive, aes(x=t, y=resid_add))+
geom_line()+
labs(title="Série Y_add (additive) détrendée")+
theme_bw()
Dans le cas d’un processus multiplicatif, l’équation de la série est : \[\begin{equation} Y_t = T \times E_t \end{equation}\]
Visuellement, une série qui suit un processus multiplicatif va ressembler à ceci :
# 2) Série à tendance MULTIPLICATIVE: Y_t = T_t * E_t
# - Même tendance linéaire mais multipliée par des chocs > 0
T_mult <- 0.5 * t + 5
E_mult <- rlnorm(n, meanlog = 0, sdlog = 0.3) # chocs multiplicatifs centrés autour de 1
Y_mult <- T_mult * E_mult
multiplicative <- data.frame(t, Y_mult)
head(multiplicative)
ggplot(multiplicative, aes(x=t, y=Y_mult))+
geom_line()+
labs(title="Série Y_mult (processus multiplicatif) en niveau")+
theme_bw()
Ici, la distribution de la série semble moins suivre la tendance linéaire que dans le processus additif.
Pour le processus multiplicatif, la même méthode pour détrendée va donner les résultats suivants :
detrend_mult <- feols(Y_mult ~ t, data=multiplicative)
etable(detrend_mult)
detrend_mult
Dependent Var.: Y_mult
Constant 3.926 (2.859)
t 0.5423*** (0.0247)
_______________ __________________
S.E. type IID
Observations 200
R2 0.70935
Adj. R2 0.70788
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
trend_hat_mult <- fitted(detrend_mult) # tendance estimée
resid_mult <- resid(detrend_mult) # résidus (série "dé-tendancée")
detrending_multiplicative <- data.frame(multiplicative, trend_hat_mult, resid_mult)
head(detrending_multiplicative)
ggplot(detrending_multiplicative, aes(x=t, y=Y_mult))+
geom_line()+
geom_line(aes(y=trend_hat_mult), color="red", lty=2, lwd=1)+
theme_bw()
ggplot(detrending_multiplicative, aes(x=t, y=resid_mult))+
geom_line()+
theme_bw()
Ici, si on reprend le même processus de dé-stationnarisation, on voit que, effectivement les résidus sont distribués autour de 0, et que l’espérance des résidus est bien 0. En revanche, la variance des résidus n’est pas constante (=heteroscédasticité): elle augmente avec le temps.
Un autre moyen, qui ne règle pas toujours le problème (mais qui, en général capte les autres composantes de la variation de \(Y_t\) comme le cycle par exemple) et de mesurer la moyenne mobile de la série, et de retirer cette moyenne mobile :
require(zoo)
detrending_multiplicative2<-detrending_multiplicative%>%
mutate(moving_average = rollapply(Y_mult, FUN=mean, width=5, fill=NA, align="right"))%>%
mutate(detrended_serie = Y_mult - moving_average)%>%
na.omit()
detrending_multiplicative2%>%
ggplot(aes(x=t, y=Y_mult))+
geom_line()+
geom_line(aes(y=moving_average), col="red", lty=2, lwd=1)+
theme_bw()
detrending_multiplicative2 %>%
ggplot(aes(x=t, y=detrended_serie))+
geom_line()+
theme_bw()
Ici, ça n’a pas aidé à retirer l’hétéroscédasticité, mais c’est une bonne alternative (et c’est très souvent utilisé dans la recherche. Par exemple, cet article de la BCE (https://www.ecb.europa.eu/pub/pdf/scpwps/ecb.wp2868~0c2ad2e6e7.en.pdf) utilise la moyenne mobile des 15 dernières périodes pour détrender une série (page 14). Idem pour cet article de 1993 : https://academic.oup.com/qje/article-pdf/108/4/905/5365099/108-4-905.pdf).
Ici, comme l’hétéroscédasticité est encore présente, il faudrait éventuellement modéliser empiriquement le fait que l’hétéroscédasticité fait partie du processus de la série, dans un modèle ARCH (Auto-Regressive Conditional Heteroskdasticity) ou GARCH (Generalized ARCH) du type : \[\begin{align*} &y_t = a_0 + \varepsilon_t \\ &\varepsilon_t \sim N(0, h_t) \\ &h_t = \beta h_{t-1} + \mu_t \end{align*}\] Les chocs idiosyncratiques ont une distribution normale autour de 0, mais avec une variance \(h\) qui dépend du temps (\(h_t\)), et notamment qui dépend de la variance passée. Les modèles ARCH/GARCH, qu’on ne verra pas pendant ces séances, sont des extensions des modèles AR/MA/ARIMA que l’on verra dans les séance 5, 6 et 7.
Aussi, il faut bien se rappeler que le but de la stationnarisation n’est pas de transformer une série en une suite parfaite de bruits blancs. Dans la réalité, les variables (\(Y_t\)) sont affectées par leur tendance, le cycle, la saisonnalité. En revanche, stationnariser une série permet de l’isoler de l’influence du temps, et améliore l’estimation de l’effet d’autres variables sur la série.
#Exemple de stationnarisation
On va d’abord simuler des données :
set.seed(123)
n <- 200 # longueur des séries
t <- 1:n # variable qui va de 1 à 200
u <- rnorm(n, mean = 0, sd = 1) # loi normale de moyenne nulle et d'écart type 1
# 1) Série I(1) : Random Walk avec léger drift
# y_t = y_{t-1} + d + u_t
d <- 0.03
y1 <- cumsum(d + u)
difference <- data.frame(t, y1) %>%
mutate(dy1 = c(NA, diff(y1)))
head(difference)
La première étape est donc de tester la présence d’un trend :
require(urca)
summary(ur.df(difference$y1, type="trend"))
###############################################
# Augmented Dickey-Fuller Test Unit Root Test #
###############################################
Test regression trend
Call:
lm(formula = z.diff ~ z.lag.1 + 1 + tt + z.diff.lag)
Residuals:
Min 1Q Median 3Q Max
-2.18117 -0.54020 -0.08912 0.56928 2.95658
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.3172463 0.1542791 2.056 0.0411 *
z.lag.1 -0.0656894 0.0256276 -2.563 0.0111 *
tt 0.0002116 0.0012502 0.169 0.8658
z.diff.lag -0.0365851 0.0716882 -0.510 0.6104
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.935 on 194 degrees of freedom
Multiple R-squared: 0.04006, Adjusted R-squared: 0.02522
F-statistic: 2.699 on 3 and 194 DF, p-value: 0.04701
Value of test-statistic is: -2.5632 2.4736 3.6261
Critical values for test statistics:
1pct 5pct 10pct
tau3 -3.99 -3.43 -3.13
phi2 6.22 4.75 4.07
phi3 8.43 6.49 5.47
Le résultat test de Dickey-Fuller se lit de la façon suivante :
test-statistic) avec les valeurs critiques
à 5%.Le coefficient associé à la tendance tt n’est pas
significatif, donc il n’y a pas de tendance déterministe détectée. On
sait donc que ce n’est pas un processus TS. En revanche, quand on
regarde les t-stats, on peut voir que la valeur du test pour
tau3 (la première valeur sur la ligne
Value of test-statistic is: -2.5632 2.4736 3.6261) n’excède
pas (en valeur absolue) la valeur critique à 5% : on sait donc que la
série n’est donc pas stationnaire.
On test ensuite avec le modèle avec drift (donc avec une constante
notée Intercept dans la régression).
summary(ur.df(difference$y1, type="drift"))
###############################################
# Augmented Dickey-Fuller Test Unit Root Test #
###############################################
Test regression drift
Call:
lm(formula = z.diff ~ z.lag.1 + 1 + z.diff.lag)
Residuals:
Min 1Q Median 3Q Max
-2.1913 -0.5481 -0.1001 0.5614 2.9738
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.33101 0.13078 2.531 0.01216 *
z.lag.1 -0.06410 0.02379 -2.694 0.00767 **
z.diff.lag -0.03780 0.07115 -0.531 0.59583
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.9326 on 195 degrees of freedom
Multiple R-squared: 0.03992, Adjusted R-squared: 0.03007
F-statistic: 4.054 on 2 and 195 DF, p-value: 0.01884
Value of test-statistic is: -2.6944 3.7146
Critical values for test statistics:
1pct 5pct 10pct
tau2 -3.46 -2.88 -2.57
phi1 6.52 4.63 3.81
Ici, on peut voir que le coefficient associé à la constante dan sle
tableau de régression est significatif à 5%. Il semble donc que la série
soit affectée par un drift. Aussi, quand on compare la valeur de la
t-stat avec la valeur critique associée à tau2, on
voit que la valeur de la t-stat n’excède pas (en valeur
absolue) la valeur critique à 5%, donc la série n’est pas stationnaire.
On sait donc que la série n’est pas stationnaire, et qu’elle suit un
processus DS. Il suffirait donc de la passer en différence pour qu’elle
devienne stationnaire. On peut le vérifier en faisant le test de
stationnarité (sans trend ni constante) sur la série en différence
dy1 :
summary(ur.df(difference$dy1 %>% na.omit()))
###############################################
# Augmented Dickey-Fuller Test Unit Root Test #
###############################################
Test regression none
Call:
lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)
Residuals:
Min 1Q Median 3Q Max
-2.13867 -0.57418 -0.03455 0.63940 3.10357
Coefficients:
Estimate Std. Error t value Pr(>|t|)
z.lag.1 -1.15030 0.10402 -11.058 <2e-16 ***
z.diff.lag 0.08256 0.07121 1.159 0.248
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.9403 on 195 degrees of freedom
Multiple R-squared: 0.536, Adjusted R-squared: 0.5312
F-statistic: 112.6 on 2 and 195 DF, p-value: < 2.2e-16
Value of test-statistic is: -11.0583
Critical values for test statistics:
1pct 5pct 10pct
tau1 -2.58 -1.95 -1.62
Ici, la t-stat excède la valeur critique à 1% en valeur absolue, ce qui indique que la série en différence est effectivement stationnaire. On peut donc l’utiliser dans le cadre d’une régression.
Comment savoir le type de non-stationnarité ? TS vs DS
Afin de s’assurer, avec un test formel, de la stationnarité (ou non-stationnarité) d’une série, il existe de nombreux tests. Il faut également déterminer pour les séries non-stationnaires quel type de non-stationnarité est détectée, car chaque type entraîne des stratégies de stationnarisation différentes qui peuvent créer des perturbations artificielles dans la dynamique d’une série si elles sont mal appliquées.
L’ensemble de ce processus peut être résumé par la Stratégie Séquentielle d’Identification que vous pouvez voir sur ce lien : https://deep-nectarine-155.notion.site/Strat-gie-s-quentielle-28fdaa6a390080f6b63cf102991f522a
La première étape est de tester la présence d’une trend déterministe, pour savoir si le processus est stationnaire en tendance (TS) éventuellement :