library(readxl)
library(forecast)
## Warning: package 'forecast' was built under R version 4.3.3
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(tseries)
## Warning: package 'tseries' was built under R version 4.3.3
library(nortest)
library(moments)
df <- read_excel("C:/Users/karsu/OneDrive - dane.gov.co/Desktop/LUIS CARLOS/SERIES DE TIEMPO/Ingreso_promedio_laboral.xlsx")
1. Determinar un Modelo 1 AR(p) o un Modelo MA(q) o un Modelo ARMA(p,q),según corresponda, en sus datos originales. El modelo no debe tener ni constante ni intercepto, ni tendencia. Realizar las pruebas correspondientes.
df.ts<-ts(df$Valor,start = c(2015,1),frequency = 12)
start(df.ts)
## [1] 2015 1
end(df.ts)
## [1] 2024 12
cv_d1<- abs(sd(df.ts[13:120]-df.ts[1:108])/
mean(df.ts[13:120]-df.ts[1:108]))
cv_d1
## [1] 6.272601
cv_c1 <- abs(sd(df.ts[13:120]/df.ts[1:108]) / mean(df.ts[13:120] / df.ts[1:108]))
cv_c1
## [1] 0.2603789
if(cv_d1<cv_c1){"Se elige el esquema aditivo"}else{"Se elige el esquema multiplicativo"}
## [1] "Se elige el esquema multiplicativo"
#Se elige el esquema multiplicativo
gastos.descompuesta1<-decompose(df.ts,type="additive")
plot(gastos.descompuesta1)
#acá se pone 19 como el dato 19, pero puede ser cualquiera
#Descompone el modelo en sus 3 partes
a1<- gastos.descompuesta1$trend[19] #Tendencia
b1<-gastos.descompuesta1$seasonal[19] #Estacionalidad
c1<-gastos.descompuesta1$random[19] #Aleatorio - error
a1+b1+c1 #La sumatoria de la descomposición de la serue da el valor real, si es aditiva
## [1] 1129256
#La grafica compara el valor (observe) con la tendencia, la estacionalidad y el aleatorio.
#En este caso, la estacionalidad nos da en junio, ver el pico.
##3 Método: varianza multiplicativa
gastos.descompuesta2<-decompose(df.ts,type="multiplicative")
plot(gastos.descompuesta2)
a2<- gastos.descompuesta2$trend[19] #Tendencia
b2<-gastos.descompuesta2$seasonal[19] #Estacionalidad
c2<-gastos.descompuesta2$random[19] #Aleatorio - error
a2*b2*c2
## [1] 1129256
cbind(a1+b1+c1,a2*b2*c2)
## [,1] [,2]
## [1,] 1129256 1129256
df.ts[19] #Es llamar el dato 19. Para validar. El dato 19 es el 400.
## [1] 1129256
##Método: varianza
#na.rm es por si hay datos vacios para que no los tome en cuenta
u1<-var(gastos.descompuesta1$random,na.rm=T) #Aditiva
u2<-var(gastos.descompuesta2$random,na.rm=T) #Multiplicativa
cbind(u1,u2)
## u1 u2
## [1,] 7706149110 0.008006869
if(u1<u2){"Se elige el esquema aditivo"}else{"Se elige el esquema multiplicativo"}
## [1] "Se elige el esquema multiplicativo"
#Se elige la serie de menor varianza, es decir u2 entonces la serie es multiplicativa
Gráficos de autocorrelación y autocorrelación parcial
par(mfrow=c(2,1))
acf(ts(df.ts,frequency=1)) #función de autocorrelación (ACF) #MA: medias moviles
pacf(ts(df.ts,frequency=1)) #función de autocorrelación parcial (PACF) #AR: autoregresivo
par(mfrow=c(1,1))
# - ACF: Decaimiento lento, sugiere un proceso AR.
# - PACF: Pico significativo en lag 1 y luego cae, sugiere AR(1).
# Por lo tanto, ajustamos un modelo AR(1).
#H0: No es estacionaria------ es decir hay caminata aleatoria
#H1: Es estacionaria
library(tseries)
adf.test(df.ts,k=0)
##
## Augmented Dickey-Fuller Test
##
## data: df.ts
## Dickey-Fuller = -2.8135, Lag order = 0, p-value = 0.2387
## alternative hypothesis: stationary
# Como p valor=0.2387 mayor 0.05 acepto H0 La serie no es estacionaria es decir
# hay caminata aleatoria
#se debe estacionar la serie
library(forecast)
ndiffs(df.ts) #con una diferencia
## [1] 1
#conseguir la estacionariedad
seriedif<-diff(df.ts,differences = 1)
seriedif
## Jan Feb Mar Apr May
## 2015 41826.5827 -108031.2862 52803.5669 13101.3707
## 2016 56762.3345 -30687.9131 -46240.1418 41458.7209 9692.5287
## 2017 -216096.4885 -7154.0529 -7840.2469 12028.1769 21072.1678
## 2018 16626.9373 -9665.2574 -2703.5775 33201.1016 83539.7862
## 2019 395365.1579 -72530.6700 -34135.7544 97501.2708 -32343.9965
## 2020 -280554.7171 15908.9201 -455637.0144 7479.6470 3956.6223
## 2021 153423.7287 13587.9165 -26067.3759 32093.0631 22818.8382
## 2022 42266.0608 9106.2589 28808.8485 7834.7343 43728.7559
## 2023 30358.9837 38050.2892 -1786.1654 23456.7500 -22835.4233
## 2024 69088.7737 -8735.4599 41045.9718 7497.2660 34786.5108
## Jun Jul Aug Sep Oct
## 2015 -64051.3708 63371.0631 -13328.9572 -35428.2412 213552.1399
## 2016 -74008.2808 19299.0258 168548.2150 -153463.6743 -691.4565
## 2017 -38487.0791 22454.1116 26997.6303 1753.0715 -36936.3024
## 2018 -61502.8072 7317.3504 -6109.8973 -12989.7914 7814.5534
## 2019 -79512.6922 120183.7072 -53242.2063 -19951.2804 59619.9422
## 2020 -732.1192 -58099.4674 447894.5474 -358.2218 890.9646
## 2021 -19865.8338 13525.2626 -41625.1148 1911.1180 -4421.7986
## 2022 -29294.7337 32422.5905 -8495.3169 -9314.5556 15927.2134
## 2023 36722.2690 13666.1693 -6575.0945 30361.4057 -4395.9864
## 2024 -4557.6016 -41762.6241 29506.3653 13601.7626 -2681.5917
## Nov Dec
## 2015 -62527.1348 -45887.3093
## 2016 56469.7512 1370.2662
## 2017 43688.6392 -45622.7094
## 2018 12434.7418 -15755.3723
## 2019 -97415.8791 6979.9200
## 2020 22659.4723 -36392.3996
## 2021 10754.7153 -27060.2966
## 2022 19009.0791 -8647.3690
## 2023 23608.7821 -39063.1057
## 2024 20633.7029 -6228.5523
plot(seriedif)
summary(seriedif)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -455637 -24451 3957 3661 27903 447895
class(seriedif)
## [1] "ts"
#Verificar estacionariedad de los datos
#H0: No es estacionaria------ es decir hay caminata aleatoria
#H1: Es estacionaria
library(tseries)
adf.test(seriedif,k=0)
## Warning in adf.test(seriedif, k = 0): p-value smaller than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: seriedif
## Dickey-Fuller = -13.086, Lag order = 0, p-value = 0.01
## alternative hypothesis: stationary
# Como p valor=0.01 menor 0.05, Rechazo H0 La serie es estacionaria es decir, no hay caminata aleatoria.
#Gráficos
par(mfrow=c(2,1))
acf(ts(seriedif,frequency=1)) #MA
pacf(ts(seriedif,frequency=1)) #AR
par(mfrow=c(1,1))
# Modelos
#ARMA(1,1) o #ARMA(1,0)
# Modelo ARMA(1,1) sin constante ni tendencia
modelo1_arma11 <- Arima(seriedif, order = c(1, 0, 1))
summary(modelo1_arma11)
## Series: seriedif
## ARIMA(1,0,1) with non-zero mean
##
## Coefficients:
## ar1 ma1 mean
## -0.2804 0.0914 3615.011
## s.e. 0.3015 0.3049 6934.617
##
## sigma^2 = 8.062e+09: log likelihood = -1524.58
## AIC=3057.15 AICc=3057.5 BIC=3068.27
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 66.07616 88650.7 47333.09 -70.61029 370.4672 0.6237739 0.002519279
# Modelo ARMA(1,0) sin constante ni tendencia
modelo1_arma10 <- Arima(seriedif, order = c(1, 0, 0))
summary(modelo1_arma10)
## Series: seriedif
## ARIMA(1,0,0) with non-zero mean
##
## Coefficients:
## ar1 mean
## -0.1912 3623.073
## s.e. 0.0896 6833.867
##
## sigma^2 = 8e+09: log likelihood = -1524.62
## AIC=3055.25 AICc=3055.45 BIC=3063.58
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 55.47252 88686.4 46993.07 -68.53483 357.4362 0.6192931 0.007459966
# Comparar AIC para elegir el mejor modelo
cat("\nComparación de AIC para los modelos de la Pregunta 1:\n")
##
## Comparación de AIC para los modelos de la Pregunta 1:
tabla_aic_modelo1 <- data.frame(
Modelo = c("ARMA(1,1)", "ARMA(1,0)"),
AIC = c(modelo1_arma11$aic, modelo1_arma10$aic)
)
print(tabla_aic_modelo1)
## Modelo AIC
## 1 ARMA(1,1) 3057.151
## 2 ARMA(1,0) 3055.246
mejor_modelo1=modelo1_arma10
aic_modelo1=mejor_modelo1$aic
# Pruebas para el mejor modelo
cat("\nPrueba de Ljung-Box para el mejor Modelo 1:\n")
##
## Prueba de Ljung-Box para el mejor Modelo 1:
print(Box.test(mejor_modelo1$residuals, lag = 10, type = "Ljung-Box"))
##
## Box-Ljung test
##
## data: mejor_modelo1$residuals
## X-squared = 17.547, df = 10, p-value = 0.06311
# Como P-valor=0.06311 es mayor 0.05, Acepto Ho, es decir los residuos del modelo se comportan como ruido blanco.
2. Determinar un Modelo 2 ARIMA(p,d,q), según corresponda en sus datos en diferencias. El modelo no debe tener ni constante ni intercepto, ni tendencia. Realizar las pruebas correspondientes
# Modelos
#ARIMA(1,1,1), ARIMA(1,1,0) o ARIMA(0,1,1)
# --- ARIMA(p,d,q) en los datos diferenciados ---
# Probar varios modelos ARIMA
modelo2_arima110 <- Arima(df.ts, order = c(1, 1, 0))
modelo2_arima011 <- Arima(df.ts, order = c(0, 1, 1))
modelo2_arima111 <- Arima(df.ts, order = c(1, 1, 1))
# Comparar AIC
tabla_aic_modelo2 <- data.frame(
Modelo = c("ARIMA(1,1,0)", "ARIMA(0,1,1)", "ARIMA(1,1,1)"),
AIC = c(modelo2_arima110$aic, modelo2_arima011$aic, modelo2_arima111$aic)
)
cat("\nComparación de AIC para los modelos de la Pregunta 2:\n")
##
## Comparación de AIC para los modelos de la Pregunta 2:
print(tabla_aic_modelo2)
## Modelo AIC
## 1 ARIMA(1,1,0) 3053.526
## 2 ARIMA(0,1,1) 3054.203
## 3 ARIMA(1,1,1) 3055.422
# Seleccionar el mejor modelo
modelos2 <- list(modelo2_arima110, modelo2_arima011, modelo2_arima111)
mejor_modelo2 <- modelos2[[which.min(c(modelo2_arima110$aic, modelo2_arima011$aic, modelo2_arima111$aic))]]
mejor_modelo2_nombre <- tabla_aic_modelo2$Modelo[which.min(tabla_aic_modelo2$AIC)]
cat("\nEl mejor modelo para la Pregunta 2 es:", mejor_modelo2_nombre, "\n")
##
## El mejor modelo para la Pregunta 2 es: ARIMA(1,1,0)
# Pruebas para el mejor modelo
cat("\nPrueba de Ljung-Box para el mejor Modelo 2:\n")
##
## Prueba de Ljung-Box para el mejor Modelo 2:
print(Box.test(mejor_modelo2$residuals, lag = 10, type = "Ljung-Box"))
##
## Box-Ljung test
##
## data: mejor_modelo2$residuals
## X-squared = 17.656, df = 10, p-value = 0.06105
# Como P-valor=0.06105 es mayor 0.05, Acepto Ho, es decir los residuos del modelo se comportan como ruido blanco.
cat("\nPrueba ADF para Modelo 2 (datos diferenciados):\n")
##
## Prueba ADF para Modelo 2 (datos diferenciados):
print(adf.test(seriedif, k = 0))
## Warning in adf.test(seriedif, k = 0): p-value smaller than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: seriedif
## Dickey-Fuller = -13.086, Lag order = 0, p-value = 0.01
## alternative hypothesis: stationary
# Visualización de los residuales
tsdisplay(mejor_modelo2$residuals, main = paste("Análisis de los residuales del Modelo 2 -", mejor_modelo2_nombre))
aic_modelo2 <- mejor_modelo2$aic
aic_modelo2
## [1] 3053.526
3. Determinar un Modelo 3 SARIMA(p,d,q)x(P,D,Q)s, según corresponda en sus datos en diferencias. El modelo no debe tener ni constante ni intercepto, ni tendencia. Realizar las pruebas correspondientes.
#descomponemos la serie
plot(decompose(df.ts,type="multiplicative"))
#diferencia parte estacional
nsdiffs(df.ts)
## [1] 0
di1<-diff(df.ts,lag = 12)
di1
## Jan Feb Mar Apr May Jun
## 2016 112162.758 39648.263 101439.407 90094.561 86685.719 76728.809
## 2017 -224349.447 -200815.587 -162415.692 -191846.236 -180466.597 -144945.395
## 2018 8580.344 6069.139 11205.809 32378.734 94846.352 71830.624
## 2019 430945.988 368080.576 336648.399 400948.568 285064.785 267054.900
## 2020 -385402.356 -296962.766 -718464.026 -808485.649 -772185.031 -693404.458
## 2021 100994.680 98673.677 528243.315 552856.731 571718.947 552585.232
## 2022 17916.555 13434.897 68311.122 44052.793 64962.710 55533.811
## 2023 131444.489 160388.519 129793.505 145415.521 78851.342 144868.345
## 2024 160298.664 113512.915 156345.052 140385.568 198007.502 156727.631
## Jul Aug Sep Oct Nov Dec
## 2016 32656.771 214533.944 96498.511 -117745.086 1251.800 48509.376
## 2017 -141790.309 -283340.894 -128124.148 -164368.994 -177150.106 -224143.082
## 2018 56693.863 23586.335 8843.472 53594.328 22340.431 52207.768
## 2019 379921.257 332788.948 325827.459 377632.848 267782.227 290517.519
## 2020 -871687.632 -370550.878 -350957.820 -409686.797 -289611.446 -332983.766
## 2021 624209.962 134690.300 136959.640 131646.877 119742.120 129074.223
## 2022 74431.138 107560.936 96335.263 116684.275 124938.638 143351.566
## 2023 126111.923 128032.146 167708.107 147384.907 151984.610 121568.874
## 2024 101298.838 137380.298 120620.654 122335.049 119359.970 152194.523
nsdiffs(di1)
## [1] 0
par(mfrow=c(2,1))
acf(ts(di1,frequency=1)) #MA
pacf(ts(di1,frequency=1)) #AR
par(mfrow=c(1,1))
#Se proponen los siguientes modelos
modelo3_sarima110_100 <- Arima(df.ts, order = c(1, 1, 0), seasonal = list(order = c(1, 0, 0), period = 12), include.mean = FALSE)
modelo3_sarima110_000 <- Arima(df.ts, order = c(1, 1, 0), seasonal = list(order = c(0, 0, 0), period = 12), include.mean = FALSE)
# Comparar AIC
tabla_aic_modelo3 <- data.frame(
Modelo = c("SARIMA(1,1,0)(1,0,0)[12]", "SARIMA(1,1,0)(0,0,0)[12]"),
AIC = c(modelo3_sarima110_100$aic, modelo3_sarima110_000$aic)
)
cat("\nComparación de AIC para los modelos de la Pregunta 3:\n")
##
## Comparación de AIC para los modelos de la Pregunta 3:
print(tabla_aic_modelo3)
## Modelo AIC
## 1 SARIMA(1,1,0)(1,0,0)[12] 3052.953
## 2 SARIMA(1,1,0)(0,0,0)[12] 3053.526
# Seleccionar el mejor modelo
modelos3 <- list(modelo3_sarima110_100, modelo3_sarima110_000)
mejor_modelo3 <- modelos3[[which.min(c(modelo3_sarima110_100$aic, modelo3_sarima110_000$aic))]]
mejor_modelo3_nombre <- tabla_aic_modelo3$Modelo[which.min(tabla_aic_modelo3$AIC)]
cat("\nEl mejor modelo para la Pregunta 3 es:", mejor_modelo3_nombre, "\n")
##
## El mejor modelo para la Pregunta 3 es: SARIMA(1,1,0)(1,0,0)[12]
# Pruebas para el mejor modelo
cat("\nPrueba de Ljung-Box para Modelo 3:\n")
##
## Prueba de Ljung-Box para Modelo 3:
print(Box.test(mejor_modelo3$residuals, lag = 10, type = "Ljung-Box"))
##
## Box-Ljung test
##
## data: mejor_modelo3$residuals
## X-squared = 21.118, df = 10, p-value = 0.02029
# Como P-valor=0.02029 es menor 0.05, Rechazo Ho, es decir los residuos del modelo no se comportan como ruido blanco.
cat("\nPrueba ADF para Modelo 3 (datos diferenciados):\n")
##
## Prueba ADF para Modelo 3 (datos diferenciados):
print(adf.test(seriedif, k = 0))
## Warning in adf.test(seriedif, k = 0): p-value smaller than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: seriedif
## Dickey-Fuller = -13.086, Lag order = 0, p-value = 0.01
## alternative hypothesis: stationary
# Visualización de los residuales
tsdisplay(mejor_modelo3$residuals, main = paste("Analisis de los residuales del Modelo 3 -", mejor_modelo3_nombre))
# Guardar AIC para comparación posterior
aic_modelo3 <- mejor_modelo3$aic
aic_modelo3
## [1] 3052.953
como los residuales del mejor modelo no son ruido blanco, se proponen los siguientes modelos
# Modelos propuestos
modelo3_sarima110_000 <- Arima(df.ts, order=c(1,1,0), seasonal=list(order=c(0,0,0), period=12), include.mean=FALSE)
modelo3_sarima110_100 <- mejor_modelo3 # SARIMA(1,1,0)(1,0,0)[12]
modelo3_sarima110_101 <- Arima(df.ts, order=c(1,1,0), seasonal=list(order=c(1,0,1), period=12), include.mean=FALSE)
modelo3_sarima111_101 <- Arima(df.ts, order=c(1,1,1), seasonal=list(order=c(1,0,1), period=12), include.mean=FALSE)
modelo3_sarima111_100 <- Arima(df.ts, order=c(1,1,1), seasonal=list(order=c(1,0,0), period=12), include.mean=FALSE)
modelo3_sarima210_100 <- Arima(df.ts, order=c(2,1,0), seasonal=list(order=c(1,0,0), period=12), include.mean=FALSE)
modelo3_sarima111_102 <- Arima(df.ts, order=c(1,1,1), seasonal=list(order=c(1,0,2), period=12), include.mean=FALSE)
modelo3_sarima211_101 <- Arima(df.ts, order=c(2,1,1), seasonal=list(order=c(1,0,1), period=12), include.mean=FALSE)
# Tabla comparativa (usando los datos proporcionados)
tabla_comparativa <- data.frame(
Modelo = c("SARIMA(1,1,0)(1,0,0)[12]", "SARIMA(1,1,0)(1,0,1)[12]",
"SARIMA(1,1,1)(1,0,1)[12]", "SARIMA(1,1,1)(1,0,0)[12]",
"SARIMA(2,1,0)(1,0,0)[12]", "SARIMA(1,1,1)(1,0,2)[12]",
"SARIMA(2,1,1)(1,0,1)[12]", "SARIMA(1,1,0)(0,0,0)[12]"),
AIC = c(3052.788, 3054.787, 3056.787, 3054.950, 3054.945, 3055.501, 3058.298, 3053.526),
LjungBox_p = c(0.01872763, 0.01863907, 0.01864935, 0.02018155, 0.01996502, 0.06443904, 0.02006230, 0.06104534)
)
# Imprimir la tabla comparativa
cat("\nTabla comparativa de modelos:\n")
##
## Tabla comparativa de modelos:
print(tabla_comparativa)
## Modelo AIC LjungBox_p
## 1 SARIMA(1,1,0)(1,0,0)[12] 3052.788 0.01872763
## 2 SARIMA(1,1,0)(1,0,1)[12] 3054.787 0.01863907
## 3 SARIMA(1,1,1)(1,0,1)[12] 3056.787 0.01864935
## 4 SARIMA(1,1,1)(1,0,0)[12] 3054.950 0.02018155
## 5 SARIMA(2,1,0)(1,0,0)[12] 3054.945 0.01996502
## 6 SARIMA(1,1,1)(1,0,2)[12] 3055.501 0.06443904
## 7 SARIMA(2,1,1)(1,0,1)[12] 3058.298 0.02006230
## 8 SARIMA(1,1,0)(0,0,0)[12] 3053.526 0.06104534
# Seleccionar modelos que pasen la prueba de Ljung-Box (p > 0.05)
modelos_validos <- tabla_comparativa[tabla_comparativa$LjungBox_p > 0.05, ]
# Verificar si hay modelos válidos
if (nrow(modelos_validos) == 0) {
cat("\nNo hay modelos que pasen la prueba de Ljung-Box (p > 0.05).\n")
} else {
# Seleccionar el modelo con el menor AIC entre los válidos
indice_mejor <- which.min(modelos_validos$AIC)
mejor_modelo_nombre_nuevo <- modelos_validos$Modelo[indice_mejor]
# Imprimir el mejor modelo
cat("\nMejor modelo final (menor AIC con Ljung-Box p > 0.05):", mejor_modelo_nombre_nuevo, "\n")
}
##
## Mejor modelo final (menor AIC con Ljung-Box p > 0.05): SARIMA(1,1,0)(0,0,0)[12]
mejor_modelo3 <- modelo3_sarima110_000
aic_modelo3 <- mejor_modelo3$aic
4. Determinar un Modelo 4 con la función auto.arima(). Realizar las pruebas correspondientes.
# Ajustar modelo con auto.arima
modelo4 <- auto.arima(df.ts,seasonal = TRUE)
summary(modelo4)
## Series: df.ts
## ARIMA(2,1,2)
##
## Coefficients:
## ar1 ar2 ma1 ma2
## 0.5437 -0.5820 -0.7632 0.8866
## s.e. 0.1034 0.1993 0.0546 0.1376
##
## sigma^2 = 7.247e+09: log likelihood = -1518.22
## AIC=3046.45 AICc=3046.98 BIC=3060.34
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 3358.72 83334.51 47013.55 -0.08229661 4.554846 0.2311256
## ACF1
## Training set -0.01396495
# Pruebas para el modelo
cat("\nPrueba de Ljung-Box para Modelo 4:\n")
##
## Prueba de Ljung-Box para Modelo 4:
print(Box.test(modelo4$residuals, lag = 10, type = "Ljung-Box"))
##
## Box-Ljung test
##
## data: modelo4$residuals
## X-squared = 8.9556, df = 10, p-value = 0.5363
# Como P-valor=0.5363 es mayor 0.05, Acepto Ho, es decir los residuos
#del modelo se comportan como ruido blanco.
# Visualización de los residuales
tsdisplay(modelo4$residuals, main = "Análisis de los residuales del Modelo 4")
#No hay patrones evidentes, lo cual es bueno.
#La mayoría de las barras están dentro de las bandas de confianza
#Las barras también caen dentro de las bandas,residuos no correlacionados.
# Guardar AIC
aic_modelo4 <- modelo4$aic
Gráficos ACF/PACF de la serie diferenciada para evaluar el modelo
par(mfrow = c(2, 1))
acf(ts(seriedif, frequency = 1), main = "ACF de la serie diferenciada", lag.max = 20)
pacf(ts(seriedif, frequency = 1), main = "PACF de la serie diferenciada", lag.max = 20)
par(mfrow = c(1, 1))
# Interpretación para refutar o confirmar ARIMA(2,1,2):
cat("\nEvaluación del modelo ARIMA(2,1,2) basado en ACF/PACF de seriedif:\n")
##
## Evaluación del modelo ARIMA(2,1,2) basado en ACF/PACF de seriedif:
cat(" ACF: Muestra un pico significativo solo en lag 0 y los demás lags están dentro de las bandas, sugiere q=0 o q=1, y no q=2.\n")
## ACF: Muestra un pico significativo solo en lag 0 y los demás lags están dentro de las bandas, sugiere q=0 o q=1, y no q=2.
cat("PACF: Muestra un pico significativo solo en lag 1 y los demás lags están dentro de las bandas, sugiere p=1, y no p=2.\n")
## PACF: Muestra un pico significativo solo en lag 1 y los demás lags están dentro de las bandas, sugiere p=1, y no p=2.
cat("Conclusión: ACF muestra picos en lag 0 o lag 1 y PACF muestra picos solo en lag 1 , ARIMA(2,1,2) está sobreajustado. Un modelo como ARIMA(1,1,0) o ARIMA(1,1,1) es más adecuado.\n")
## Conclusión: ACF muestra picos en lag 0 o lag 1 y PACF muestra picos solo en lag 1 , ARIMA(2,1,2) está sobreajustado. Un modelo como ARIMA(1,1,0) o ARIMA(1,1,1) es más adecuado.
5. Determinar el mejor modelo empleando el Criterio AIC. Elaborar una tabla comparativa.
# Crear la tabla con los nombres como texto
tabla_aic <- data.frame(
Modelo = c("Mejor modelo 1", "Mejor modelo 2", "Mejor modelo 3"),
AIC = c(aic_modelo1, aic_modelo2, aic_modelo3)
)
# Imprimir la tabla
cat("\nTabla comparativa de AIC:\n")
##
## Tabla comparativa de AIC:
print(tabla_aic)
## Modelo AIC
## 1 Mejor modelo 1 3055.246
## 2 Mejor modelo 2 3053.526
## 3 Mejor modelo 3 3053.526
# El mejor modelo segun AIC es el modelo SARIMA(1,1,0)(0,0,0)[12]
6. Realizarle a los residuales del mejor modelo el Análisis de Normalidad (8 pruebas). Elaborar una tabla comparativa.
residuales_mejor <- modelo3_sarima110_000$residuals
# --- Análisis Gráfico ---
# Histograma con curva normal
par(mfrow = c(1, 1))
hist(residuales_mejor, prob = TRUE, main = "Histograma con curva normal",
ylab = "Frecuencia Relativa", xlab = "Residuales")
x <- seq(min(residuales_mejor), max(residuales_mejor), length = 40)
f <- dnorm(x, mean = mean(residuales_mejor), sd = sd(residuales_mejor))
lines(x, f, col = "red", lwd = 2)
# Gráfico Q-Q Normal
qqnorm(residuales_mejor, main = "Gráfico Q-Q de los Residuales")
qqline(residuales_mejor, col = "red")
# Boxplots para df.ts y seriedif
par(mfrow = c(2, 1))
# Serie original
cat("\nDatos atípicos en la serie original (df.ts):\n")
##
## Datos atípicos en la serie original (df.ts):
a <- boxplot.stats(df.ts)
cat("Valores atípicos:", a$out, "\n")
## Valores atípicos: 552393.6
cat("Mínimo atípico:", min(a$out, na.rm = TRUE), "\n")
## Mínimo atípico: 552393.6
boxplot(df.ts, horizontal = TRUE, main = "Boxplot de la serie original")
# Serie diferenciada
cat("\nDatos atípicos en la serie diferenciada (seriedif):\n")
##
## Datos atípicos en la serie diferenciada (seriedif):
b <- boxplot.stats(seriedif)
cat("Valores atípicos:", b$out, "\n")
## Valores atípicos: -108031.3 213552.1 168548.2 -153463.7 -216096.5 395365.2 120183.7 -280554.7 -455637 447894.5 153423.7
cat("Mínimo atípico:", min(b$out, na.rm = TRUE), "\n")
## Mínimo atípico: -455637
boxplot(seriedif, horizontal = TRUE, main = "Boxplot de la serie diferenciada")
par(mfrow = c(1, 1))
# --- Métodos Analíticos ---
# Coeficiente de asimetría
asim <- skewness(residuales_mejor)
cat("\nCoeficiente de asimetría de los residuales:", asim, "\n")
##
## Coeficiente de asimetría de los residuales: 0.2734168
# Coeficiente de curtosis
curt <- kurtosis(residuales_mejor)
cat("\nCoeficiente de curtosis de los residuales:", curt, "\n")
##
## Coeficiente de curtosis de los residuales: 15.61578
# Test de Shapiro-Wilk
shapiro <- shapiro.test(residuales_mejor)
cat("\nTest de Shapiro-Wilk para los residuales:\n")
##
## Test de Shapiro-Wilk para los residuales:
print(shapiro)
##
## Shapiro-Wilk normality test
##
## data: residuales_mejor
## W = 0.7249, p-value = 1.069e-13
# Test de Lilliefors
lillie <- lillie.test(residuales_mejor)
cat("\nTest de Lilliefors para los residuales:\n")
##
## Test de Lilliefors para los residuales:
print(lillie)
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: residuales_mejor
## D = 0.20574, p-value = 1.325e-13
# Test de Jarque-Bera
jb <- jarque.bera.test(residuales_mejor)
cat("\nTest de Jarque-Bera para los residuales:\n")
##
## Test de Jarque-Bera para los residuales:
print(jb)
##
## Jarque Bera Test
##
## data: residuales_mejor
## X-squared = 797.29, df = 2, p-value < 2.2e-16
# Tabla comparativa
tabla_normalidad <- data.frame(
Prueba = c("Asimetría", "Curtosis", "Shapiro-Wilk", "Lilliefors", "Jarque-Bera"),
Valor_o_p_valor = c(asim, curt, shapiro$p.value, lillie$p.value, jb$p.value),
Normalidad = c(
abs(asim) < 0.5, # Asimetría cercana a 0
abs(curt - 3) < 0.5, # Curtosis cercana a 3
shapiro$p.value > 0.05,
lillie$p.value > 0.05,
jb$p.value > 0.05
)
)
cat("\nTabla comparativa de normalidad de los residuales:\n")
##
## Tabla comparativa de normalidad de los residuales:
print(tabla_normalidad)
## Prueba Valor_o_p_valor Normalidad
## 1 Asimetría 2.734168e-01 TRUE
## 2 Curtosis 1.561578e+01 FALSE
## 3 Shapiro-Wilk 1.069418e-13 FALSE
## 4 Lilliefors 1.324875e-13 FALSE
## 5 Jarque-Bera 0.000000e+00 FALSE
#La asimetría está cerca de 0, lo que es un buen indicio, el histograma y el Q-Q plot parecen sugerir una distribución normal. Aunque En realidad, la curtosis elevada (ese "pico" pronunciado) y los p-valores tan bajos en las pruebas estadísticas nos demuestran que los residuales no siguen una distribución normal.
# Por lo tanto los residuales de nuestro modelo SARIMA no son normales. Por lo que tenemos que tener cautela en nuestras predicciones.
7. Empleando el mejor modelo pronosticar todo 2025 y comparar con los datos reales. Elaborar una tabla comparativa.
# Predicciones para 2025 y Comparación con Datos Reales
# Generar pronósticos para 2025 (12 meses)
pronostico <- forecast(modelo3_sarima110_000, h = 12)
predicciones <- as.numeric(pronostico$mean)
intervalos <- data.frame(Lower = pronostico$lower[, 2], Upper = pronostico$upper[, 2])
# Datos reales proporcionados para 2025 (solo enero-marzo)
datos_reales_2025 <- c(1559422.723, 1560994.667, 1578788.635, rep(NA, 9))
# Calcular errores para los meses con datos reales
errores <- predicciones - datos_reales_2025
errores_abs <- abs(errores)
porcentaje_error <- (errores_abs / datos_reales_2025) * 100
# Crear tabla de predicciones y comparación
tabla_prediccion <- data.frame(
Mes = month.abb[1:12],
Prediccion = round(predicciones, 2),
Real = round(datos_reales_2025, 2),
Error = round(errores, 2),
Porcentaje_Error = round(porcentaje_error, 2),
Lower_95CI = round(intervalos$Lower, 2),
Upper_95CI = round(intervalos$Upper, 2)
)
cat("\nTabla de predicciones y comparación para 2025 (SARIMA(1,1,0)(0,0,0)[12]):\n")
##
## Tabla de predicciones y comparación para 2025 (SARIMA(1,1,0)(0,0,0)[12]):
print(tabla_prediccion)
## Mes Prediccion Real Error Porcentaje_Error Lower_95CI Upper_95CI
## 1 Jan 1534457 1559423 -24965.48 1.60 1359694 1709221
## 2 Feb 1534234 1560995 -26761.02 1.71 1309273 1759194
## 3 Mar 1534276 1578789 -44512.62 2.82 1265038 1803514
## 4 Apr 1534268 NA NA NA 1227640 1840896
## 5 May 1534270 NA NA NA 1194243 1874296
## 6 Jun 1534269 NA NA NA 1163860 1904679
## 7 Jul 1534269 NA NA NA 1135784 1932755
## 8 Aug 1534269 NA NA NA 1109560 1958978
## 9 Sep 1534269 NA NA NA 1084864 1983674
## 10 Oct 1534269 NA NA NA 1061457 2007082
## 11 Nov 1534269 NA NA NA 1039154 2029384
## 12 Dec 1534269 NA NA NA 1017814 2050724
# Resumen de errores para enero-marzo
cat("\nResumen de errores (enero-marzo 2025):\n")
##
## Resumen de errores (enero-marzo 2025):
cat("Error Absoluto Medio (MAE):", mean(abs(errores[1:3]), na.rm = TRUE), "\n")
## Error Absoluto Medio (MAE): 32079.71
cat("Error Porcentual Absoluto Medio (MAPE):", mean(porcentaje_error[1:3], na.rm = TRUE), "%\n")
## Error Porcentual Absoluto Medio (MAPE): 2.044906 %
# Nota sobre la no normalidad
cat("\nNota: Los residuales del modelo no son normales (curtosis = 15.61, Shapiro-Wilk p-valor = 1.069e-13), probablemente debido a valores atípicos (ej, -455637, 447894.5 en el año 2020). Esto puede subestimar o sobreestimar los intervalos de confianza, por lo que las predicciones deben interpretarse con cautela.\n")
##
## Nota: Los residuales del modelo no son normales (curtosis = 15.61, Shapiro-Wilk p-valor = 1.069e-13), probablemente debido a valores atípicos (ej, -455637, 447894.5 en el año 2020). Esto puede subestimar o sobreestimar los intervalos de confianza, por lo que las predicciones deben interpretarse con cautela.
# Gráfico de las predicciones
plot(pronostico, main = "Predicciones de Ingreso Promedio Laboral para 2025",
xlab = "Año", ylab = "Ingreso Promedio Laboral")
points(2025 + (1:3)/12, datos_reales_2025[1:3], col = "red", pch = 16)
legend("topleft", legend = c("Predicciones", "Datos Reales"), col = c("blue", "red"), lty = c(1, NA), pch = c(NA, 16))
8. Presentar cinco (5) conclusiones
Conclusiones
Al comienzo, la serie no era estacionaria, como lo indica el p-valor de 0.2387 en la prueba ADF. Sin embargo, después de aplicar una diferenciación, el p-valor bajó a 0.01, lo que confirma que la serie se volvió estacionaria. Esto justifica el uso de un modelo ARIMA o SARIMA con una diferencia (d=1) para poder representar adecuadamente el comportamiento de los datos.
Después de evaluar varios modelos, el SARIMA(1,1,0)(0,0,0)[12] resultó ser el más adecuado. Su valor AIC fue de 3053.526, y la prueba de Ljung-Box arrojó un p-valor de 0.06105, lo que sugiere que los residuos se comportan como ruido blanco. En otras palabras, este modelo que en la práctica equivale a un ARIMA(1,1,0) logra capturar bien la dinámica de la serie, sin necesidad de incluir componentes estacionales.
Aunque el modelo ARIMA(2,1,2), sugerido por la función auto.arima, mostró residuos que se comportan como ruido blanco (p-valor de 0.5363 en la prueba de Ljung-Box) y un AIC ligeramente más bajo (3046.45), el análisis de las funciones ACF y PACF indica que podría estar sobreajustado. Por eso, un modelo más sencillo como el ARIMA(1,1,0) resulta una opción más adecuada para esta serie de tiempo.
Las pruebas de normalidad como Shapiro-Wilk, Lilliefors y Jarque-Bera, indicaron que los residuos del modelo SARIMA no siguen una distribución normal. Esto puede deberse a que la curtosis es muy alta (15.61) y a la presencia de varios valores atípicos.
Las predicciones para los meses de enero a marzo de 2025 arrojaron un MAE de 32079,71 y un MAPE de 2.04%, lo que sugiere que el modelo tuvo un buen nivel de precisión en ese periodo de tiempo.