Los métodos de suavizado son una familia de métodos de pronóstico que promedian los valores durante múltiplos períodos para reducir el ruido y descubrir patrones en los datos.
Los promedios móviles son un enfoque de suavizado que promedian los valores de la serie en una ventana de períodos de tiempo consecutivos, generando una serie de promedios. Los enfoques difieren principalmente en función al número de valores promediados. Entre las principales técnicas tenemos:
Para este método, elegimos un número de puntos cercanos y promediamos para estimar la tendencia. Al calcular una media móvil simple, es beneficioso utilizar un número impar de puntos para que el cálculo sea simétrico. Por ejemplo, para calcular un promedio móvil con un horizante de 5, la fórmula sería:
\[ \hat{y}_t=\dfrac{y_{t-2}+y_{t-1}+y_t+y_{t+1}+y_{t+2}}{5} \]
donde \(t\) es el tiempo en el instante en el que se está suavizando y 5 el número de puntos que se utilizan para calcular el promedio.
library(tidyverse) #Manipulación y visualización de datos
library(lubridate) #Manejo de fechas
library(vars) #Métodos de suavizamiento
library(forecast) #Modelos predictivos
library(ggExtra) #Manipulación de gráficas
library(knitr) #Visualización de tablas
#Carga de la serie de datos
load("serie_1.RData")
#Arreglo de fechas para posterior gráfica
r1_t <- r1_t %>% mutate(id_date=as.Date(paste0(id_date,"-01")))
#Visualización de los 10 primeros registros
head(r1_t,10)
## # A tibble: 10 x 2
## id_date total
## <date> <dbl>
## 1 2018-01-01 2
## 2 2018-02-01 8
## 3 2018-03-01 5
## 4 2018-04-01 11
## 5 2018-05-01 8
## 6 2018-06-01 18
## 7 2018-07-01 6
## 8 2018-08-01 7
## 9 2018-09-01 8
## 10 2018-10-01 12
#Gráfico de la serie
p1_t <- ggplot(r1_t, aes(id_date, total)) +
geom_line() + #Gráfico de lineas
geom_point(size=.6, colour="#2072B2") + #coloca los puntos
theme_bw() + #tema del gráfico en blanco
theme(axis.title.x = element_blank(), #remuevo el titulo del eje x
axis.text.x = element_text(size = 5, colour = "black", angle = 60, vjust = .5), #texto en eje x
axis.ticks.y = element_blank(), #remueve los marcadores del eje y
axis.title.y = element_text(size = 6), #tamaño titulo en y
axis.text.y = element_text(size = 5, colour = "black"), #tamaño del texto en eje y
plot.title = element_text(size=8, hjust = .5), #tamaño del titulo centrado
panel.grid.major = element_line(colour = "#2072B2", #color, tamaño y diseño de
size = .05, #la malla de la gráfica
linetype = "dashed")) +
scale_y_continuous("Cantidad enviada\n", limits = c(0,30), breaks = seq(0,30,5))+ #escalo el eje y
ggExtra::removeGridX() + #remueve grid del eje x
ggtitle("Serie repuesto AC/DCDV1") + #titulo de la gráfica
scale_x_date(date_labels = "%b%Y", #etiquetas en las fechas, limites y saltos
limits = as.Date(c('2018-01-01','2020-01-01')),
date_breaks = "2 month") +
geom_hline(yintercept = mean(r1_t$total), color = "blue", linetype = "dashed", size=.3)
p1_t
#Transformación en serie de tiempo para calculos
r1_ts <- ts(r1_t[,2], frequency = 12, start = c(2018,1))
#Descomposición de la serie
autoplot(decompose(r1_ts)) + theme_bw() +
theme(axis.title.x = element_blank(),
axis.text.x = element_text(size = 5, colour = "black"),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed"))+
ggExtra::removeGridX() +
ggtitle("Descomposición de la serie repuesto AC/DCDV1")
La serie de tiempo que se estudia en este ejemplo parece tener una ligera tendencia y estacionalidad a través del tiempo. Se emplea una media móvil simple como indicador de la tendencia para esta serie.
#Definimos el horizonte para el promedio
k <- 7
#Calculamos la media movil simple
sma <- rollmean(r1_ts, k, fill = NA)
sma
## Jan Feb Mar Apr May Jun Jul
## 2018 NA NA NA 8.285714 9.000000 9.000000 10.000000
## 2019 15.000000 15.857143 15.571429 17.428571 16.714286 17.714286 18.428571
## 2020 13.428571 12.142857 11.857143 12.142857 12.285714 11.857143 12.571429
## Aug Sep Oct Nov Dec
## 2018 9.857143 10.285714 10.285714 12.285714 13.857143
## 2019 18.428571 17.000000 17.571429 16.000000 16.000000
## 2020 14.285714 13.714286 NA NA NA
#Transformamos el suavizamiento a un data frame
sma <- data.frame(sma)
#Añadimos las fechas correspondientes
sma <- sma %>% mutate(id_date=as.Date(paste0(rep(c(2018, 2019, 2020), each=12),"-",rep(1:12, 3),"-",1)))
#Creamos una base con las dos series
p2_t <- merge(r1_t, sma, by="id_date")
p2_tMelted <- reshape2::melt(p2_t, id.var='id_date')
#Graficamente
ggplot(p2_tMelted, aes(x=id_date, y=value, col=variable)) + geom_line() +
theme_bw() +
theme(axis.title.x = element_blank(),
axis.text.x = element_text(size = 5, colour = "black", angle = 60, vjust = .5),
axis.ticks.y = element_blank(),
axis.title.y = element_text(size = 6),
legend.title=element_blank(),
legend.text = element_text(size=5),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed")) +
scale_y_continuous("Cantidad enviada\n", limits = c(0,30), breaks = seq(0,30,5))+
ggExtra::removeGridX() +
ggtitle("Comparativa series AC/DCDV1 y SMA") +
scale_x_date(date_labels = "%b%Y",
date_breaks = "2 month") +
scale_color_discrete(labels=c("Serie AC/DCDV1", "SMA"))
Los promedios móviles centrados se calculan promediando los datos tanto del pasado como en el futuro de un punto determinado de tiempo. En este sentido, no se pueden utilizar para realizar pronósticos porque, en el momento de la predicción, el futuro es incierto. Por lo tanto, se usan medias móviles asimétricas, donde la ventana de \(k\) períodos se coloca sobre los valores \(k\) disponibles más recientes de la serie. Por ejemplo, si tenemos datos hasta el período de tiempo \(t\), podemos predecir el valor de \(t+1\) promediando sobre \(k\) períodos antes de \(t+1\), la fórmula sería:
\[ \hat{y}_{t+1}=\dfrac{y_{t-4}+y_{t-3}+y_{t-2}+y_{t-1}+y_{t}}{5} \]
Continuando con el ejemplo propuesto, se aplica la media móvil asimétrica con una ventana de 12 días promedio para pronosticar la demanda en los siguientes períodos.
#Media móvil asimétrica horizonte de 12 días
sma_a <- rollmean(r1_ts, 12, align = "right", fill = NA)
#Transformamos a un data frame y calculamos la predicción para el 2020-12-01
sma_a <- data.frame(sma_a)
#Agregamos las fechas
sma_a <- sma_a %>% mutate(id_date=as.Date(paste0(rep(c(2018, 2019, 2020), each=12),"-",rep(1:12, 3),"-",1)))
#Creamos una base con las dos series
p3_t <- merge(r1_t, sma_a, by="id_date")
p3_tMelted <- reshape2::melt(p3_t, id.var='id_date')
ggplot(p3_tMelted, aes(x=id_date, y=value, col=variable)) + geom_line() +
theme_bw() +
theme(axis.title.x = element_blank(),
axis.text.x = element_text(size = 5, colour = "black", angle = 60, vjust = .5),
axis.ticks.y = element_blank(),
axis.title.y = element_text(size = 6),
legend.title=element_blank(),
legend.text = element_text(size=5),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed")) +
scale_y_continuous("Cantidad enviada\n", limits = c(0,30), breaks = seq(0,30,5))+
ggExtra::removeGridX() +
ggtitle("Comparativa series AC/DCDV1 y SMA Asimétrico") +
scale_x_date(date_labels = "%b%Y",
date_breaks = "2 month") +
scale_color_discrete(labels=c("Serie AC/DCDV1", "SMA A."))
#Predicción para ene2021
ene21 <- sum(p3_t[25:36,2])/12; ene21
## [1] 13.08333
#Predicción para los próximos 6 meses
val <- p3_t$total.x
fit <- NA
k <- 1:6
for(i in seq_along(k)){
fit[i] <- sum(val[length(val):(length(val)-11)])/12
val <- c(val,fit[i])
}
val[37:42]
## [1] 13.08333 13.17361 13.18808 13.20375 13.55406 13.51690
Esta técnica se emplea a menudo con un número par de puntos de datos para que el producto final sea simétrico alrededor de cada punto. Por ejemplo, un promedio de media móvil de un número par está desiquilibrado y, para nuestro propósito, el desequilibrio estará a favor de observaciones más recientes.
\[ \hat{y}_t=\dfrac{y_{t-1}+y_t+y_{t+1}+y_{t+2}}{4} \]
Para hacer que la media móvil sea simétrica (más precisa), tomamos un 2-MA del 4-MA para crear un 2x4-MA. Para el paso 2-MA, promediamos las medias móviles actuales y anteriores.
\[ \hat{y}_t=\frac{1}{8}y_{t-2}+\frac{1}{4}y_{t-1}+\frac{1}{4}y_{t}+\frac{1}{4}y_{t+1}+\frac{1}{8}y_{t+2} \]
Un promedio móvil de un promedio móvil se puede considerar como un MA simétrico que tiene diferentes pesos en cada observación cercana. Por ejemplo, el 2x4-MA es equivalente a un 5-MA ponderado por \([\frac{1}{8}, \frac{1}{4},\frac{1}{4},\frac{1}{4},\frac{1}{8}]\). En general, un m-MA ponderado se puede escribir como:
\[ \hat{T}_t=\sum_{j=-k}^{k}a_{j}y_{t+j} \] donde \(k=\frac{(m-1)}{2}\) y los pesos vienen dados por \([a_{-k}, \dots, a_{k}]\). Es importante que todos los pesos sumen uno y que sean simétricos para que \(a_j=a_{-j}\). Este simple m-MA es un caso especial donde todos los pesos son iguales a \(\frac{1}{m}\). Una de las principales ventajas es que ofrecen una estimación más suave del ciclo de tendencia. En lugar de que las observaciones ingresen y salgan del cálculo con el peso total, sus pesos se aumentan lentamente y luego disminuyen lentamente, lo que da como resultado una curva más suave.
Este método es adecuado para datos sin tendencia o patron estacional. Se pondera las observaciones recientes más que las observaciones anteriores. El peso de cada ponderación se determina mediante el uso de un parámetro de suacvizado, que se denota como \(\alpha\). Para un conjunto con \(T\) observaciones, se calcula el valor predicho.
\[ \hat{y}_t=\alpha y_t+\alpha(1-\alpha)y_{t-1}+\cdots+\alpha(1-\alpha)^{t-1}y_t \]
donde \(0 < \alpha \leq 1\). También es común utilizar la forma componente de este modelo dada por: \[ \hat{y}_{t+1}=l_t \]
\[ l_t=\alpha y_t +(1-\alpha)l_{t-1} \]
En ambas ecuaciones podemos observar que el maypr peso se coloca a la observación más reciente. En la práctica, \(\alpha\) es igual a \(0.1 - 0.2\) tiende a funcionar bastante bien. Cuando \(\alpha\) está más cerca de cero, consideramos este como aprendizaje lento porque el algoritmo da más peso a los datos históricos. Cuando \(\alpha\) está más cerca de 1 consideramos este aprendizaje rápido porque el algoritmo da más peso a la observación más reciente; por lo tanto, los cambios recientes en los datos tendrá un mayor impacto en los valores pronosticados.
Continuando con el ejemplo, se aplica el método de suavizamiento para la serie de los repuestos.
#Muestra de entrenamiento
train.ts <- ts(r1_t[1:30,2], frequency = 12, start = c(2018,1))
#Muestra de validacion
test.ts <- ts(r1_t[30:36,2], frequency = 12, start = c(2020,8))
test.ts1 <- ts(r1_t[31:36,2], frequency = 12, start = c(2020,8))
#Suavizado exponencial simple
ses <- ses(train.ts, h = 4, alpha = .2)
ses
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jul 2020 13.59617 6.384798 20.80755 2.567326 24.62502
## Aug 2020 13.59617 6.241985 20.95036 2.348912 24.84344
## Sep 2020 13.59617 6.101892 21.09046 2.134659 25.05769
## Oct 2020 13.59617 5.964371 21.22798 1.924339 25.26801
#Grafico de la predicción del modeloo ses
p4_t <- autoplot(ses) + theme_bw() +
theme(axis.title.x = element_blank(),
axis.text.x = element_text(size = 5, colour = "black", vjust = .5),
axis.ticks.y = element_blank(),
axis.title.y = element_text(size = 6),
legend.title=element_blank(),
legend.text = element_text(size=5),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed")) +
scale_y_continuous("Cantidad enviada\n", limits = c(0,30), breaks = seq(0,30,5))+
ggExtra::removeGridX() +
ggtitle("Proyecciones de la serie AC/DCDV1 con SES")
p4_t
El método mejora en sus predicciones cuando la serie no presenta ninguna tendencia. Por lo tanto, procedemos a diferenciar la serie original de los datos
dr1_ts <- diff(train.ts)
dr1_ts.test <- diff(test.ts)
#Gráfico de la serie diferenciada
p4_t <- autoplot(dr1_ts) +
theme_bw() +
theme(axis.title.x = element_blank(),
axis.text.x = element_text(size = 5, colour = "black", vjust = .5),
axis.ticks.y = element_blank(),
axis.title.y = element_text(size = 6),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed")) +
scale_y_continuous("Cantidad enviada\n", breaks = seq(-10,15,5))+
ggExtra::removeGridX() +
ggtitle("Serie diferenciada repuesto AC/DCDV1")
p4_t
#Calculamos el SES de la serie diferenciada
ses_dif <- ses(dr1_ts, alpha=.2, h = 4)
ses_dif
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jul 2020 0.1051907 -9.594044 9.804426 -14.72851 14.93889
## Aug 2020 0.1051907 -9.786127 9.996508 -15.02227 15.23266
## Sep 2020 0.1051907 -9.974550 10.184931 -15.31044 15.52082
## Oct 2020 0.1051907 -10.159515 10.369896 -15.59332 15.80370
#Grafico de la predicción del modeloo ses
p5_t <- autoplot(ses_dif) + theme_bw() +
theme(axis.title.x = element_blank(),
axis.text.x = element_text(size = 5, colour = "black", vjust = .5),
axis.ticks.y = element_blank(),
axis.title.y = element_text(size = 6),
legend.title=element_blank(),
legend.text = element_text(size=5),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed")) +
scale_y_continuous("Cantidad enviada\n",breaks = seq(-10,15,5))+
ggExtra::removeGridX() +
ggtitle("Proyecciones de la serie diferenciada AC/DCDV1 con SES")
p5_t
Para comparar que tan bien predice el modelo, podemos comparar nuestros pronósticos con nuestro conjunto de datos de validación.
kable(accuracy(ses_dif,dr1_ts.test), align = "c")
| ME | RMSE | MAE | MPE | MAPE | MASE | ACF1 | Theil’s U | |
|---|---|---|---|---|---|---|---|---|
| Training set | -0.2439326 | 7.302714 | 5.64375 | NaN | Inf | 0.7159981 | -0.6005006 | NA |
| Test set | -0.6051907 | 3.551937 | 3.50000 | 99.56171 | 99.56171 | 0.4440299 | -0.5000000 | 0.4135442 |
El método Holt realiza predicciones para datos con tendencia pero sin estacionalidad utilizando dos parámetros de suavizamiento, \(\alpha\) y \(\beta\), que corresponden a los componentes de nivel y tendencia, respectivamente. Para el método de Holt, la predicción será una línea de una pendiente distinta de cero que se extiende desde el paso del tiempo despúes del útlimo punto de datos recopilados en adelante.
El pronóstico de k-step-forward se obtiene combinando el nivel estimado en el tiempo \(t(L_t)\) y la estimación de tendencia en el tiempo \(t(T_t)\).
\[ \hat{y}_{T+1}=L_{T}+kT_{t} \]
El nivel \(L_t\) y tendencia \(T_t\) se actualizan a través de un par de ecuaciones de actualización, que es donde entran los parámetros de suavizamiento.
\[ L_t=\alpha y_t+ \alpha(1-\alpha)(L_{t-1}+T_{t-1}) \] \[ T_t=\beta(L_t-L_{t-1})+(1-\beta)T_{t-1} \] En estas ecuaciones, la primera significa que el nivel en el momento \(t\) es un promedio ponderado del valor real en el momento \(t\) y el nivel en el período anterior, ajustado por la tendencia. La segunda ecuación significa que la tendencia en el momento \(t\) es un promedio ponderado de la tendencia en el período anterior y la información más reciente sobre el cambio en el nivel. Similar al SES, \(\alpha\) y \(\beta\) se limitan a 0 - 1 con valores más altos proporcionan un aprendizaje más rápido y valores más bajos que proporcionan un aprendizaje más lento.
Para capturar una tendencia multiplicativa, se hace un pequeño ajuste en las ecuaciones anteriores: \[ \hat{y}_{t+1}=L_t \times kT_t \] \[ L_t = \alpha y_t + \alpha(1-\alpha) (L_{t-1}\times T_{t-1}) \] \[ T_t = \beta \left( \dfrac{L_t}{L_{t-1}} \right) +(1-\beta)T_{t-1} \]
Aplicando el método de Holt a la serie en estudio:
hlt <- holt(train.ts, h=6)
hlt
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jul 2020 14.13846 6.848548 21.42837 2.989501 25.28742
## Aug 2020 14.40264 6.816103 21.98918 2.800031 26.00526
## Sep 2020 14.66683 6.794632 22.53902 2.627345 26.70631
## Oct 2020 14.93101 6.782982 23.07903 2.469678 27.39234
## Nov 2020 15.19519 6.780187 23.61019 2.325554 28.06483
## Dec 2020 15.45937 6.785429 24.13332 2.193720 28.72502
p6_t <- autoplot(hlt) +
theme_bw() +
theme(axis.title.x = element_blank(),
axis.text.x = element_text(size = 5, colour = "black", vjust = .5),
axis.ticks.y = element_blank(),
axis.title.y = element_text(size = 6),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed")) +
scale_y_continuous("Cantidad enviada\n", breaks = seq(-10,30,5))+
ggExtra::removeGridX() +
ggtitle("Serie repuesto AC/DCDV1 método de Holt")
p6_t
hlt$model
## Holt's method
##
## Call:
## holt(y = train.ts, h = 6)
##
## Smoothing parameters:
## alpha = 0.2881
## beta = 1e-04
##
## Initial states:
## l = 5.9636
## b = 0.2642
##
## sigma: 5.6883
##
## AIC AICc BIC
## 212.0481 214.5481 219.0541
kable(accuracy(hlt,test.ts1), align = "c")
| ME | RMSE | MAE | MPE | MAPE | MASE | ACF1 | Theil’s U | |
|---|---|---|---|---|---|---|---|---|
| Training set | -0.0053028 | 5.295565 | 4.139699 | -17.05496 | 40.56978 | 0.4543572 | -0.0233594 | NA |
| Test set | -0.5310076 | 4.124122 | 3.869183 | -12.83840 | 29.62489 | 0.4246664 | 0.1790143 | 0.6522865 |
Podemos intentar mejorar la predicción ajustando el modelo para diferentes valores de \(\beta\)
beta <- seq(.001,.5, .001)
RMSE <- NA
for(i in seq_along(beta)){
fit <- holt(train.ts, beta = beta[i], h = 6)
RMSE[i] <- accuracy(fit, test.ts1)[2,2]
}
beta.fit <- data.frame(beta, RMSE)
beta.min <- filter(beta.fit, RMSE==min(RMSE))
beta.min
## beta RMSE
## 1 0.22 3.693711
ggplot(beta.fit, aes(beta, RMSE)) +
geom_line() +
geom_point(data=beta.min, aes(beta, RMSE), size=1, color="blue") +
theme_bw() +
theme(axis.title.x = element_text(size=6, colour = "black"),
axis.text.x = element_text(size = 5, colour = "black", vjust = .5),
axis.ticks.y = element_blank(),
axis.title.y = element_text(size = 6),
axis.text.y = element_text(size = 5, colour = "black"),
plot.title = element_text(size=8, hjust = .5),
panel.grid.major = element_line(colour = "#2072B2",
size = .05,
linetype = "dashed")) +
scale_y_continuous("RMSE", breaks = seq(0,16,2))+
scale_x_continuous("Beta") +
ggExtra::removeGridX() +
ggtitle("Valor óptimo del parámetro beta")
Probamos estimar nuevamente el modelo con el valor de \(\beta\) óptimo.
hlt_1 <- holt(train.ts, h=6, beta = .22)
hlt_1
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jul 2020 13.12214 4.636840 21.60743 0.1449953 26.09928
## Aug 2020 13.79062 3.431815 24.14942 -2.0518055 29.63304
## Sep 2020 14.45910 1.486902 27.43131 -5.3801665 34.29837
## Oct 2020 15.12759 -1.055409 31.31058 -9.6221702 39.87735
## Nov 2020 15.79607 -4.081267 35.67341 -14.6036942 46.19584
## Dec 2020 16.46456 -7.512626 40.44174 -20.2053790 53.13449
hlt_1$model
## Holt's method
##
## Call:
## holt(y = train.ts, h = 6, beta = 0.22)
##
## Smoothing parameters:
## alpha = 0.4802
## beta = 0.22
##
## Initial states:
## l = 2.8158
## b = 1.8178
##
## sigma: 6.6211
##
## AIC AICc BIC
## 219.1587 220.7587 224.7635
kable(accuracy(hlt_1,test.ts1), align = "c")
| ME | RMSE | MAE | MPE | MAPE | MASE | ACF1 | Theil’s U | |
|---|---|---|---|---|---|---|---|---|
| Training set | -0.1741343 | 6.163920 | 4.896282 | -18.08756 | 47.13131 | 0.5373968 | -0.1243392 | NA |
| Test set | -0.7275878 | 3.693711 | 3.423337 | -13.31291 | 26.84947 | 0.3757321 | 0.1218431 | 0.5968626 |
Para realizar predicciones utilizando datos con tendencia y estacionalidad, recurrimos al método estacional de Holt Winters. Este método se puede implementar con una estructura “aditiva” o “multiplicativa”, donde la elección del modelo depende del conjunto de datos. El modelo aditivo se utiliza mejor cuando la tendencia estacional es de la misma magnitud en el conjunto de datos, mientras que se prefiere el modelo multiplicativo cuando la magnitud de la estacionalidad cambia a medida que aumenta el tiempo.
Para el modelo aditivo, la forma de la ecuación regular es: \[ \hat{y}_{t+1}=L_t+kT_t+S_{t+k-m} \] El nivel \(L_t\), la tendencia \(T_t\) y la estacionalidad \(S_t\) se actualizan a través de un par de ecuaciones de actualización donde intervienen los parámetros de suavizamiento.
\[ L_t=\alpha(y_t-S_{t-m})+(1-\alpha)(L_{t-1}+ T_{t-1}) \]
\[ T_t=\beta(L_{t-1}+ T_{t-1})+(1-\beta)T_{t-1} \] \[ S_t=\gamma(y_t-L_t)+(1-\gamma)S_{t-m} \] De manera similar al SES y al método de Holt,los tres parámetros están restringidos al intervalo \((0,1]\).
Aplicando el método de Holt-Winters a la serie en estudio:
hw <- ets(train.ts, model = "AAA")
summary(hw)
## ETS(A,A,A)
##
## Call:
## ets(y = train.ts, model = "AAA")
##
## Smoothing parameters:
## alpha = 0.2162
## beta = 1e-04
## gamma = 0.6296
##
## Initial states:
## l = 5.5737
## b = 0.3134
## s = -2.4555 -4.1799 3.2755 -2.5057 -8.2977 -6.5536
## 10.6981 0.8942 2.4752 -0.5081 -2.4323 9.5898
##
## sigma: 10.3776
##
## AIC AICc BIC
## 253.5505 304.5505 277.3709
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set -0.2222448 7.089231 5.203259 -26.05345 64.58367 0.5710894
## ACF1
## Training set -0.01327052
hw_f <- forecast(hw, h=6)
hw_f
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jul 2020 20.097107 6.797713 33.39650 -0.2425603 40.43677
## Aug 2020 10.892772 -2.714115 24.49966 -9.9171659 31.70271
## Sep 2020 20.253089 6.345228 34.16095 -1.0171498 41.52333
## Oct 2020 17.716596 3.513862 31.91933 -4.0046104 39.43780
## Nov 2020 11.761679 -2.730194 26.25355 -10.4017288 33.92509
## Dec 2020 7.359078 -7.416542 22.13470 -15.2382823 29.95644
kable(accuracy(hw_f, test.ts1), align = "c")
| ME | RMSE | MAE | MPE | MAPE | MASE | ACF1 | Theil’s U | |
|---|---|---|---|---|---|---|---|---|
| Training set | -0.2222448 | 7.089231 | 5.203259 | -26.053454 | 64.58367 | 0.5710894 | -0.0132705 | NA |
| Test set | 0.8033573 | 8.221212 | 7.148340 | -8.454511 | 48.30016 | 0.7845739 | 0.3160046 | 1.506997 |
checkresiduals(hw_f)
##
## Ljung-Box test
##
## data: Residuals from ETS(A,A,A)
## Q* = 15.458, df = 3, p-value = 0.001464
##
## Model df: 16. Total lags used: 19
Si tenemos estacionalidad multiplicativa, entonces nuestra forma de la ecuación cambia:
\[ \hat{y}_{t+1}= (L_{t} +kT_{t})S_{t+k-m} \] El nivel \(L_t\), la tendencia \(T_t\) y la estacionalidad \(S_t\) se actualizan a través de un par de ecuaciones de actualización donde intervienen los parámetros de suavizamiento.
\[ L_t=\alpha \dfrac{y_t}{S_{t-m}}+(1-\alpha)(L_{t-1}+T_{t-1}) \]
\[ T_t=\beta(L_{t}-L_{t-1})+(1-\beta)T_{t-1} \] \[ S_t = \gamma \dfrac{y_t}{L_t}+(1-\gamma)S_{t-m} \]
hw_m <- ets(train.ts, model = "MMM")
summary(hw_m)
## ETS(M,M,M)
##
## Call:
## ets(y = train.ts, model = "MMM")
##
## Smoothing parameters:
## alpha = 0.1458
## beta = 0.1424
## gamma = 0.0029
##
## Initial states:
## l = 8.0605
## b = 1.0239
## s = 0.7042 0.8237 1.1328 1.1125 0.6453 0.9269
## 1.6749 1.0641 1.1795 0.8384 0.985 0.9126
##
## sigma: 0.4895
##
## AIC AICc BIC
## 223.5533 274.5533 247.3736
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -1.839297 8.45185 4.416584 -29.94618 48.01181 0.4847471 0.2102473
hwm_f <- forecast(hw_m, h=6)
hwm_f
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jul 2020 7.640882 2.8523952 12.488628 0.2845318 15.02008
## Aug 2020 4.822279 1.7984342 8.104849 0.2837716 10.01423
## Sep 2020 7.525233 2.7181165 13.229900 0.3739944 16.78250
## Oct 2020 6.944160 2.2358446 13.628637 0.2274005 18.74688
## Nov 2020 4.574542 1.3278182 9.918623 0.2261158 14.73759
## Dec 2020 3.540794 0.8629064 8.921983 0.1880326 14.30815
kable(accuracy(hwm_f, test.ts1), align = "c")
| ME | RMSE | MAE | MPE | MAPE | MASE | ACF1 | Theil’s U | |
|---|---|---|---|---|---|---|---|---|
| Training set | -1.839296 | 8.45185 | 4.416584 | -29.94618 | 48.01181 | 0.4847471 | 0.2102473 | NA |
| Test set | 8.918598 | 10.49940 | 8.918598 | 56.43483 | 56.43483 | 0.9788706 | 0.2941233 | 1.954509 |
checkresiduals(hwm_f)
##
## Ljung-Box test
##
## data: Residuals from ETS(M,M,M)
## Q* = 41.631, df = 3, p-value = 4.805e-09
##
## Model df: 16. Total lags used: 19
hw_m1 <- ets(train.ts, model = "MAM")
summary(hw_m1)
## ETS(M,A,M)
##
## Call:
## ets(y = train.ts, model = "MAM")
##
## Smoothing parameters:
## alpha = 0.1388
## beta = 0.1388
## gamma = 1e-04
##
## Initial states:
## l = 8.6143
## b = 0.0336
## s = 0.6905 0.7984 1.1889 1.0968 0.6865 0.9147
## 1.8665 1.057 1.1208 0.7631 0.9099 0.907
##
## sigma: 0.5168
##
## AIC AICc BIC
## 223.6023 274.6023 247.4227
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -1.050813 8.343387 4.624479 -24.93227 49.10704 0.5075647 0.1036556
hwm1_f <- forecast(hw_m1, h=6)
hwm1_f
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jul 2020 6.9661575 2.352342 11.579973 -0.0900650 14.022380
## Aug 2020 4.2457772 1.232768 7.258787 -0.3622233 8.853778
## Sep 2020 5.2139557 0.666400 9.761511 -1.7409305 12.168842
## Oct 2020 3.9505050 -1.325990 9.227000 -4.1191984 12.020208
## Nov 2020 1.5105357 -2.649404 5.670475 -4.8515425 7.872614
## Dec 2020 0.3181932 -4.043977 4.680363 -6.3531698 6.989556
kable(accuracy(hwm1_f, test.ts1), align = "c")
| ME | RMSE | MAE | MPE | MAPE | MASE | ACF1 | Theil’s U | |
|---|---|---|---|---|---|---|---|---|
| Training set | -1.050813 | 8.343387 | 4.624479 | -24.93227 | 49.10704 | 0.5075647 | 0.1036556 | NA |
| Test set | 11.352207 | 12.883862 | 11.352207 | 73.60455 | 73.60455 | 1.2459739 | 0.3208982 | 2.448427 |
checkresiduals(hwm1_f)
##
## Ljung-Box test
##
## data: Residuals from ETS(M,A,M)
## Q* = 36.453, df = 3, p-value = 6.007e-08
##
## Model df: 16. Total lags used: 19
Nota: Optimizar el modelo AAA para el parámetro beta