El análisis de series temporales es fundamental en econometría porque permite estudiar la evolución de variables económicas como el producto interno bruto, la inflación, el desempleo y las tasas de interés. Antes de estimar relaciones entre estas variables es importante examinar sus propiedades estadísticas para evitar conclusiones engañosas.
La prueba de raíz unitaria de Dickey-Fuller permite evaluar la presencia de una raíz unitaria en una serie temporal. La prueba de cointegración de Johansen permite investigar relaciones de equilibrio de largo plazo entre series integradas, mientras que la causalidad en el sentido de Granger permite determinar si los valores pasados de una variable aportan información para predecir otra. La causalidad de Granger no demuestra causalidad en sentido estricto.
El objetivo de este informe es explicar el propósito, las hipótesis, la implementación en R, los estadísticos y los criterios de decisión de estas pruebas, así como ilustrar su aplicación. Esta sección desarrolla la prueba de Dickey-Fuller aumentada mediante un ejemplo reproducible.
La prueba de Dickey-Fuller examina si una serie temporal presenta una raíz unitaria. Una serie con raíz unitaria es no estacionaria; por el contrario, una serie estacionaria en sentido débil tiene media y varianza constantes y una autocovarianza que depende del rezago y no del momento en que se mide. Identificar estas características ayuda a seleccionar transformaciones y modelos adecuados.
El modelo autorregresivo de primer orden es:
\[ Y_t = \rho Y_{t-1} + \varepsilon_t \]
Al restar \(Y_{t-1}\) de ambos lados, se obtiene:
\[ \Delta Y_t = \gamma Y_{t-1} + \varepsilon_t, \qquad \gamma = \rho - 1 \]
Las hipótesis son:
\[ H_0: \gamma = 0 \quad \text{(existe raíz unitaria)} \]
\[ H_1: \gamma < 0 \quad \text{(no existe raíz unitaria)} \]
Bajo \(H_0\), \(\rho=1\) y los choques pueden tener efectos permanentes. Bajo \(H_1\), y bajo las condiciones de estabilidad del modelo, la serie es estacionaria. En la versión aumentada se incluyen rezagos de las primeras diferencias para controlar la autocorrelación:
\[ \Delta Y_t = a + bt + \gamma Y_{t-1} + \sum_{i=1}^{k} \delta_i \Delta Y_{t-i} + \varepsilon_t \]
Aquí \(a\) representa una constante,
\(bt\) una tendencia determinística y
\(k\) el número de rezagos adicionales.
La función tseries::adf.test() incluye constante y
tendencia lineal.
La función utilizada es
adf.test(x, alternative = "stationary", k = 3) del paquete
tseries.
x: serie temporal numérica que se analiza.alternative = "stationary": indica que la hipótesis
alternativa es estacionariedad.k = 3: incluye tres rezagos de las primeras diferencias
para controlar la autocorrelación. En aplicaciones empíricas, la
elección de rezagos debe justificarse.El estadístico de Dickey-Fuller se calcula a partir del coeficiente estimado de la variable rezagada:
\[ \tau = \frac{\widehat{\gamma}}{SE(\widehat{\gamma})} \]
En la salida de R se identifica como Dickey-Fuller. Bajo
la hipótesis nula, este estadístico no sigue la distribución t
convencional. adf.test() informa también un valor p
aproximado.
Se utilizará un nivel de significancia de \(\alpha=0.05\):
En un procedimiento basado en valores críticos, se rechaza \(H_0\) si el estadístico es más negativo que el valor crítico de Dickey-Fuller correspondiente a la especificación del modelo.
Rechazar \(H_0\) aporta evidencia de estacionariedad bajo la especificación considerada. No rechazar \(H_0\) no demuestra que exista una raíz unitaria: indica que los datos no proporcionan evidencia suficiente para rechazarla. En ese caso puede examinarse la serie en primeras diferencias y contrastar nuevamente.
Se genera un paseo aleatorio con 120 observaciones mensuales. Como el proceso se construye acumulando perturbaciones aleatorias, tiene raíz unitaria por diseño. Luego se calculan primeras diferencias y se vuelve a aplicar la prueba.
set.seed(123)
serie <- ts(cumsum(rnorm(120)), start = c(2015, 1), frequency = 12)
plot(serie, main = "Serie original: paseo aleatorio",
xlab = "Año", ylab = "Valor de la serie", col = "steelblue")##
## Augmented Dickey-Fuller Test
##
## data: serie
## Dickey-Fuller = -2.4499, Lag order = 3, p-value = 0.3897
## alternative hypothesis: stationary
serie_dif <- diff(serie)
plot(serie_dif, main = "Serie en primeras diferencias",
xlab = "Año", ylab = "Primera diferencia", col = "darkgreen")resultado_diferencias <- adf.test(serie_dif, alternative = "stationary", k = 3)
print(resultado_diferencias)##
## Augmented Dickey-Fuller Test
##
## data: serie_dif
## Dickey-Fuller = -5.2745, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary
alpha <- 0.05
resumen <- data.frame(
Serie = c("Original (niveles)", "Primera diferencia"),
Estadistico_DF = c(unname(resultado_niveles$statistic),
unname(resultado_diferencias$statistic)),
Valor_p = c(resultado_niveles$p.value, resultado_diferencias$p.value)
)
resumen$Decision <- ifelse(resumen$Valor_p < alpha,
"Rechazar H0", "No rechazar H0")
knitr::kable(resumen, digits = 4,
caption = "Resultados de la prueba Dickey-Fuller aumentada")| Serie | Estadistico_DF | Valor_p | Decision |
|---|---|---|---|
| Original (niveles) | -2.4499 | 0.3897 | No rechazar H0 |
| Primera diferencia | -5.2745 | 0.0100 | Rechazar H0 |
Interpretación: Para la serie original, el valor p es 0.39; por tanto, no se rechaza la hipótesis nula y no se puede descartar la presencia de una raíz unitaria. Para la primera diferencia, el valor p es 0.01; por tanto, se rechaza la hipótesis nula, lo que respalda la estacionariedad de la serie diferenciada.
Este ejemplo es ilustrativo y utiliza datos simulados, no observaciones de una variable económica real. La interpretación se refiere al nivel de significancia y a la especificación de la prueba elegidos
La gran mayoría de las variables económicas (como los precios, el producto interno bruto, el consumo o los salarios) no son estacionarias a nivel; es decir, cambian a lo largo del tiempo mostrando tendencias estocásticas. Cuando intentamos hacer una regresión lineal común (MCO) con dos o más variables no estacionarias, corremos el riesgo de obtener una regresión espuria (Granger y Newbold, 1974): un resultado que parece mostrar una relación estadística fuerte (\(R^2\) alto y coeficientes significativos) cuando en realidad las variables no tienen ningún vínculo real.
El método inicial de Engle y Granger (1987) permitió evaluar la cointegración, pero presenta dos limitantes graves: 1. Obliga a elegir de forma arbitraria cuál es la variable dependiente y cuál la independiente, lo que puede cambiar los resultados. 2. Solo puede buscar una sola relación de largo plazo, siendo inútil si tenemos tres o más variables.
La prueba desarrollada por Søren Johansen (1988, 1991) resuelve estas limitantes mediante un marco multivariado basado en Vectores Autorregresivos (VAR).
Su propósito principal es: 1. Determinar cuántas relaciones lineales de largo plazo (vectores de cointegración, \(r\)) existen entre un conjunto de múltiples variables no estacionarias \(I(1)\). 2. Analizar cómo las variables se corrigen en el corto plazo cuando se desvían de su punto de equilibrio, mediante la estimación de un Modelo VEC (Vector de Corrección de Errores).
El procedimiento parte de un modelo VAR de \(k\) retardos reescrito como un Modelo de Corrección de Errores Vectorial (VECM):
\[ \Delta Y_t = \Pi Y_{t-1} + \sum_{i=1}^{k-1} \Gamma_i \Delta Y_{t-i} + \mu + \epsilon_t \]
Donde:
El rango de la matriz \(\Pi\) (\(r\)) nos indica directamente qué está pasando con las variables:
Johansen propone dos pruebas estadísticas basadas en los valores propios (o eigenvalores, \(\lambda\)) de la matriz \(\Pi\). A continuación se explican las hipótesis de manera sencilla:
Esta prueba analiza de forma acumulativa la cantidad de vectores de cointegración.
Planteamiento formal: * Hipótesis Nula (\(H_0: r \le r_0\)): El número de vectores de cointegración (\(r\)) es menor o igual a \(r_0\). * Hipótesis Alternativa (\(H_1: r > r_0\)): El número de vectores de cointegración (\(r\)) es estrictamente mayor que \(r_0\).
Fórmula del estadístico: \[ \lambda_{trace}(r_0) = -T \sum_{i=r_0+1}^{n} \ln(1 - \hat{\lambda}_i) \]
A diferencia de la Traza, esta prueba es paso a paso e incremental: evalúa si pasar de \(r_0\) a exactamente \(r_0 + 1\) vectores aporta significancia estadística.
Planteamiento formal: * Hipótesis Nula (\(H_0: r = r_0\)): Existen exactamente \(r_0\) vectores de cointegración. * Hipótesis Alternativa (\(H_1: r = r_0 + 1\)): Existen exactamente \(r_0 + 1\) vectores de cointegración.
Fórmula del estadístico: \[ \lambda_{max}(r_0, r_0+1) = -T \ln(1 - \hat{\lambda}_{r_0+1}) \]
Para realizar la prueba de Johansen en R se utiliza la función
ca.jo() de la librería urca.
# Sintaxis completa en R
library(urca)
modelo_johansen <- ca.jo(
x = datos,
type = "eigen",
ecdet = "const",
K = 2,
spec = "longrun"
)
summary(modelo_johansen)x: Matriz o marco de datos (data.frame)
que contiene las variables temporales a nivel \(I(1)\).type: Especifica la prueba a realizar. Puede ser
"trace" (Prueba de la Traza) o "eigen" (Prueba
del Máximo Valor Propio).ecdet: Indica la presencia de componentes
determinísticos en la ecuación de cointegración:
"none": Sin constante ni tendencia."const": Incluye constante (intercepto)."trend": Incluye tendencia lineal.K: Representa el número de retardos (lags) del
modelo VAR en niveles subyacente. (Nota: El modelo
VEC resultante usará \(K-1\) retardos
en diferencias).spec: Define el tipo de parametrización del modelo VEC.
Se utiliza "longrun" para enfocarse en la relación de largo
plazo o "transitory" para enfatizar la dinámica de corto
plazo.R no muestra directamente un valor \(p\) (\(p\text{-value}\)) convencional en esta prueba, sino que presenta una tabla con el estadístico calculado y los valores críticos asintóticos.
test
(Estadístico de prueba).5pct).El proceso se realiza en orden estricto de arriba hacia abajo:
library(wbstats)
library(dplyr)
library(tidyr)
# Indicadores del Banco Mundial
indicadores <- c(
Consumo = "NE.CON.PRVT.KD",
PIB = "NY.GDP.MKTP.KD"
)
# Descargar datos de El Salvador
datos <- wb_data(
country = "SLV",
indicator = indicadores,
start_date = 2000,
end_date = 2024
)
# Mostrar los primeros registros
head(datos)## Clave <iso3c>
## iso2c iso3c country date Consumo PIB
## <char> <char> <char> <num> <num> <num>
## 1: SV SLV El Salvador 2000 15643275859 17621447036
## 2: SV SLV El Salvador 2001 15851642189 17776447691
## 3: SV SLV El Salvador 2002 15970985833 18056056716
## 4: SV SLV El Salvador 2003 16096384943 18338704970
## 5: SV SLV El Salvador 2004 16350957198 18501810235
## 6: SV SLV El Salvador 2005 17012246854 18997812331
Utilizamos dplyr::select() para crear una nueva base
llamada base_johansen, que contiene únicamente la fecha, el
consumo y el PIB. Estas son las variables que utilizaremos en el
análisis de cointegración de Johansen.
library(wbstats)
library(dplyr)
library(tidyr)
# Indicadores del Banco Mundial
indicadores <- c(
Consumo = "NE.CON.PRVT.KD",
PIB = "NY.GDP.MKTP.KD"
)
# Descargar datos de El Salvador
datos <- wb_data(
country = "SLV",
indicator = indicadores,
start_date = 2000,
end_date = 2024
)
# Seleccionar las variables de estudio
base_johansen <- datos %>%
dplyr::select(date, Consumo, PIB)
# Mostrar resultados
print(base_johansen)## Clave <iso3c>
## date Consumo PIB
## <num> <num> <num>
## 1: 2000 15643275859 17621447036
## 2: 2001 15851642189 17776447691
## 3: 2002 15970985833 18056056716
## 4: 2003 16096384943 18338704970
## 5: 2004 16350957198 18501810235
## 6: 2005 17012246854 18997812331
## 7: 2006 17764554572 19821747187
## 8: 2007 19025818470 20187974225
## 9: 2008 18951820206 20622904544
## 10: 2009 17711613152 20188015255
## 11: 2010 17880387192 20622904544
## 12: 2011 18159387055 21407994006
## 13: 2012 18746643729 22012261123
## 14: 2013 19395041332 22504372601
## 15: 2014 19363874569 22888906230
## 16: 2015 19939740000 23438240000
## 17: 2016 20332511725 24033351542
## 18: 2017 20670789092 24573529737
## 19: 2018 20947864104 25166352436
## 20: 2019 21302013482 25779775127
## 21: 2020 19570668970 23744951346
## 22: 2021 21439840148 26571731219
## 23: 2022 21419540980 27356820682
## 24: 2023 22388093664 28274665875
## 25: 2024 22866617462 29007110834
## date Consumo PIB
## [1] 25 3
## date Consumo PIB
## 0 0 0
## date Consumo PIB
## Min. :2000 Min. :1.564e+10 Min. :1.762e+10
## 1st Qu.:2006 1st Qu.:1.771e+10 1st Qu.:1.982e+10
## Median :2012 Median :1.903e+10 Median :2.201e+10
## Mean :2012 Mean :1.899e+10 Mean :2.230e+10
## 3rd Qu.:2018 3rd Qu.:2.067e+10 3rd Qu.:2.457e+10
## Max. :2024 Max. :2.287e+10 Max. :2.901e+10
Ahora necesitamos observar cómo se han comportado las exportaciones , el consumo y el PIB durante el período de estudio.
## Visualizar las variables
## Observar el comportamiento del consumo y el PIB durante el período de estudio (2000-2024).
# Configurar gráficos
par(mfrow = c(2,1))
# Gráfico de consumo
plot(base_johansen$date, base_johansen$Consumo,
type = "l",
col = "red",
lwd = 2,
main = "Evolución del consumo de los hogares",
xlab = "Año",
ylab = "Dólares constantes de 2015")
# Gráfico del PIB
plot(base_johansen$date, base_johansen$PIB,
type = "l",
col = "darkgreen",
lwd = 2,
main = "Evolución del PIB",
xlab = "Año",
ylab = "Dólares constantes de 2015")EEntre 2000 y 2024, el consumo de los hogares y el PIB (en dólares constantes de 2015) muestran una tendencia creciente y se mueven de forma muy similar. Ambos presentan una caída en 2009 por la crisis financiera y otra en 2020 por la pandemia, seguidas de una recuperación rápida, con el consumo algo más sensible a esos choques. Esta evolución conjunta sugiere una posible relación de largo plazo, que debe confirmarse con pruebas de raíz unitaria y cointegración.
## Transformación de las variables económicas a escala logarítmica
# Aplicar logaritmos naturales
base_log <- data.frame(
date = base_johansen$date,
log_Consumo = log(base_johansen$Consumo),
log_PIB = log(base_johansen$PIB)
)
# Mostrar resultados
head(base_log)## date log_Consumo log_PIB
## 1 2000 23.47331 23.59238
## 2 2001 23.48654 23.60114
## 3 2002 23.49404 23.61675
## 4 2003 23.50186 23.63228
## 5 2004 23.51755 23.64113
## 6 2005 23.55720 23.66759
## [1] "date" "log_Consumo" "log_PIB"
## Aplicar ADF a las variables en niveles
library(urca)
# ADF para consumo
adf_Consumo <- ur.df(
base_log$log_Consumo,
type = "trend",
selectlags = "AIC"
)
summary(adf_Consumo)##
## ###############################################
## # 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
## -0.086315 -0.018703 0.009391 0.013882 0.067389
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 17.187619 5.982926 2.873 0.00974 **
## z.lag.1 -0.731647 0.254964 -2.870 0.00981 **
## tt 0.010568 0.003815 2.770 0.01220 *
## z.diff.lag 0.157471 0.226649 0.695 0.49560
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03228 on 19 degrees of freedom
## Multiple R-squared: 0.3325, Adjusted R-squared: 0.2271
## F-statistic: 3.155 on 3 and 19 DF, p-value: 0.04876
##
##
## Value of test-statistic is: -2.8696 5.0205 4.1174
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau3 -4.38 -3.60 -3.24
## phi2 8.21 5.68 4.67
## phi3 10.61 7.24 5.91
# ADF para PIB
adf_PIB <- ur.df(
base_log$log_PIB,
type = "trend",
selectlags = "AIC"
)
summary(adf_PIB)##
## ###############################################
## # 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
## -0.088637 -0.003244 0.003582 0.012498 0.028695
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 25.552490 7.912009 3.230 0.00441 **
## z.lag.1 -1.084396 0.336039 -3.227 0.00444 **
## tt 0.022313 0.006745 3.308 0.00370 **
## z.diff.lag 0.155259 0.241727 0.642 0.52836
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.02495 on 19 degrees of freedom
## Multiple R-squared: 0.4652, Adjusted R-squared: 0.3807
## F-statistic: 5.508 on 3 and 19 DF, p-value: 0.00679
##
##
## Value of test-statistic is: -3.227 11.053 5.5947
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau3 -4.38 -3.60 -3.24
## phi2 8.21 5.68 4.67
## phi3 10.61 7.24 5.91
Con un nivel de significancia del 5%, comparamos el estadístico \(\tau_3\) con el valor crítico de -3.60.
| Variable | Estadístico ADF | Valor crítico 5% | Decisión |
|---|---|---|---|
| Consumo | -2.8696 | -3.60 | No se rechaza H₀ |
| PIB | -3.2270 | -3.60 | No se rechaza H₀ |
Interpretación:
## Aplicar ADF a las primeras diferencias
# ADF para consumo
adf_d_Consumo <- ur.df(
diff(base_log$log_Consumo),
type = "drift",
selectlags = "AIC"
)
summary(adf_d_Consumo)##
## ###############################################
## # 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
## -0.100891 -0.007018 0.000837 0.019754 0.059346
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.020330 0.009837 2.067 0.05267 .
## z.lag.1 -1.259663 0.360473 -3.494 0.00243 **
## z.diff.lag 0.042058 0.232797 0.181 0.85855
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03855 on 19 degrees of freedom
## Multiple R-squared: 0.6054, Adjusted R-squared: 0.5638
## F-statistic: 14.57 on 2 and 19 DF, p-value: 0.0001458
##
##
## Value of test-statistic is: -3.4945 6.1214
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.75 -3.00 -2.63
## phi1 7.88 5.18 4.12
# ADF para PIB
adf_d_PIB <- ur.df(
diff(base_log$log_PIB),
type = "drift",
selectlags = "AIC"
)
summary(adf_d_PIB)##
## ###############################################
## # 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
## -0.101567 -0.002334 0.004003 0.010692 0.042940
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.03563 0.01010 3.528 0.002250 **
## z.lag.1 -1.67812 0.37441 -4.482 0.000255 ***
## z.diff.lag 0.20549 0.22446 0.915 0.371417
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03069 on 19 degrees of freedom
## Multiple R-squared: 0.7091, Adjusted R-squared: 0.6785
## F-statistic: 23.16 on 2 and 19 DF, p-value: 8.049e-06
##
##
## Value of test-statistic is: -4.4821 10.0601
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.75 -3.00 -2.63
## phi1 7.88 5.18 4.12
Comparamos el estadístico \(\tau_2\) con el valor crítico de -3.00 al 5%.
| Variable | Estadístico ADF | Valor crítico 5% | Decisión |
|---|---|---|---|
| Consumo | -3.4945 | -3.00 | Se rechaza H₀ |
| PIB | -4.4821 | -3.00 | Se rechaza H₀ |
Interpretación:
Como ambas variables no son estacionarias en niveles, pero sí son estacionarias en primeras diferencias, se consideran integradas de orden uno, es decir, I(1).
Por tanto, se cumple la condición inicial para continuar con la prueba de cointegración de Johansen.
## Selección del número óptimo de rezagos
library(vars)
library(urca)
# Organizar las variables
data_johansen <- cbind(
Consumo = base_log$log_Consumo,
PIB = base_log$log_PIB
)
# Seleccionar el número de rezagos
seleccion_rezagos <- VARselect(
data_johansen,
lag.max = 3,
type = "const"
)
# Mostrar los criterios de selección
seleccion_rezagos$selection## AIC(n) HQ(n) SC(n) FPE(n)
## 3 1 1 1
## 1 2 3
## AIC(n) -1.460783e+01 -1.457084e+01 -1.461314e+01
## HQ(n) -1.453774e+01 -1.445401e+01 -1.444958e+01
## SC(n) -1.431028e+01 -1.407491e+01 -1.391884e+01
## FPE(n) 4.543426e-07 4.775088e-07 4.714857e-07
Como tres de los cuatro criterios seleccionan 1 rezago y contamos con solo 25 observaciones anuales, utilizaremos 1 rezago para continuar con el análisis de Johansen.
## Prueba de cointegración de Johansen
library(urca)
# Aplicar la prueba de Johansen
johansen <- ca.jo(
data_johansen,
type = "trace",
ecdet = "const",
K = 2,
spec = "transitory"
)
# Mostrar resultados
summary(johansen)##
## ######################
## # Johansen-Procedure #
## ######################
##
## Test type: trace statistic , without linear trend and constant in cointegration
##
## Eigenvalues (lambda):
## [1] 4.966707e-01 2.519711e-01 -7.771561e-16
##
## Values of teststatistic and critical values of test:
##
## test 10pct 5pct 1pct
## r <= 1 | 6.68 7.52 9.24 12.97
## r = 0 | 22.47 17.85 19.96 24.60
##
## Eigenvectors, normalised to first column:
## (These are the cointegration relations)
##
## Consumo.l1 PIB.l1 constant
## Consumo.l1 1.000000 1.000000 1.000000
## PIB.l1 -0.777737 -0.682084 -1.465204
## constant -5.203833 -7.407621 11.236263
##
## Weights W:
## (This is the loading matrix)
##
## Consumo.l1 PIB.l1 constant
## Consumo.d -0.4454855 -0.39263289 2.117138e-12
## PIB.d -0.4800990 0.01424845 2.247854e-12
Los resultados de la prueba de Johansen, mediante el estadístico de traza y con un nivel de significancia del 5%, muestran que se rechaza la hipótesis nula de ausencia de cointegración, debido a que el estadístico de 22.47 supera el valor crítico de 19.96.
Por otra parte, no se rechaza la hipótesis nula de que existe como máximo una relación de cointegración, ya que el estadístico de 6.68 es inferior al valor crítico de 9.24.
En consecuencia, se identifica una relación de cointegración entre el consumo de los hogares y el PIB de El Salvador, lo que indica que ambas variables mantienen una relación de equilibrio de largo plazo durante el período 2000–2024.
Como encontramos una relación de cointegración, podemos estimar un modelo de corrección de errores vectorial (VECM).
## Estimación del modelo VECM
vecm <- cajorls(
johansen,
r = 1
)
# Mostrar resultados
summary(vecm$rlm)## Response Consumo.d :
##
## Call:
## lm(formula = Consumo.d ~ ect1 + Consumo.dl1 + PIB.dl1 - 1, data = data.mat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.101752 -0.013107 0.000047 0.014069 0.065103
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## ect1 -0.4455 0.1248 -3.571 0.00191 **
## Consumo.dl1 0.4561 0.3874 1.177 0.25286
## PIB.dl1 -0.8396 0.4522 -1.857 0.07815 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03291 on 20 degrees of freedom
## Multiple R-squared: 0.3897, Adjusted R-squared: 0.2981
## F-statistic: 4.257 on 3 and 20 DF, p-value: 0.01768
##
##
## Response PIB.d :
##
## Call:
## lm(formula = PIB.d ~ ect1 + Consumo.dl1 + PIB.dl1 - 1, data = data.mat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.102151 -0.007933 0.004221 0.012188 0.040933
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## ect1 -0.4801 0.1081 -4.441 0.000251 ***
## Consumo.dl1 0.3997 0.3357 1.191 0.247780
## PIB.dl1 -0.7732 0.3919 -1.973 0.062448 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.02852 on 20 degrees of freedom
## Multiple R-squared: 0.5003, Adjusted R-squared: 0.4253
## F-statistic: 6.674 on 3 and 20 DF, p-value: 0.002653
Los resultados respaldan la existencia de una relación de equilibrio de largo plazo entre el consumo de los hogares y el PIB de El Salvador durante 2000–2024. Esto se demuestra mediante la prueba de Johansen, cuyo estadístico fue de 22.47, superior al valor crítico de 19.96 al 5%, identificando una relación de cointegración. Además, el modelo VECM muestra que el consumo corrige aproximadamente el 44.55% de los desequilibrios y el PIB el 48.01% en cada período anual. Esto significa que ambas variables contribuyen a recuperar su equilibrio de largo plazo.
La prueba de causalidad de Granger se utiliza para determinar si una serie temporal aporta información útil para predecir otra (Granger, 1969). En esencia, verifica si los valores pasados de una variable \(X\) ayudan a mejorar la predicción de los valores futuros de otra variable \(Y\), más allá de lo que \(Y\) puede predecirse a partir de su propia historia.
Su propósito central es evaluar si una variable contiene información predictiva única sobre otra, partiendo del principio de que el pasado puede influir en el futuro. Es importante aclarar que la causalidad de Granger no implica causalidad real o teórica, sino una relación basada únicamente en la precedencia temporal y en la capacidad predictiva de las series.
Además, la prueba debe aplicarse a series estacionarias. Si las series son \(I(1)\) conviene trabajarlas en primeras diferencias (o en variaciones), y si están cointegradas corresponde usar un modelo de corrección de errores (Hamilton, 1994; Pfaff, 2008a).
La prueba determina si una serie temporal \(X\) tiene la capacidad de predecir otra serie temporal \(Y\). Esto se hace mediante la comparación de dos modelos de regresión: uno que incluye los valores pasados (rezagados) de \(X\) y otro que no los incluye.
Modelo 1: con valores pasados de X (modelo no restringido)
\[ Y_t = \alpha_0 + \alpha_1 Y_{t-1} + \alpha_2 Y_{t-2} + \dots + \alpha_p Y_{t-p} + \beta_1 X_{t-1} + \beta_2 X_{t-2} + \dots + \beta_p X_{t-p} + \varepsilon_t \]
Donde:
Modelo 2: sin valores pasados de X (modelo restringido)
Este modelo solo incluye los valores rezagados de \(Y\) para predecir el valor actual de \(Y\), sin considerar la serie \(X\):
\[ Y_t = \alpha_0 + \alpha_1 Y_{t-1} + \alpha_2 Y_{t-2} + \dots + \alpha_p Y_{t-p} + \varepsilon_t \]
Los componentes son los mismos que en el Modelo 1, pero no se incluyen los valores rezagados de \(X\).
Hipótesis nula (\(H_0\)). Establece que la serie temporal \(X\) no causa a la serie temporal \(Y\) en el sentido de Granger, es decir, \(\beta_1 = \beta_2 = \dots = \beta_p = 0\). Esto implica que los valores pasados de \(X\) no proporcionan información útil para predecir \(Y\). Se toma como punto de partida porque se busca evidencia suficiente para rechazarla.
Hipótesis alternativa (\(H_1\)). Propone que la serie temporal \(X\) sí causa a la serie temporal \(Y\) en el sentido de Granger, es decir, que al menos un \(\beta_j \neq 0\). Su aceptación implica que existe una relación de predecibilidad entre las dos series.
Para llevar a cabo la prueba de causalidad de Granger en R se utiliza
la función grangertest() del paquete lmtest
(Zeileis y Hothorn, 2002):
Donde:
| Argumento | Explicación |
|---|---|
y ~ x |
Fórmula. y es la variable dependiente, es decir, la
serie que se desea predecir o la serie “causada”; x es la
variable independiente, que se utiliza para predecir y,
conocida como la serie “causal”. Se contrasta si x
causa a la Granger a y. |
order |
Número entero que indica cuántos rezagos se incluirán en la prueba.
El valor por defecto es 1, lo que significa que solo se
considera el valor inmediato anterior. Por ejemplo, si
order = 3 se incluyen los valores de los tres períodos
anteriores. |
data |
Data frame (o serie ts) que contiene las variables de
la fórmula. |
na.action |
Tratamiento de valores faltantes (por defecto
na.omit). |
... |
Argumentos adicionales que se pasan a waldtest(), por
ejemplo test = "Chisq" para usar el estadístico \(\chi^2\) en lugar de \(F\). |
La función toma como argumentos principales las dos series de tiempo
(\(x\) e \(y\)) y busca determinar si x
tiene un efecto causal de Granger sobre y.
El argumento order define cuántos rezagos se incluirán
en el análisis. La selección del número de rezagos debe basarse en la
teoría económica, en el conocimiento del proceso o en criterios
estadísticos como el AIC o el BIC, y es común probar diferentes valores
para este argumento.
La función genera un estadístico de prueba \(F\) y un valor \(p\). Si el valor \(p\) es menor que el nivel de significancia establecido (por ejemplo, \(0.05\)), se rechaza la hipótesis nula de no causalidad de Granger.
En la prueba de causalidad de Granger se utiliza un estadístico \(F\) para comparar el Modelo 1 (no restringido) con el Modelo 2 (restringido). Sea \(RSS_R\) la suma de cuadrados de los residuos del modelo restringido, \(RSS_{NR}\) la del no restringido y \(T\) el número de observaciones utilizadas:
\[ F = \frac{(RSS_R - RSS_{NR})/p}{RSS_{NR}/(T - 2p - 1)} \;\sim\; F_{(p,\; T-2p-1)} \quad \text{bajo } H_0 \]
Al ejecutar la función en R se genera una salida que incluye varios componentes clave:
x y la variabilidad no explicada. Un
valor \(F\) más alto sugiere que los
rezagos de x tienen un efecto significativo en la
predicción de y.Pr(>F)): se utiliza para determinar la
significancia estadística del estadístico \(F\). Si el valor \(p\) es menor que el nivel de significancia
establecido (por ejemplo, \(0.05\)), se
rechaza la hipótesis nula de no causalidad de Granger, lo que sugiere
que x causa a y en el sentido de Granger.Ejemplo de salida en R. Al ejecutar la prueba, la salida tiene las siguientes columnas:
Res.Df: grados de libertad residuales para cada
modelo.Df: diferencia en los grados de libertad entre los dos
modelos (es igual a \(p\)).F: estadístico de prueba \(F\) calculado.Pr(>F): valor \(p\)
asociado al estadístico \(F\).Criterio de decisión: se rechaza \(H_0\) si \(p\text{-valor} < \alpha\) (equivalentemente, si \(F > F_{\alpha,(p,\,T-2p-1)}\)).
Antes del ejemplo se define una función para simular series autorregresivas estacionarias, otra para resumir el resultado de cada prueba y otra para redactar la conclusión según el valor \(p\) obtenido. Los datos del ejemplo son simulados y se expresan como variaciones porcentuales, por lo que son estacionarios por construcción.
library(lmtest)
library(urca)
# Serie AR(1) estacionaria
sim_ar <- function(n, phi, sd = 1) {
x <- numeric(n)
e <- rnorm(n, sd = sd)
x[1] <- e[1]
for (i in 2:n) x[i] <- phi * x[i - 1] + e[i]
x
}
# Extrae F, gl y valor p de un objeto grangertest
resumen <- function(g, causa, efecto, alfa = 0.05) {
data.frame(
Hipotesis = paste(causa, "->", efecto),
Res.Df = g$Res.Df[2],
Df = g$Df[2],
F = round(g$F[2], 3),
p_valor = round(g$`Pr(>F)`[2], 4),
Decision = ifelse(g$`Pr(>F)`[2] < alfa, "Rechaza H0", "No rechaza H0"),
row.names = NULL
)
}
# Redacta la conclusión de una prueba
concl <- function(g, causa, efecto, alfa = 0.05) {
pv <- g$`Pr(>F)`[2]
if (pv < alfa) {
paste0("Como el valor p (", round(pv, 4), ") es menor que ", alfa,
", se rechaza H0: **", causa, " sí Granger-causa ", efecto, "**.")
} else {
paste0("Como el valor p (", round(pv, 4), ") es mayor o igual que ", alfa,
", no se rechaza H0: **no hay evidencia de que ", causa,
" Granger-cause ", efecto, "**.")
}
}
# Prueba ADF (con constante): estadístico tau vs. crítico al 5%
adf <- function(x) {
t <- ur.df(x, type = "drift", lags = 2, selectlags = "AIC")
c(Estadistico = round(t@teststat[1, "tau2"], 3),
Critico_5pct = round(t@cval["tau2", "5pct"], 3))
}Se simulan 200 observaciones de las variaciones porcentuales del precio del petróleo y de la inflación. Se construyen de forma independiente, de modo que no debería haber relación predictiva entre ellas.
Petróleo → Inflación
Inflación → Petróleo
set.seed(2024)
# Datos simulados: dos series estacionarias independientes
t <- 200
petroleo <- sim_ar(t, phi = 0.5, sd = 1.0)
inflacion <- sim_ar(t, phi = 0.4, sd = 0.8)
data1 <- data.frame(petroleo, inflacion)
# Prueba en un sentido: petróleo -> inflación
granger_1 <- grangertest(inflacion ~ petroleo, order = 2, data = data1)
# Prueba en el sentido contrario: inflación -> petróleo
granger_2 <- grangertest(petroleo ~ inflacion, order = 2, data = data1)
granger_1## Granger causality test
##
## Model 1: inflacion ~ Lags(inflacion, 1:2) + Lags(petroleo, 1:2)
## Model 2: inflacion ~ Lags(inflacion, 1:2)
## Res.Df Df F Pr(>F)
## 1 193
## 2 195 -2 1.6668 0.1916
## Granger causality test
##
## Model 1: petroleo ~ Lags(petroleo, 1:2) + Lags(inflacion, 1:2)
## Model 2: petroleo ~ Lags(petroleo, 1:2)
## Res.Df Df F Pr(>F)
## 1 193
## 2 195 -2 0.8752 0.4184
knitr::kable(
data.frame(Variable = c("petroleo", "inflacion"),
rbind(adf(data1$petroleo), adf(data1$inflacion)),
row.names = NULL),
caption = "Prueba ADF (estacionariedad) - se rechaza raíz unitaria si el estadístico es menor que el crítico"
)| Variable | Estadistico | Critico_5pct |
|---|---|---|
| petroleo | -7.191 | -2.88 |
| inflacion | -8.217 | -2.88 |
knitr::kable(
rbind(resumen(granger_1, "Petróleo", "Inflación"),
resumen(granger_2, "Inflación", "Petróleo")),
caption = "Resumen de las pruebas de Granger (alfa = 5%)"
)| Hipotesis | Res.Df | Df | F | p_valor | Decision |
|---|---|---|---|---|---|
| Petróleo -> Inflación | 195 | -2 | 1.667 | 0.1916 | No rechaza H0 |
| Inflación -> Petróleo | 195 | -2 | 0.875 | 0.4184 | No rechaza H0 |
Dado que las series se construyeron sin ninguna relación entre sí, lo esperado es que no exista evidencia de causalidad de Granger en ninguno de los dos sentidos; es decir, ni el petróleo predice a la inflación ni la inflación predice al petróleo. Si en algún sentido aparece un rechazo, corresponde a un falso positivo propio de trabajar con un nivel de significancia del 5%.
En este primer ejemplo, consideramos dos series temporales económicas: una que representa el de un sector y otra que representa el . Nuestro objetivo es determinar si el gasto en publicidad puede predecir el nivel de ventas o si, por el contrario, el nivel de ventas influye en el gasto en publicidad.
\(H_0\): El gasto en publicidad no causa el nivel de ventas.\ \(H_0\): El nivel de ventas no causa el gasto en publicidad.
\(H_1\): El gasto en publicidad causa el nivel de ventas.\ \(H_1\): El nivel de ventas causa el gasto en publicidad.
library(lmtest)
set.seed(123)
tsData1 <- data.frame(
gasto_publicidad = cumsum(rnorm(200, 0.5, 1.2)), # Gasto en publicidad
ventas = cumsum(rnorm(200, 2.0, 3.5)) # Nivel de ventas
)# Prueba de causalidad de Granger: ¿La "publicidad" causa las "ventas"?
granger_test_pub_ven <- grangertest(ventas ~ gasto_publicidad,
order = 3,
data = tsData1)
print("Prueba de causalidad de Granger (gasto_publicidad -> ventas):")## [1] "Prueba de causalidad de Granger (gasto_publicidad -> ventas):"
## Granger causality test
##
## Model 1: ventas ~ Lags(ventas, 1:3) + Lags(gasto_publicidad, 1:3)
## Model 2: ventas ~ Lags(ventas, 1:3)
## Res.Df Df F Pr(>F)
## 1 190
## 2 193 -3 1.3788 0.2506
Como el valor p (0.2506) de esta prueba es mayor a 0.05, que dice que ``el gasto en publicidad no causa el nivel de ventas’’. Esto indica que, en este conjunto de datos simulado, el gasto en publicidad no contiene información estadísticamente significativa para predecir las ventas.
granger_test_ven_pub <- grangertest(gasto_publicidad ~ ventas,
order = 3,
data = tsData1)
print("Prueba de causalidad de Granger (ventas -> gasto_publicidad):")## [1] "Prueba de causalidad de Granger (ventas -> gasto_publicidad):"
## Granger causality test
##
## Model 1: gasto_publicidad ~ Lags(gasto_publicidad, 1:3) + Lags(ventas, 1:3)
## Model 2: gasto_publicidad ~ Lags(gasto_publicidad, 1:3)
## Res.Df Df F Pr(>F)
## 1 190
## 2 193 -3 1.3717 0.2528
Como el valor p (0.2528) de esta prueba es mayor a 0.05, que dice que ``el nivel de ventas no causa el gasto en publicidad’’.
En este segundo ejemplo, consideramos dos variables macroeconómicas: la fijada por el banco central y el nivel de de las empresas. El objetivo es determinar si los cambios en las tasas de interés anteceden y explican la inversión, o si es la inversión la que presiona las tasas de interés.
\(H_0\): La tasa de interés no causa la inversión privada.\ \(H_0\): La inversión privada no causa la tasa de interés.
set.seed(456)
tsData2 <- data.frame(
tasa_interes = cumsum(rnorm(200, 0.01, 0.05)), # Tasa de Interés
inversion = cumsum(rnorm(200, 0.20, 0.80)) # Inversión Privada
)# Prueba de causalidad de Granger: ¿La "tasa de interés" causa la "inversión"?
granger_test_tasa_inv <- grangertest(inversion ~ tasa_interes,
order = 3,
data = tsData2)
print("Prueba de causalidad de Granger (tasa_interes -> inversion):")## [1] "Prueba de causalidad de Granger (tasa_interes -> inversion):"
## Granger causality test
##
## Model 1: inversion ~ Lags(inversion, 1:3) + Lags(tasa_interes, 1:3)
## Model 2: inversion ~ Lags(inversion, 1:3)
## Res.Df Df F Pr(>F)
## 1 190
## 2 193 -3 0.9921 0.3977
Como el valor p (0.3977) es mayor a 0.05, . Concluimos que, en este conjunto de datos simulado, la tasa de interés no causa (en sentido de Granger) a la inversión privada. Esto indica que los movimientos pasados de la tasa de interés no contienen información estadísticamente significativa para predecir la inversión en este caso particular.
granger_test_inv_tasa <- grangertest(tasa_interes ~ inversion,
order = 3,
data = tsData2)
print("Prueba de causalidad de Granger (inversion -> tasa_interes):")## [1] "Prueba de causalidad de Granger (inversion -> tasa_interes):"
## Granger causality test
##
## Model 1: tasa_interes ~ Lags(tasa_interes, 1:3) + Lags(inversion, 1:3)
## Model 2: tasa_interes ~ Lags(tasa_interes, 1:3)
## Res.Df Df F Pr(>F)
## 1 190
## 2 193 -3 1.161 0.3259
Como el valor p (0.3259) es mayor a 0.05, . Esto sugiere que los movimientos en la inversión privada no contienen información predictiva útil, en sentido de Granger, para anticipar los cambios futuros en las tasas de interés en este modelo.
El análisis econométrico de series temporales permite comprender de manera más precisa las relaciones y dinámicas de las variables económicas a lo largo del tiempo. A través de las pruebas de Dickey-Fuller, Johansen y causalidad de Granger, se identifican las condiciones de estacionariedad, las relaciones de equilibrio de largo plazo y la capacidad predictiva entre variables. En el caso de El Salvador, los resultados de la aplicación de Johansen evidencian una relación de cointegración entre el consumo de los hogares y el PIB durante el período 2000-2024, demostrando que ambas variables mantienen un equilibrio de largo plazo y cuentan con mecanismos de ajuste ante los desequilibrios. Asimismo, los ejemplos de causalidad de Granger muestran la importancia de evaluar la información predictiva sin confundirla con una causalidad económica definitiva. En conjunto, estos métodos constituyen herramientas fundamentales para el estudio econométrico, ya que permiten obtener conclusiones más confiables y fundamentadas para interpretar el comportamiento de la economía.
Autor. (2009, 8 de junio). Granger casualidad o causalidad y cointegración. La Nueva España. https://www.lne.es/economia/2009/06/08/granger-casualidad-causalidad-cointegracion-21519334.html
Granger, C. W. J. (1969). Investigating causal relations by econometric models and cross-spectral methods. Econometrica, 37(3), 424–438. https://doi.org/10.2307/1912791
Gujarati, D. N. y Porter, D. C. (2010). Econometría (5.ª ed.). McGraw-Hill.
Hamilton, J. D. (1994). Time Series Analysis. Princeton University Press.
Lütkepohl, H. (2005). New Introduction to Multiple Time Series Analysis. Springer.
Montero Granados, R. (2013). Variables no estacionarias y cointegración (Documentos de Trabajo en Economía Aplicada). Universidad de Granada. https://www.ugr.es/~montero/matematicas/cointegracion.pdf
Pfaff, B. (2008a). Analysis of Integrated and Cointegrated Time Series with R (2.ª ed.). Springer.
Pfaff, B. (2008b). VAR, SVAR and SVEC models: Implementation within R package vars. Journal of Statistical Software, 27(4), 1–32. https://doi.org/10.18637/jss.v027.i04
R-bloggers. (2021, noviembre). Granger causality test in R (with example). https://www.r-bloggers.com/2021/11/granger-causality-test-in-r-with-example/
Sandoval R., W. (s. f.). Cointegración. RPubs. https://rpubs.com/wilsonsr/828582
Xie, Y., Allaire, J. J. y Grolemund, G. (2018). R Markdown: The Definitive Guide. Chapman & Hall/CRC. https://bookdown.org/yihui/rmarkdown/
Zeileis, A. y Hothorn, T. (2002). Diagnostic checking in regression relationships. R News, 2(3), 7–10. https://cran.r-project.org/doc/Rnews/Rnews_2002-3.pdf