Aplicación 2.2: Regresiones con datos de series temporales
Consumo privado en España
En esta aplicación se estimará una función de consumo de tipo Keynesiano agregada (para un consumidor representativo), usando datos de series temporales para España del período 1964-2022:
\[C_{t} = \beta_1 + \beta_2 Y_{t} + e_{t}\]
donde \(C\) representa el consumo privado (gasto en consumo final de los hogares e instituciones privadas sin fines de lucro al servicio de los hogares -ISFLSH-, en millones de € constantes de 2015), e \(Y\) es la renta (renta disponible bruta de los hogares e ISFLSH, en millones de € constantes de 2015).
Desde el punto de vista técnico, el objetivo principal del ejemplo es la introducción de las principales funciones y librerías especializadas de R y Python para regresiones con series temporales.
Code
# Lectura de librerías
library(tidyverse)
# Lectura de datos
<- read_csv("data/CONS_ESP_ts.csv")
CONS_ESP head(CONS_ESP)
# A tibble: 6 × 3
Date C Y
<date> <dbl> <dbl>
1 1964-12-31 164361. 175820.
2 1965-12-31 174522. 182783.
3 1966-12-31 186740. 195919.
4 1967-12-31 196348. 201365.
5 1968-12-31 207885. 220639.
6 1969-12-31 225025. 236631.
Code
tail(CONS_ESP)
# A tibble: 6 × 3
Date C Y
<date> <dbl> <dbl>
1 2017-12-31 666835. 710941.
2 2018-12-31 678168. 721103.
3 2019-12-31 685567. 749681.
4 2020-12-31 601782. 733411.
5 2021-12-31 644511. 749752.
6 2022-12-31 674961. 732679.
Code
# Asignación del formato de series temporales
# (https://cran.r-project.org/web/views/TimeSeries.html)
#
# Aquí se usará la clase básica "ts", válida para series temporales
# regulares (espaciadas de forma homogénea en el tiempo).
# Pueden usarse otras clases más generales, siendo las más usadas:
# "zoo": https://cran.r-project.org/web/packages/zoo/index.html
# "xts": https://github.com/joshuaulrich/xts
# "tsibble": https://github.com/robjhyndman/fpp3package
# Ver anexo para una demostración sobre el <<tidyverts>>,
# el complemento al tidyverse para el análisis de series temporales.
#
<- ts(CONS_ESP[,2:3], start=c(1964), end = c(2022))
ts_CONS_ESP #
# Estadística descriptiva
summary(ts_CONS_ESP)
C Y
Min. :164361 Min. :175820
1st Qu.:329035 1st Qu.:342111
Median :442941 Median :468111
Mean :454270 Mean :490163
3rd Qu.:618063 3rd Qu.:680903
Max. :693029 Max. :749752
Code
# Gráficas
<- ggplot(data = CONS_ESP, aes(x = Date)) +
g1 geom_line(aes(y = C)) +
labs(y = "Consumo privado en España (millones €)", x = "Año")
g1
Code
<- ggplot(data = CONS_ESP, aes(x = Date)) +
g2 geom_line(aes(y = Y)) +
labs(y = "Renta disponible en España (millones €)", x = "Año")
g2
Code
# Diagrama de puntos con línea de regresión
<- ggplot(CONS_ESP, aes(x = Y, y = C)) +
g3 geom_point() +
stat_smooth(method = lm) +
labs(x = "Renta disponible",y = "Consumo privado")
g3
Code
# Regresión por MCO
<- lm (formula = C ~ Y, data = ts_CONS_ESP)
lin_model summary(lin_model)
Call:
lm(formula = C ~ Y, data = ts_CONS_ESP)
Residuals:
Min 1Q Median 3Q Max
-65322 -6950 1132 8820 24670
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.539e+04 5.376e+03 4.723 1.56e-05 ***
Y 8.750e-01 1.025e-02 85.366 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 14690 on 57 degrees of freedom
Multiple R-squared: 0.9922, Adjusted R-squared: 0.9921
F-statistic: 7287 on 1 and 57 DF, p-value: < 2.2e-16
Code
# ANEXO: La librería fpp3 y el tidyverts' (https://tidyverts.org/)
# La macro-librería `fpp3` contiene varias librerías específicas
# y otras generales, como `tidyverse` y `lubridate`.
# La clase `tsibble` proporciona una infraestructura de datos para ordenar
# y manipular series temporales. Se pueden encontrar los detalles en las
# páginas webs https://tsibble.tidyverts.org/index.html y
# https://robjhyndman.com/publications/tsibble/.
# Toda la información de la librería fpp3 se encuentra en:
# https://github.com/robjhyndman/fpp3package.
# El libro de texto que acompaña a esta librería es el siguiente:
# FORECASTING: PRINCIPLES AND PRACTICE -> https://otexts.com/fpp3/.
#
# NOTA:
# Existen otras librerías especializadas en el análisis de series temporales,
# como `TSstudio` (https://ramikrispin.github.io/TSstudio/),
# `timetk` (https://business-science.github.io/timetk/) o
# `tsbox`(https://docs.ropensci.org/tsbox/).
#
library(fpp3)
Registered S3 method overwritten by 'tsibble':
method from
as_tibble.grouped_df dplyr
── Attaching packages ──────────────────────────────────────────── fpp3 1.0.1 ──
✔ tsibble 1.1.6 ✔ feasts 0.4.1
✔ tsibbledata 0.4.1 ✔ fable 0.4.1
── Conflicts ───────────────────────────────────────────────── fpp3_conflicts ──
✖ lubridate::date() masks base::date()
✖ dplyr::filter() masks stats::filter()
✖ tsibble::intersect() masks base::intersect()
✖ tsibble::interval() masks lubridate::interval()
✖ dplyr::lag() masks stats::lag()
✖ tsibble::setdiff() masks base::setdiff()
✖ tsibble::union() masks base::union()
Code
# Creación del objeto tsibble
<- CONS_ESP[,2:3] %>%
CONS_ESP_ts mutate(Year = 1964:2022) %>%
as_tsibble(index = Year)
# Gráficas individuales
%>% autoplot(C) +
CONS_ESP_ts ggtitle("Consumo privado en España") +
ylab("Millones €") + xlab("Año")
Code
%>% autoplot(Y) +
CONS_ESP_ts ggtitle("Renta disponible en España") +
ylab("Millones €") + xlab("Año")
Code
# Diagrama de puntos junto con la recta de regresión estimada
%>%
CONS_ESP_ts ggplot(aes(x=Y, y=C)) +
ylab("Consumo privado") +
xlab("Renta disponible") +
geom_point() +
geom_smooth(method="lm", se=FALSE)
`geom_smooth()` using formula = 'y ~ x'
Code
# Regresión por MCO
%>%
CONS_ESP_ts model(tslm = TSLM(C ~ Y)) %>%
report()
Series: C
Model: TSLM
Residuals:
Min 1Q Median 3Q Max
-65322 -6950 1132 8820 24670
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.539e+04 5.376e+03 4.723 1.56e-05 ***
Y 8.750e-01 1.025e-02 85.366 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 14690 on 57 degrees of freedom
Multiple R-squared: 0.9922, Adjusted R-squared: 0.9921
F-statistic: 7287 on 1 and 57 DF, p-value: < 2.22e-16
Code
# Lectura de librerías
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.formula.api as smf
# Lectura de datos
# (al introducir la opción index_col se está asignando en este caso
# de forma implícita un formato temporal para el resto de columnas)
= pd.read_csv("data/CONS_ESP_ts.csv", index_col=0)
CONS_ESP # (al introducir la opción index_col se está asignando en este caso
# de forma implícita un formato temporal para el resto de columnas)
#
# Asignación del formato temporal
# (https://pandas.pydata.org/docs/user_guide/timeseries.html)
# Un análisis detallado puede encontrarse en la siguiente página web:
# https://jakevdp.github.io/PythonDataScienceHandbook/
# 03.11-working-with-time-series.html
= pd.read_csv("data/CONS_ESP_ts.csv",
ts_CONS_ESP =['Date'], index_col='Date')
parse_dates ts_CONS_ESP.head()
C Y
Date
1964-12-31 164360.565116 175819.627074
1965-12-31 174521.522473 182783.279618
1966-12-31 186740.485052 195918.543262
1967-12-31 196347.846128 201364.508921
1968-12-31 207884.976097 220638.674259
Code
ts_CONS_ESP.tail()
C Y
Date
2018-12-31 678168.472101 721102.640419
2019-12-31 685567.322159 749681.277625
2020-12-31 601782.445267 733411.116791
2021-12-31 644511.362421 749751.796026
2022-12-31 674960.899465 732678.649099
Code
# Estadística descriptiva
ts_CONS_ESP.describe()
C Y
count 59.000000 59.000000
mean 454270.117905 490163.324114
std 165346.490515 188238.913008
min 164360.565116 175819.627074
25% 329034.893784 342110.756619
50% 442940.762635 468111.433640
75% 618063.297097 680903.206704
max 693029.305659 749751.796026
Code
# Gráficas
"C"])
plt.plot(ts_CONS_ESP["Año")
plt.xlabel("Consumo privado en España (millones €)")
plt.ylabel( plt.show()
Code
"Y"])
plt.plot(ts_CONS_ESP["Año")
plt.xlabel("Renta disponible en España (millones €)")
plt.ylabel( plt.show()
Code
# Diagrama de puntos con línea de regresión
= smf.ols(formula = "C ~ Y", data = ts_CONS_ESP)
reg = reg.fit()
res "Y"], ts_CONS_ESP["C"], color = "black")
plt.scatter(ts_CONS_ESP["Y"], res.fittedvalues, color = "blue")
plt.plot(ts_CONS_ESP["Renta disponible")
plt.xlabel("Consumo privado")
plt.ylabel( plt.show()
Code
# Regresión por MCO
= smf.ols(formula = "C ~ Y", data = ts_CONS_ESP)
model = model.fit()
lin_model print(lin_model.summary())
OLS Regression Results
==============================================================================
Dep. Variable: C R-squared: 0.992
Model: OLS Adj. R-squared: 0.992
Method: Least Squares F-statistic: 7287.
Date: Sun, 09 Feb 2025 Prob (F-statistic): 7.70e-62
Time: 13:04:52 Log-Likelihood: -648.82
No. Observations: 59 AIC: 1302.
Df Residuals: 57 BIC: 1306.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept 2.539e+04 5375.895 4.723 0.000 1.46e+04 3.62e+04
Y 0.8750 0.010 85.366 0.000 0.854 0.895
==============================================================================
Omnibus: 32.296 Durbin-Watson: 0.950
Prob(Omnibus): 0.000 Jarque-Bera (JB): 99.304
Skew: -1.504 Prob(JB): 2.73e-22
Kurtosis: 8.599 Cond. No. 1.47e+06
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.47e+06. This might indicate that there are
strong multicollinearity or other numerical problems.