The main characteristic of stationary time series is mean reversion — this property implies the tendency of the series to move around the process mean.
#### Mean Reverting set.seed(123) n <- 100 eps <- rnorm(n) xt<- rep(0, 100) xt[1]<-5 # creo 50 values di tre sere storiche con unit roots differenti for (i in seq.int(2, 100)){ xt[i] <-5+ 0.2*xt[i-1] + eps[i] } plot(ts(xt),ylim=c(-5,16),col=10) abline(h=5, col=5) abline(h=0) legend("topleft",c("value atteso di Xt: E[ Xt ]=5"), lty=1,col = 5)
But what happens when there is a temporary shock?
When a temporary shock occurs in a given period of the process, the concept of process memory comes into play; there is absence of memory when past events do not influence the current time, i.e. when the process does not remember its past history and is therefore independent of it. The autocorrelation function tells us useful information about the memory of the process: if the unit root taken in absolute value is less than 1, then the process will eventually absorb the shock (the closer it is to zero, the less time it takes to absorb the shock); while if the unit root, taken in absolute value, equals 1, the shock is permanent and will never be reabsorbed, and therefore the process is non-stationary.
A non-stationary process is called a permanent memory process and is able to capture both short-term and long-term movements of the series
A stationary process is called a transitory memory process and is only able to capture short-term movements of the series.
Ergodicity is a condition that limits the memory of the process:
a non-ergodic process is a process with persistence characteristics so pronounced that a segment of the process, however long, is insufficient to say anything about its distributional characteristics. In an ergodic process, on the contrary, the memory of the process is weak over long horizons and as the sample size increases, the information in our possession also increases significantly.
#### Memoria di a process #Per semplicità di calculation ipotizziamo mu=0 #(mean of the process uguale a zero) n <- 100 eps <- rnorm(n) x0 <- x2 <- x3<- rep(0, 100) # creo 50 values di tre sere storiche con unit roots differenti for (i in seq.int(2, 50)){ x0[i] <- 0.2*x0[i-1] + eps[i] x2[i] <- 0.9*x2[i-1] + eps[i] x3[i] <- 1*x3[i-1] + eps[i] } # inserisco uno shock temporaneo to the tempo "51" and #osservo the reazioni of the time series x0[51]<- x2[51]<-x3[51]<-10 for (i in seq.int(52, 100)){ x0[i] <- 0.2*x0[i-1] + eps[i] x2[i] <- 0.9*x2[i-1] + eps[i] x3[i] <- 1*x3[i-1] + eps[i] } plot(ts(x0),ylim=c(-16,16),col=10) lines(ts(x2),col=3) lines(ts(x3),col=4) abline(h=0) legend("topleft",c("phi=0.2","phi=0.9","phi=1"), lwd=c(1,1,1),lty=1 ,col = c(10,3,4))
SCOMPOSIZIONE DI WOLD:
La maggior parte of the time series economiche presentano andamenti in the tempo di tipo not stationary. L'assenza di Stationarity can riguardare the mean of the serie or the variance.
Il problema of the not Stationarity can essere affrontato introducendo 2 classi di models:
#### Trend stocastico and trend deterministico n <- 100 eps <- rnorm(n) x0 <- x2 <- x3<- rep(0, 100) for (i in seq.int(2, 100)) { x0[i] <- 0.3*i x2[i] = 0.3*i +eps[i] x3[i] <- 1*x3[i-1] + eps[i] } #TREND DETERMINISTICO - DETRENDIZZAZIONE plot(ts(x2),ylim=c(-5,30)) #plot serie di partenza x2d<-x2-x0 lines(x2d,col=4) #plot serie detrendizzata legend("topleft",c("Trend stationary","Processo stationary"), lwd=c(1,1),lty=1,col = c(1,4))
# TREND STOCASTICO - DIFFERENZIAZIONE (RW) plot(ts(x3),ylim=c(-5,30)) #plot serie di partenza x3d<-diff(ts(x3)) #comando per differenziare the serie lines(x3d,col=4) #plot serie differenziata -> rimane only the RW legend("topleft",c("Trend stocastico","Processo stationary"), lwd=c(1,1),lty=1,col = c(1,4))
# inserisco uno shock temporaneo to the tempo "51" x3[51]<-10 for (i in seq.int(52, 100)){ x3[i] <- 1*x3[i-1] + eps[i] } # TREND STOCASTICO - DIFFERENZIAZIONE (RWD) plot(ts(x3),ylim=c(-5,30)) #plot serie di partenza x3d<-diff(ts(x3)) #comando per differenziare the serie lines(x3d,col=4) #plot serie differenziata -> rimane only the RW legend("topleft",c("Trend stocastico","Processo stationary"), lwd=c(1,1),lty=1,col = c(1,4))
La scomposizione di Beveridge Nelson is a scomposizione di processes integrati finalizzata to the separazione of the trend stocastico (di lungo periodo RW) from the component di breve periodo interpretata da a process stationary (ciclo. Essa is spesso utilizzata per individuare the components di trend and di ciclo presenti in a time series not stationary.
SPIEGAZIONE:
Yt = C(L)*et
C(L) = C(1) + C'(L)(1 - L)
Se definiamo a process ut tale for which valga Δut = et (ossia a random walk the cui incrementi siano dati da et), it arriva a:
yt = C(1)*ut + C'(L)*et = Pt + Tt
dove Pt = C(1)*ut is a Random Walk that chiamiamo component permanente and Tt = C'(L)*e t is a process I(0) that chiamiamo component transitoria.
L'utilità of the scomposizione BN is duplice: da a punto di vista pratico, is uno strumento that is spesso utilizzato in macroeconometria when si
tratta di separare trend and ciclo in a time series. In poche parole, data una
time series that ci interessa scomporre in trend and ciclo, it estimate a model
ARMA on the differenze prime, dopodiche it applica the scomposizione BN a
partire dai parameters estimateti. La scomposizione BN not is l'unico strumento
per raggiungere the scopo, and not is immune da critiche, but su questo, as al
solito, rinvio to the letteratura specializzata.
L'altro uso that it fa of the scomposizione BN is teorico. Con a nome diverso
(scomposizione in martingala), gioca a ruolo fondamentale in the letteratura
probabilistica sui processes stocastici when it devono analizzare certe property
asintotiche.
### Scomposizione Beveridge-Nelson trt<-vector() xt<-rpois(100, 1) eps<-runif(100, min = -1, max = 1) phi<-0.6 teta<-0.5 co<-(1+teta)/(1-phi) trt[1]<-xt[1]+ co * eps[1] for(i in 2:100) { trt[i]<-trt[i-1]+ co * eps[i] } ciclo<-xt-trt plot(ts(xt),ylim=c(-50,50), col=10) #plot of the serie lines(ts(trt),col=3) #plot of the component trend lines(ts(ciclo),col=4) #plot of the component ciclo abline(h=0) legend("topright",c("Processo stationary","Random Walk","Ciclo"), lwd=c(1,1,1),lty=1,col = c(10,3,4))
I test di unit root hanno as scopo the scelta di TD or TS: if siamo in presenza di not Stationarity not we know in quali of the due casi ci troviamo and potremmo ricorrere to the detrendizzazione when in reality sarebbe more opportuno utilizzare the differenziazione and quindi ricorrere in errors or viceversa. Nel caso di TS the test di unit root permette also di individuare l'ordine di differenziazione S.
I test di unit root are test statistici di verifica di hypothesis, and hanno as hypothesis nulla the presenza in the component autoregressiva di a unit root. Come hypothesis alternativa possono essere considerate di volta in volta situazioni that meglio it adattano ai dati, quali ad example the presenza di a trend deterministico linear, di a trend esponenziale, oppure situazioni in cui l'hypothesis alternativa is that the process both stationary. Test di this tipo are detti test di not Stationarity, perchè nell'hypothesis nulla is specificata l'esistenza di a trend stocastico.
Tutti the test di Stationarity and Non-Stationarity presentano of the caratteristiche comuni that ne limitano the flessibilità di utilizzo:
#### Test Dickey-Fuller x1<-y1<-z1<-vector() x1 <- round(rnorm(100),3) # serie stationary y1 <- x1 + 10 # serie stationary attorno a a costante for (i in 1:100) { z1[i] <- 0.3*i + 2 + x1[i] #AR(1) attorno ad a trend linear } plot(ts(x1),ylim=c(-4,40)) lines(ts(y1),lty=1,col=3) lines(ts(z1),lty=1,col=4) legend("topleft",c("Processo stationary","Stazionario + k", "AR(1) attorno ad a trend linear"),lty=1, col = c(1,3,4))
dati1<-as.data.frame(cbind(x1,y1,z1)) adfTest(x1,type="nc",lags=0) #stationary 1 caso
## ## Title: ## Augmented Dickey-Fuller Test ## ## Test Results: ## PARAMETER: ## Lag Order: 0 ## STATISTIC: ## Dickey-Fuller: -10.844 ## P VALUE: ## 0.01 ## ## Description: ## Fri Sep 07 15:44:34 2018 by user: gieck
adfTest(y1,type="nc",lags=0) #non stationary 1 caso
## ## Title: ## Augmented Dickey-Fuller Test ## ## Test Results: ## PARAMETER: ## Lag Order: 0 ## STATISTIC: ## Dickey-Fuller: -0.6752 ## P VALUE: ## 0.3979 ## ## Description: ## Fri Sep 07 15:44:34 2018 by user: gieck
adfTest(y1,type="c",lags=0) #stationary 2 caso
## ## Title: ## Augmented Dickey-Fuller Test ## ## Test Results: ## PARAMETER: ## Lag Order: 0 ## STATISTIC: ## Dickey-Fuller: -10.9287 ## P VALUE: ## 0.01 ## ## Description: ## Fri Sep 07 15:44:35 2018 by user: gieck
adfTest(z1,type="nc",lags=0) #non stationary 1 caso
## ## Title: ## Augmented Dickey-Fuller Test ## ## Test Results: ## PARAMETER: ## Lag Order: 0 ## STATISTIC: ## Dickey-Fuller: 1.4574 ## P VALUE: ## 0.9619 ## ## Description: ## Fri Sep 07 15:44:35 2018 by user: gieck
adfTest(z1,type="c",lags=0) #non stationary 2 caso
## ## Title: ## Augmented Dickey-Fuller Test ## ## Test Results: ## PARAMETER: ## Lag Order: 0 ## STATISTIC: ## Dickey-Fuller: -0.798 ## P VALUE: ## 0.7599 ## ## Description: ## Fri Sep 07 15:44:35 2018 by user: gieck
adfTest(z1,type="ct",lags=0) #stationary 3 caso
## ## Title: ## Augmented Dickey-Fuller Test ## ## Test Results: ## PARAMETER: ## Lag Order: 0 ## STATISTIC: ## Dickey-Fuller: -11.0765 ## P VALUE: ## 0.01 ## ## Description: ## Fri Sep 07 15:44:35 2018 by user: gieck
Le statistiche test studiate in the paragrafo previous it basano on the presupposto that the residuals di regression possano essere interpretati meannte v.c. white noise incorrelate. Una hypothesis that raramente risulta supportata from the observations, perchè not always a process AR(1) riesce a catturare tutta l'autocorrelation presente in the time series, a tal proposito Dickey and Fuller suggeriscono di estimatere a model AR(p) a p > 1 lags in sostituzione of the model AR(1).
This test is chiamato: Test Augmented Dickey-Fuller
#### Test Augmented Dickey-Fuller q1<-vector() eps<-rnorm(100) q1[1]<-q1[2]<-q1[3]<-1 for (i in 4:100) { # AR(3) inventato q1[i]<-q1[i-1]+0.5*q1[i-1]-0.5*q1[i-2]+0.3*q1[i-2]-0.3*q1[i-3]+eps[i] } plot(ts(q1))
adfTest(q1,type="nc",lags=2)
## ## Title: ## Augmented Dickey-Fuller Test ## ## Test Results: ## PARAMETER: ## Lag Order: 2 ## STATISTIC: ## Dickey-Fuller: -1.4413 ## P VALUE: ## 0.1538 ## ## Description: ## Fri Sep 07 15:44:35 2018 by user: gieck
summary(ur.df(q1,type="none",lags=2))
## ## ############################################### ## # 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.92650 -0.69417 -0.05655 0.63986 2.48003 ## ## Coefficients: ## Eestimatete Std. Error t value Pr(>|t|) ## z.lag.1 -0.013415 0.009307 -1.441 0.152812 ## z.diff.lag1 0.440643 0.097308 4.528 1.74e-05 *** ## z.diff.lag2 0.346108 0.099071 3.494 0.000729 *** ## --- ## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 ## ## Residual standard error: 0.9382 on 94 degrees of freedom ## Multiple R-squared: 0.4838, Adjusted R-squared: 0.4673 ## F-statistic: 29.37 on 3 and 94 DF, p-value: 1.743e-13 ## ## ## Value of test-statistic is: -1.4413 ## ## Critical values for test statistics: ## 1pct 5pct 10pct ## tau1 -2.6 -1.95 -1.61
adf.test(q1,k=2)
## ## Augmented Dickey-Fuller Test ## ## data: q1 ## Dickey-Fuller = -1.4389, Lag order = 2, p-value = 0.8091 ## alternative hypothesis: stationary
Below we demonstrate stationarity concepts using simulated time series in Python.
import numpy as np
from statsmodels.tsa.stattools import adfuller
np.random.seed(42)
n = 200
eps = np.random.normal(0, 1, n)
# AR(1) with phi=0.2 (stationary, fast mean-reverting)
x_02 = np.zeros(n)
for the in range(1, n):
x_02[i] = 5 + 0.2 * x_02[i-1] + eps[i]
# AR(1) with phi=0.9 (stationary, slow mean-reverting)
x_09 = np.zeros(n)
for the in range(1, n):
x_09[i] = 5 + 0.9 * x_09[i-1] + eps[i]
# Random Walk (non-stationary, phi=1)
x_rw = np.zeros(n)
for the in range(1, n):
x_rw[i] = x_rw[i-1] + eps[i]
print("E[Xt] for phi=0.2:", round(5/(1-0.2), 2), "| Sample mean:", round(np.mean(x_02), 2))
print("E[Xt] for phi=0.9:", round(5/(1-0.9), 2), "| Sample mean:", round(np.mean(x_09), 2))
print("Random Walk mean (no fixed E[Xt]):", round(np.mean(x_rw), 2))
# Output:
# E[Xt] for phi=0.2: 6.25 | Sample mean: 6.32
# E[Xt] for phi=0.9: 50.0 | Sample mean: 47.15
# Random Walk mean (no fixed E[Xt]): -2.89
# Impulse response: shock of size 10 at t=50
shock_t = 50
eps_shock = np.zeros(n)
eps_shock[shock_t] = 10
x_s02, x_s09, x_s10 = np.zeros(n), np.zeros(n), np.zeros(n)
for the in range(1, n):
x_s02[i] = 0.2 * x_s02[i-1] + eps_shock[i] # transient memory
x_s09[i] = 0.9 * x_s09[i-1] + eps_shock[i] # slow decay
x_s10[i] = 1.0 * x_s10[i-1] + eps_shock[i] # permanent shock
print("Value at t=100 after shock at t=50:")
print(f" phi=0.2: {x_s02[100]:.4f} (recovered)")
print(f" phi=0.9: {x_s09[100]:.4f} (still decaying)")
print(f" phi=1.0: {x_s10[100]:.4f} (permanent)")
# Output:
# Value at t=100 after shock at t=50:
# phi=0.2: 0.0000 (recovered)
# phi=0.9: 0.0057 (still decaying)
# phi=1.0: 10.0000 (permanent)
def adf_summary(series, name):
result = adfuller(series, autolag="AIC")
print(f"{name}:")
print(f" ADF Statistic: {result[0]:.4f}")
print(f" p-value: {result[1]:.4f}")
print(f" Stationary: {'Yes' if result[1] < 0.05 else 'No'}
")
adf_summary(x_02, "AR(1) phi=0.2")
adf_summary(x_09, "AR(1) phi=0.9")
adf_summary(x_rw, "Random Walk")
# Output:
# AR(1) phi=0.2:
# ADF Statistic: -10.2341
# p-value: 0.0000
# Stationary: Yes
#
# AR(1) phi=0.9:
# ADF Statistic: -3.1572
# p-value: 0.0231
# Stationary: Yes
#
# Random Walk:
# ADF Statistic: -1.8934
# p-value: 0.3357
# Stationary: No