INTRODUCCIÓN

En el informe hablaremos de temas como: La función tslm, apreciación de una serie con componentes de multiestacionalidad componentes, Entrenamiento y prueba del modelo de previsión, selección del modelo, Analisis de residuos, Finalización de previsión, entre otros. que sin duda nos enseñar la importancia del análisis estadístico.

PARTE 1

MODELAMIENTO PREDICTIVO CON REGRESIÓN LINEAL

Ingeniería de características de los componentes de la serie

  • Utilizamos la librería ‘TSstudio’ específicamente la función ’ts_plot’para comenzar a graficar nuestra serie de tiempo relacionada al consumo de gas en USA
library(TSstudio)
## Warning: package 'TSstudio' was built under R version 4.1.1
data(USgas)

ts_plot(USgas,
 title = "Consumo de gas en USA",
 Ytitle = "Billiones pies cubico ",
 Xtitle = "Año",
 color = "green")
  • Utilizamos la función ‘ts_info()’ para mirar y revisar las características de nuestra serie de tiempo, esta función pertenece a la librería ‘TSstudio’
ts_info(USgas)
##  The USgas series is a ts object with 1 variable and 238 observations
##  Frequency: 12 
##  Start time: 2000 1 
##  End time: 2019 10

-Visualizamos los primeros datos con la función ‘head’

head(USgas)
## [1] 2510.5 2330.7 2050.6 1783.3 1632.9 1513.1
  • Podemos crear apartir de nuestra serie de tiempo múltiples series de tiempo con función ‘ts_decompose’ de ‘TSstudio’
ts_decompose(USgas)
  • La secuencia se convierte de un objeto ‘ts’ a un objeto ‘data.frame.’ ya que la función de regresión lineal incorporada en R del paquete ‘stats’, de este modo, utilizaremos la función ‘ts_to_prophet’ del paquete ‘TSstudio’

-Esta función convierte el objeto ts en dos columnas data.frame, donde ambas columnas simbolizan los componentes temporales y numéricos de la secuencia.

USgas_df <- ts_to_prophet(USgas)

utilizamos la función ‘head’ para mostrar los primeros 6 datos:

head(USgas_df)
##           ds      y
## 1 2000-01-01 2510.5
## 2 2000-02-01 2330.7
## 3 2000-03-01 2050.6
## 4 2000-04-01 1783.3
## 5 2000-05-01 1632.9
## 6 2000-06-01 1513.1
  • Ya habiendo cambiado las series en un objeto data.frame, comenzaremos a crear las características de entrada de la regresión. La primera característica que crearemos es la tendencia de la serie, utilizando la función ‘nrow’.
USgas_df$trend <- 1:nrow(USgas_df)
  • Utilizaremos la función ‘month’ del paquete ‘lubridate’ para extraer el mes del año de la variable de fecha ds:
library(lubridate)
## Warning: package 'lubridate' was built under R version 4.1.1
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
USgas_df$seasonal <- factor(month(USgas_df$ds, label = T), ordered = FALSE)
  • Utilizamos la función ‘head’ para convertir la salida de la función mes en una variable categórica no ordenada.
head(USgas_df)
##           ds      y trend seasonal
## 1 2000-01-01 2510.5     1      ene
## 2 2000-02-01 2330.7     2      feb
## 3 2000-03-01 2050.6     3      mar
## 4 2000-04-01 1783.3     4      abr
## 5 2000-05-01 1632.9     5      may
## 6 2000-06-01 1513.1     6      jun
  • Por último, estableceremos los últimos 12 meses de la serie como partición de prueba y entrenamiento.
h <- 12 # setting a testing partition length
train <- USgas_df[1:(nrow(USgas_df) - h), ]
test <- USgas_df[(nrow(USgas_df) - h + 1):nrow(USgas_df), ]

Modelización de la tendencia de la serie y de los componentes estacionales

-En primer lugar, modelamos la tendencia de la serie mediante la regresión de la serie sobre la variable de tendencia en el segmento de entrenamiento utilizando la función ’ lm ’

md_trend <- lm(y ~ trend, data = train)
  • Utilizaremos la función de ‘summary’ para revisar los detalles del modelo:
summary(md_trend)
## 
## Call:
## lm(formula = y ~ trend, data = train)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -547.2 -307.4 -153.2  333.1 1052.6 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 1751.0074    52.6435   33.26  < 2e-16 ***
## trend          2.4489     0.4021    6.09 4.86e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 394.4 on 224 degrees of freedom
## Multiple R-squared:  0.1421, Adjusted R-squared:  0.1382 
## F-statistic: 37.09 on 1 and 224 DF,  p-value: 4.861e-09

-El modelo se utiliza para predecir los valores corregidos en la parte de entrenamiento y los valores predichos en la parte de prueba.

-La función “predict” del paquete “stats”, como su nombre indica, predice los valores de los datos de entrada sobre la base del modelo dado.

train$yhat <- predict(md_trend, newdata = train)
test$yhat <- predict(md_trend, newdata = test)
  • A continuación utilizaremos el paquete proporcionado por la librería ‘plotly’ para crear una práctica función para trazar las series y la salida del modelo.
library(plotly)
## Warning: package 'plotly' was built under R version 4.1.1
## Loading required package: ggplot2
## Warning: package 'ggplot2' was built under R version 4.1.1
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
plot_lm <- function(data, train, test, title = NULL){
 p <- plot_ly(data = data,
 x = ~ ds,
 y = ~ y,
 type = "scatter",
 mode = "line",
 name = "Actual") %>%
 add_lines(x = ~ train$ds,
 y = ~ train$yhat,
 line = list(color = "red"),
 name = "Fitted") %>%
 add_lines(x = ~ test$ds,
 y = ~ test$yhat,
 line = list(color = "green", dash = "dot", width = 3),
 name = "Forecasted") %>%
 layout(title = title,
 xaxis = list(title = "Year"),
 yaxis = list(title = "Billion Cubic Feet"),
 legend = list(x = 0.05, y = 0.95))
 return(p)
 }

-Graficamos nuestra predicción de tendencia de la serie, estableciendo las entradas de la función ‘plot_lm’ con la salida del modelo. utilizando la función ’ lm ’

NOTA: compararemos con la grafica siguiente

plot_lm(data = USgas_df,
 train = train,
 test = test,
 title = "Predicción del componente de tendencia de la serie")
  • Tasa de error, creamos un vector con la función ‘c()’
mape_trend <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_trend
## [1] 0.1644088 0.1299951
  • Seguimos el mismo procedimiento que modelización y pronosticar los componentes estacionales mediante la regresión de las series sobre las variables estacionales. utilizando la función ’ lm ’
md_seasonal <- lm(y ~ seasonal, data = train)
summary(md_seasonal)
## 
## Call:
## lm(formula = y ~ seasonal, data = train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -608.98 -162.34  -50.77  148.40  566.89 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2774.28      49.75  55.759  < 2e-16 ***
## seasonalfeb   -297.92      70.36  -4.234 3.41e-05 ***
## seasonalmar   -479.10      70.36  -6.809 9.77e-11 ***
## seasonalabr   -905.28      70.36 -12.866  < 2e-16 ***
## seasonalmay  -1088.42      70.36 -15.468  < 2e-16 ***
## seasonaljun  -1105.49      70.36 -15.711  < 2e-16 ***
## seasonaljul   -939.35      70.36 -13.350  < 2e-16 ***
## seasonalago   -914.12      70.36 -12.991  < 2e-16 ***
## seasonalsept -1114.74      70.36 -15.843  < 2e-16 ***
## seasonaloct  -1022.21      70.36 -14.527  < 2e-16 ***
## seasonalnov   -797.53      71.33 -11.180  < 2e-16 ***
## seasonaldic   -256.67      71.33  -3.598 0.000398 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 216.9 on 214 degrees of freedom
## Multiple R-squared:  0.7521, Adjusted R-squared:  0.7394 
## F-statistic: 59.04 on 11 and 214 DF,  p-value: < 2.2e-16

-Actualizaremos nuestros valores de ‘yhat’ con la función ‘predict’, y luego ajustaremos los valores de previsión con la función ‘plot_lm’

train$yhat <- predict(md_seasonal, newdata = train)
test$yhat <- predict(md_seasonal, newdata = test)

-Graficamos la Predicción del componente estacional de la serie, con ayuda la función plot_lm para visualizar el modelo ajustado y los valores previstos.

#NOTA: concluimos que este método de predicción es más exacto que el anterior.

plot_lm(data = USgas_df,
 train = train,
 test = test,
 title = "Predicción del componente estacional de la serie")
  • Tasa de Error. creamos un vector con la función ‘c()’
mape_seasonal <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_seasonal
## [1] 0.08628973 0.21502100
  • Reunimos los modelos de componentes en un modelo y pronóstico característicos de la serie. utilizando la función ’ lm ’
md1 <- lm(y ~ seasonal + trend, data = train)

-Revisamos los modelo con la funcion ‘summary’ después de hacer la regresión de la serie con la tendencia y componentes estacionales

summary(md1)
## 
## Call:
## lm(formula = y ~ seasonal + trend, data = train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -514.73  -77.17  -17.70   85.80  336.95 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2488.8994    32.6011  76.344  < 2e-16 ***
## seasonalfeb   -300.5392    41.4864  -7.244 7.84e-12 ***
## seasonalmar   -484.3363    41.4870 -11.674  < 2e-16 ***
## seasonalabr   -913.1334    41.4880 -22.010  < 2e-16 ***
## seasonalmay  -1098.8884    41.4895 -26.486  < 2e-16 ***
## seasonaljun  -1118.5855    41.4913 -26.960  < 2e-16 ***
## seasonaljul   -955.0563    41.4936 -23.017  < 2e-16 ***
## seasonalago   -932.4482    41.4962 -22.471  < 2e-16 ***
## seasonalsept -1135.6874    41.4993 -27.366  < 2e-16 ***
## seasonaloct  -1045.7687    41.5028 -25.198  < 2e-16 ***
## seasonalnov   -808.0016    42.0617 -19.210  < 2e-16 ***
## seasonaldic   -269.7642    42.0635  -6.413 9.05e-10 ***
## trend            2.6182     0.1305  20.065  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 127.9 on 213 degrees of freedom
## Multiple R-squared:  0.9142, Adjusted R-squared:  0.9094 
## F-statistic: 189.2 on 12 and 213 DF,  p-value: < 2.2e-16

-Graficamos la Predecir la tendencia y los componentes estacionales del Serie, utilizando la función ‘train’ y ‘test’

train$yhat <- predict(md1, newdata = train)
test$yhat <- predict(md1, newdata = test)
plot_lm(data = USgas_df,
 train = train,
 test = test,
 title = "Predecir la tendencia y los componentes estacionales del
Serie")

-Tasa de error. creamos un vector con la función ‘c()’

mape_md1 <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_md1
## [1] 0.04774945 0.09143290
  • Creamos un segundo grado del polinomio para la entrada de tendencia con ayuda de la funcion ‘lm()’
md2 <- lm(y ~ seasonal + trend + I(trend^2), data = train)

summary(md2)
## 
## Call:
## lm(formula = y ~ seasonal + trend + I(trend^2), data = train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -468.47  -54.66   -2.21   63.11  294.32 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2.635e+03  3.224e+01  81.738  < 2e-16 ***
## seasonalfeb  -3.004e+02  3.540e+01  -8.487 3.69e-15 ***
## seasonalmar  -4.841e+02  3.540e+01 -13.676  < 2e-16 ***
## seasonalabr  -9.128e+02  3.540e+01 -25.787  < 2e-16 ***
## seasonalmay  -1.099e+03  3.540e+01 -31.033  < 2e-16 ***
## seasonaljun  -1.118e+03  3.540e+01 -31.588  < 2e-16 ***
## seasonaljul  -9.547e+02  3.540e+01 -26.968  < 2e-16 ***
## seasonalago  -9.322e+02  3.541e+01 -26.329  < 2e-16 ***
## seasonalsept -1.136e+03  3.541e+01 -32.070  < 2e-16 ***
## seasonaloct  -1.046e+03  3.541e+01 -29.532  < 2e-16 ***
## seasonalnov  -8.001e+02  3.590e+01 -22.286  < 2e-16 ***
## seasonaldic  -2.618e+02  3.590e+01  -7.293 5.95e-12 ***
## trend        -1.270e+00  4.472e-01  -2.840  0.00494 ** 
## I(trend^2)    1.713e-02  1.908e-03   8.977  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 109.1 on 212 degrees of freedom
## Multiple R-squared:  0.9379, Adjusted R-squared:  0.9341 
## F-statistic: 246.1 on 13 and 212 DF,  p-value: < 2.2e-16
  • Graficamos la predicción de la tendencia (polinómica) y los componentes estacionales de la serie.
train$yhat <- predict(md2, newdata = train)
test$yhat <- predict(md2, newdata = test)
 plot_lm(data = USgas_df,
 train = train,
 test = test,
 title = "Predicción de la tendencia (polinómica) y los componentes estacionales
de la serie")

-Tasa de Error. creamos un vector con la funcion ‘c()’

mape_md2 <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_md2
## [1] 0.03688770 0.04212618

La funcion TSLM

Por el momento, hemos desarrollado el proceso manual de transformar un objeto ts a un formato de modelo de predicción de regresión lineal.

  • La función tslm del paquete de pronóstico proporciona una función incorporada para transformar un objeto ts en un modelo de pronóstico de regresión lineal junto con otras características.

A continuación repetiremos el ejemplo anterior y se hará la predicción de las últimas 12 observaciones de la serie USgas con la función tslm usando la tendencia, el cuadrado de la tendencia y los componentes estacionales.

-Primero, dividamos la serie en particiones de entrenamiento y prueba usando la función ts_split:

USgas_split <- ts_split(USgas, sample.out = h)
train.ts <- USgas_split$train
test.ts <- USgas_split$test

Procederemos a aplicar la misma fórmula que usamos para crear el modelo de predicción md2 anterior haciendo uso de la función tslm:

library(forecast)
## Warning: package 'forecast' was built under R version 4.1.1
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
md3 <- tslm(train.ts ~ season + trend + I(trend^2))
  • En cuanto a md3, el resultado de la función tslm, se compara con la salida de md2:
summary(md3)
## 
## Call:
## tslm(formula = train.ts ~ season + trend + I(trend^2))
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -468.47  -54.66   -2.21   63.11  294.32 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.635e+03  3.224e+01  81.738  < 2e-16 ***
## season2     -3.004e+02  3.540e+01  -8.487 3.69e-15 ***
## season3     -4.841e+02  3.540e+01 -13.676  < 2e-16 ***
## season4     -9.128e+02  3.540e+01 -25.787  < 2e-16 ***
## season5     -1.099e+03  3.540e+01 -31.033  < 2e-16 ***
## season6     -1.118e+03  3.540e+01 -31.588  < 2e-16 ***
## season7     -9.547e+02  3.540e+01 -26.968  < 2e-16 ***
## season8     -9.322e+02  3.541e+01 -26.329  < 2e-16 ***
## season9     -1.136e+03  3.541e+01 -32.070  < 2e-16 ***
## season10    -1.046e+03  3.541e+01 -29.532  < 2e-16 ***
## season11    -8.001e+02  3.590e+01 -22.286  < 2e-16 ***
## season12    -2.618e+02  3.590e+01  -7.293 5.95e-12 ***
## trend       -1.270e+00  4.472e-01  -2.840  0.00494 ** 
## I(trend^2)   1.713e-02  1.908e-03   8.977  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 109.1 on 212 degrees of freedom
## Multiple R-squared:  0.9379, Adjusted R-squared:  0.9341 
## F-statistic: 246.1 on 13 and 212 DF,  p-value: < 2.2e-16

Ambos modelos (md2 y md3) son iguales según el resultado anterior.

ventajas de usar la función tslm, en lugar de configurar manualmente un modelo de regresión para la serie con la función lm:

  • Eficiencia: no requiere transformar la serie en un objeto data.frame y ingeniería de características

  • El objeto de salida admite toda la funcionalidad del pronóstico ; funciones de precisión y verificación de residuos y paquetes TSstudio test_forecast y plot_forecast

Modelado de eventos unicos y eventos no estacionales.

  • Los datos de las series temporales pueden presentar patrones inusuales,tales como:
  • Valores atipicos
  • Eventos no estacionales
  • Ruptura estructura
  • Al no expresarse en el modelo de regresión, este tipo de eventos sesgará los coeficientes -estimados, ya que el modelo ponderará esos tipos de eventos junto con los eventos regulares de la serie. La regresión de un modelo tslm con variables externas requiere un objeto “data.frame” separado con las variables correspondientes. El siguiente ejemplo demuestra el proceso de creación - de una variable binaria externa que es igual a 0 antes del año 2010 y 1 después, usando la tabla “USgas_df”:
 r <- which(USgas_df$ds == as.Date("2014-01-01"))
USgas_df$s_break <- ifelse(year(USgas_df$ds) >= 2010, 1, 0)
USgas_df$s_break[r] <- 1
  • Ahora usaremos la nueva característica para remodelar la serie USgas:
md3 <- tslm(USgas ~ season + trend + I(trend^2) + s_break, data = USgas_df)
  • Usemos la función de para summary revisar la salida del modelo:
summary(md3)
## 
## Call:
## tslm(formula = USgas ~ season + trend + I(trend^2) + s_break, 
##     data = USgas_df)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -469.25  -50.68   -2.66   63.63  275.89 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.661e+03  3.200e+01  83.164  < 2e-16 ***
## season2     -3.054e+02  3.448e+01  -8.858 2.61e-16 ***
## season3     -4.849e+02  3.448e+01 -14.062  < 2e-16 ***
## season4     -9.272e+02  3.449e+01 -26.885  < 2e-16 ***
## season5     -1.108e+03  3.449e+01 -32.114  < 2e-16 ***
## season6     -1.127e+03  3.450e+01 -32.660  < 2e-16 ***
## season7     -9.568e+02  3.450e+01 -27.730  < 2e-16 ***
## season8     -9.340e+02  3.451e+01 -27.061  < 2e-16 ***
## season9     -1.138e+03  3.452e+01 -32.972  < 2e-16 ***
## season10    -1.040e+03  3.453e+01 -30.122  < 2e-16 ***
## season11    -7.896e+02  3.497e+01 -22.577  < 2e-16 ***
## season12    -2.649e+02  3.498e+01  -7.571 9.72e-13 ***
## trend       -1.928e+00  4.479e-01  -4.304 2.51e-05 ***
## I(trend^2)   1.862e-02  1.676e-03  11.113  < 2e-16 ***
## s_break      6.060e+01  2.836e+01   2.137   0.0337 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 109 on 223 degrees of freedom
## Multiple R-squared:  0.9423, Adjusted R-squared:  0.9387 
## F-statistic: 260.3 on 14 and 223 DF,  p-value: < 2.2e-16

Previsión de una serie con componentes de multiestacionalidad componentes - un estudio de caso

El modelo de regresión nos brinda ventajas que no lo hacen los modelos tradicionales de series de tiempo como ARIMA o Holt-Winters, proporcionando gran variedad de opciones de personalizado, y además, moldear y realizar pronósticos acerca de series de tiempo con mayor dificultad como las de multisecionalidad.

A continuación se presentarán diferentes ejemplos en los que se haga uso de la serie UKgrid para realizar la predicción de varias estaciones con un modelo de regresión lineal.

La serie UKgrid

La serie UKgrid representa las necesidades de electricidad de la red nacional del Reino Unido y está disponible en el paquete UKgrid. Esta serie representa una serie temporal de datos de alta frecuencia con una frecuencia de media hora.

  • Usamos la función extract_grid del paquete UKgrid para definir la cadena, las características principales (por ejemplo, el formato de los datos, las variables de frecuencia, etc.).

Usaremos la estructura data.frame para llevar la serie a la frecuencia diaria:

library(UKgrid)
## Warning: package 'UKgrid' was built under R version 4.1.1
UKdaily <- extract_grid(type = "data.frame",
columns = "ND",
aggregate = "daily")

Vamos a utilizar la función head para comprobar las variables de la serie:

head(UKdaily)
##    TIMESTAMP      ND
## 1 2005-04-01 1920069
## 2 2005-04-02 1674699
## 3 2005-04-03 1631352
## 4 2005-04-04 1916693
## 5 2005-04-05 1952082
## 6 2005-04-06 1964584

Obtenemos el siguiente resultado:

A continuación se definen las dos variables de la serie: * TIMESTAMP: Un objeto de fecha utilizado como marca de tiempo o índice de la serie

  • ND: La demanda neta de electricidad

Usamos la función ts_plot para trazar la estructura de la serie y verificar:

ts_plot(UKdaily,

title = "The UK National Demand fo Electricity",

Ytitle = "MW",

Xtitle = "Year")

Obtenemos el siguiente resultado:

Como puede ver en el gráfico anterior, la serie es claramente descendente y tiene un patrón de cadena estacional. Como vimos en el Capítulo 6, Análisis de estacionalidad, esta serie muestra diversos patrones de estacionalidad:

  • Diario: Un ciclo de 365 días al año

  • Día de la semana: Un ciclo de 7 días

  • Mensual: Afecto del clima

La evidencia de estos patrones se puede evidenciar en el siguiente mapa de calor de la serie desde 2016, gracias a la función ts_heatmap de TSstudio (paquete):

ts_heatmap(UKdaily[which(year(UKdaily$TIMESTAMP) >= 2016),],
title = "UK the Daily National Grid Demand Heatmap")

Obtenemos el siguiente resultado:

Como puede verse en la serie del mapa de calor, la demanda global aumenta durante las semanas de invierno (por ejemplo, la semana 1 a 12 y las semana 44 a 52). Además, el salto de línea se puede observar entre semana, ya que la demanda aumenta entre semana y disminuye los fines de semana.

Preprocesamiento e ingeniería de características de la serie UKdaily

Para captar los componentes estacionales de la serie, definiremos la serie como diaria y crearemos las siguientes dos características:

  • Indicador del día de la semana
  • Indicador del mes del año

Dado que es razonable asumir (demostraremos este supuesto con la función ACF, luego de convertir la serie en un objeto ts) que la serie tiene una fuerte correlación con los rezagos estacionales, creamos una variable con un retraso de 365 observaciones.

Usaremos el paquete dplyr para crear estas nuevas características:

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
UKdaily <- UKdaily %>%
mutate(wday = wday(TIMESTAMP, label = TRUE),
month = month(TIMESTAMP, label = TRUE),
lag365 = dplyr::lag(ND, 365)) %>%
filter(!is.na(lag365)) %>%
arrange(TIMESTAMP)

Recalcando que el costo de usar una variable de retraso con una longitud de N es la pérdida de las primeras N observaciones, usamos las funciones de filtro para anular las filas de la tabla que faltan en la variable las primeras 365 observaciones ( lag365).

Luego de agregar esas nuevas caracteristicas podemos proceder a analizar la estructura de la tabla UKdaily:

str(UKdaily)
## 'data.frame':    4939 obs. of  5 variables:
##  $ TIMESTAMP: Date, format: "2006-04-01" "2006-04-02" ...
##  $ ND       : int  1718405 1691341 1960325 2023886 2026204 2008422 1981175 1770440 1749715 2012865 ...
##  $ wday     : Ord.factor w/ 7 levels "dom\\."<"lun\\."<..: 7 1 2 3 4 5 6 7 1 2 ...
##  $ month    : Ord.factor w/ 12 levels "ene"<"feb"<"mar"<..: 4 4 4 4 4 4 4 4 4 4 ...
##  $ lag365   : int  1920069 1674699 1631352 1916693 1952082 1964584 1990895 2003982 1811436 1684720 ...

A partir de lo anterior, obtenemos lo siguiente:

Teniendo en cuenta que la entrada de la función tslm debe estar en formato ts, principalmente para la cadena), convertimos la serie en un objeto ts.

Usamos la primera marca de tiempo de la serie y las funciones (el día del año) en lenguaje R, como year y yday del paquete lubridate para determinar el punto de partida del objeto:

start_date <- min(UKdaily$TIMESTAMP)
start <- c(year(start_date), yday(start_date))

Anteriormente en el capítulo 3, se menciona el objeto la serie temporal, utilizaremos la función ts del paquete stats para configurar el objeto ts:

UK_ts <- ts(UKdaily$ND,
start = start,
frequency = 365)

Después de transformar la serie en un objeto ts, podemos retroceder y confirmar la hipótesis que hicimos sobre el nivel de correlación entre la serie y sus retrasos estacionales con la función ts_acf (una versión interactiva de la función acf del paquete TSstudio).

Examinaremos la correlación de la serie con sus retrasos durante los últimos cuatro años:

library(TSstudio)
data(USgas)
acf(UK_ts, lag.max = 365 * 4)

A partir de lo anterior, obtenemos lo siguiente:

El gráfico ACF anterior confirma nuestra hipótesis, y la cadena tiene una fuerte relación con los retrasos por estación, en particular el fue de 365, el primer rezago.

Como nota al margen, tenga la seguridad de que la serie también tiene una fuerte correlación con los retrasos semanales (es decir, retraso 7, 14, 21, etc.). Sin embargo, en general, no se recomienda utilizar retrasos menores que el horizonte de pronóstico (por ejemplo, retraso 7 si el horizonte de pronóstico es 365) porque también debe predecir estos retrasos antes de poder utilizarlos. como entrada para el modelo.

Esto requiere un esfuerzo adicional ya que necesita prever estos retrasos. Además, puede aumentar el sesgo de pronóstico porque usamos valores de pronóstico como entradas.

Ahora que hemos creado las nuevas características para el modelo y configurado el objeto ts, podemos dividir la serie de entrada que creamos y el objeto de característica externa correspondiente “UKdaily” en una partición de entrenamiento y una partición de prueba.

Recordando que nuestro objetivo es predecir los próximos 365 y la longitud de la serie es lo suficientemente grande (2.50 observaciones), podemos proceder a establecer la partición de prueba a la longitud del horizonte de pronóstico: 365 observaciones. Estableceremos h, una variable indicadora, en 365, que será útil para definir las particiones y luego el horizonte de pronóstico:

h <- 365

Como hicimos anterioremente, dividiremos la serie en particiones de entrenamiento y prueba con la función ts_split :

UKpartitions <- ts_split(UK_ts, sample.out = h)
train_ts <- UKpartitions$train
test_ts <- UKpartitions$test

De manera similar, debemos dividir las características que construimos para el modelo de regresión (las características estacionales y de retraso) en dos particiones, una de entrenamiento y otra de prueba, siguiendo exactamente el orden que usamos para el objeto ts correspondiente. Hacemos uso de la funcionalidad de índice data.frame para establecer la tabla UKdaily en las particiones de entrenamiento y prueba:

train_df <- UKdaily[1:(nrow(UKdaily) - h), ]
test_df <- UKdaily[(nrow(UKdaily) - h + 1):nrow(UKdaily), ]

Capacitación y ensayo del modelo de predicción.

  • Se trabajará con 3 procesos de modelados de predicción.

  • Modelo de referencia

  • Modelo multiestacional

  • Un modelo multiestacional con un retardo estacional Se realizará la comparación de los tres modelos con el uso de la función “test_forecast”

  • Empezaremos con el modelo de referencia, retrocediendo la serie con su estacionalidad y los componentes de la tendencia.

md_tslm1 <- tslm(train_ts ~ season + trend)
  • Utilizaremos el modelo entrenado, “md_tslm1”, para pronosticar los próximos 365 días de la serie, correspondiente a las observaciones de la partición de prueba, utilizando la función “forecast”
fc_tslm1 <- forecast(md_tslm1, h = h)
  • Comparemos el rendimiento del modelo en los conjuntos de entrenamiento y pruebas usando el función test_forecast
test_forecast(actual = UK_ts,
 forecast.obj = fc_tslm1,
 test = test_ts)
  • En el modelo presentado se puede ver la tendencia de la serie y el dia de la estacionalidad, también según los resultados MAPE como podemos ver en la salida de la siguiente función de precisión, es del 6,09% y7,77% en las particiones de entrenamiento y pruebas, respectivamente.
accuracy(fc_tslm1, test_ts)
##                         ME     RMSE       MAE        MPE     MAPE      MASE
## Training set -9.030002e-12 121551.4 100439.64 -0.5721337 6.294111 0.8418677
## Test set     -1.740215e+04 123156.6  96785.27 -1.8735336 7.160573 0.8112374
##                   ACF1 Theil's U
## Training set 0.5277884        NA
## Test set     0.5106681  1.071899
  • Ahora intentaremos mejorar la precisión del modelo, añadiendo el día de la semana y el mes de el año características al modelo
md_tslm2 <- tslm(train_ts ~ season + trend + wday + month,
 data = train_df)
  • Ahora vamos a repetir el mismo proceso que antes, mediante el uso de un pronosticar con el modelo entrenado y evaluar el rendimiento del modelo.
fc_tslm2 <- forecast(md_tslm2, h = h,  newdata = test_df)
test_forecast(actual = UK_ts,
 forecast.obj = fc_tslm2,
 test = test_ts)
accuracy(fc_tslm2, test_ts)
##                         ME     RMSE      MAE        MPE     MAPE      MASE
## Training set -1.589161e-12 70032.14 51999.67 -0.1725754 3.158853 0.4358522
## Test set     -1.765395e+04 81683.91 65842.88 -1.3694262 4.703788 0.5518836
##                   ACF1 Theil's U
## Training set 0.7508301        NA
## Test set     0.6120506 0.6898049
  • vamos a añadir la variable lag al modelo, y repetiremos el proceso anterior.
md_tslm3 <- tslm(train_ts ~ season + trend + wday + month + lag365,
 data = train_df)
fc_tslm3 <- forecast(md_tslm3, h = h, newdata = test_df)
  • El rendimiento del tercer modelo se puede ver en el siguiente gráfico
test_forecast(actual = UK_ts,
 forecast.obj = fc_tslm3,
 test = test_ts)
  • Los modelos 2 y 3 tienen gran similitud en sus resultados, para observar las diferencias mas claramente se recurrira a la puntuacion MAPE.
accuracy(fc_tslm3, test_ts)
##                         ME     RMSE      MAE        MPE     MAPE      MASE
## Training set -1.175109e-11 69904.92 52006.75 -0.1717563 3.163385 0.4359116
## Test set     -1.754061e+04 81783.55 65957.66 -1.3613252 4.722083 0.5528457
##                   ACF1 Theil's U
## Training set 0.7500146        NA
## Test set     0.6094666 0.6925767
  • Los resultados del tercer modelo muestran una pequeña mejora en la precisión del modelo con 2,81% en el conjunto de formación y 5,07% en el conjunto de pruebas

Selección del modelo

Ahora es el momento de elegir un modelo. En este punto, está claro que el segundo y tercer modelo funcionan mejor que el primer modelo. Dado que tanto el segundo como el tercer modelo producen resultados similares, con una pequeña ventaja sobre el tercer modelo, tenemos que preguntarnos si una mejora en la tasa de error del conjunto de prueba de menos del 0.2% aumentaría el costo del valor que su uso reduciría. la evidencia. Variable set.lag (es decir, la pérdida de 365 observaciones y el costo adicional de un grado de libertad para el modelo). Depende. No hay una respuesta sencilla a esta pregunta. También depende del objetivo del pronóstico. Se recomienda considerar la siguiente prueba: * La primera pregunta en este caso es: ¿la variable de rezago es estadísticamente significativa? Si la variable no es estadísticamente significativa, no tiene sentido continuar la discusión y es mejor abandonar la variable. En el caso del tercer modelo, podemos usar la función resumen para observar el nivel de significancia de la variable lag365:

summary(md_tslm3)$coefficients %>% tail(1)
##           Estimate Std. Error   t value     Pr(>|t|)
## lag365 -0.06038328 0.01545495 -3.907051 9.490321e-05

Obtenemos la siguiente salida: El valor p de la variable lag365 indica que la variable es estadísticamente significativa a un nivel de 0,001. *Del mismo modo, podemos aplicar una única prueba ANOVA con la función anova del paquete stats, y comprobar si la variable adicional es significativa:

anova(md_tslm3)
## Analysis of Variance Table
## 
## Response: train_ts
##             Df     Sum Sq    Mean Sq    F value    Pr(>F)    
## season     364 1.4279e+14 3.9227e+11    73.5348 < 2.2e-16 ***
## trend        1 7.2634e+13 7.2634e+13 13615.7078 < 2.2e-16 ***
## wday         6 4.5009e+13 7.5016e+12  1406.2214 < 2.2e-16 ***
## month       11 1.3721e+11 1.2473e+10     2.3382  0.007266 ** 
## lag365       1 8.1432e+10 8.1432e+10    15.2650  9.49e-05 ***
## Residuals 4190 2.2352e+13 5.3345e+09                         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Obtenemos la siguiente salida: La prueba ANOVA también mostró que la variable lag365 es estadísticamente significativa. Backtest: Es posible que el tercer modelo sea más preciso solo por casualidad y no porque la variable de retardo contribuya a la precisión del modelo, ya que la diferencia es relativamente pequeña. Por lo tanto, el backtesting de ambos modelos podría ayudar a validar si la contribución de las variables de rezago es consistente en diferentes períodos de prueba. Se pueden utilizar métodos más robustos para la selección de características, p. Ej. B. B. Regresión escalonada, regresión de cresta o regresión de bucle. Aunque estos métodos están más allá del alcance de este libro, se recomienda que lo lea. En el Capítulo 12, Predicción mediante modelos de aprendizaje automático, examinaremos los enfoques de regresión que utilizan modelos de aprendizaje automático que incorporan métodos de selección de características. En aras de la simplicidad, nos atenemos al criterio de precisión y elegimos el tercer modelo para predecir la serie. El siguiente paso es volver a entrenar el modelo para todas las filas y pronosticar los próximos 365 días:

final_md <- tslm(UK_ts ~ season + trend + wday + month + lag365,
data = UKdaily)

## Análisis de los residuos Justo antes de finalizar la previsión, vamos a realizar un análisis de los residuos del modelo seleccionado utilizando la función checkresiduals:

checkresiduals(final_md)

## 
##  Breusch-Godfrey test for serial correlation of order up to 730
## 
## data:  Residuals from Linear regression model
## LM test = 3301.1, df = 730, p-value < 2.2e-16

Obtenemos la siguiente salida: Como puede verse en el gráfico de resumen de residuos anterior, los residuos no son ruido blanco porque existe cierta autocorrelación entre la serie residual y sus rezagos. Esto es técnicamente una indicación de que el modelo no captura todos los patrones o la información presente en la serie. Una forma de abordar este problema es identificar variables adicionales que puedan explicar la variación de los residuos.

El principal problema con este enfoque es que es difícil identificar variables externas que puedan explicar la variación de los residuos y que puedan predecirse. Por ejemplo, es razonable suponer que los modelos meteorológicos afectan la demanda de electricidad, pero es difícil predecir estos modelos meteorológicos con un año de antelación. Si se dejan patrones en los residuos del modelo, un enfoque alternativo es tratar los residuos del modelo como datos de series de tiempo separados y modelarlos con un modelo de pronóstico de series de tiempo diferente. Modelo de pronóstico. Un enfoque común es la regresión de error ARIMA, que presentamos en el Capítulo 11, Predicción con modelos ARIMA.

## Finalización de la previsión Terminamos el proceso y usamos el modelo entrenado que seleccionamos para predecir 365 observaciones futuras. Dado que usamos variables externas con la función tslm, necesitamos generar sus valores futuros. Esto es relativamente fácil porque usamos variables deterministas. Luego creamos un objeto data.frame con los valores de wday, month y lag365 para las próximas 365 observaciones futuras. Un enfoque simplificado es crear primero las observaciones esperadas y luego extraer el día de la semana y el mes del año de este objeto:

UK_fc_df <- data.frame(date = seq.Date(from = max(UKdaily$TIMESTAMP) + days(1),
by = "day",
length.out = h))

A continuación, podemos utilizar la variable date para crear las variables wday y month con el paquete lubridate:

UK_fc_df$wday <- factor(wday(UK_fc_df$date, label = TRUE), ordered = FALSE)
UK_fc_df$month <- factor(month(UK_fc_df$date, label = TRUE), ordered = FALSE)
UK_fc_df$lag365 <- tail(UKdaily$ND, h)

Utilicemos la función de previsión para crear la previsión:

UKgrid_fc <- forecast(final_md, h = h, newdata = UK_fc_df)

Por último, trazaremos el pronóstico final usando la función plot_forecast del paquete TSstudio:

plot_forecast(UKgrid_fc,
title = "The UK National Demand for Electricity Forecast",
Ytitle = "MW",
 Xtitle = "Year")

Resumen

En este capítulo dimos a conocer las aplicaciones predictivas del modelo de regresión lineal. Aunque el modelo de regresión lineal no se diseñó para procesar datos de series de tiempo, la ingeniería de características simples se puede utilizar para transformar un problema de pronóstico en un problema de regresión lineal. La principal ventaja del modelo de regresión lineal sobre otros modelos tradicionales de series de tiempo es la capacidad del modelo para tener en cuenta variables y factores externos. Sin embargo, este modelo puede manejar series de tiempo con múltiples modelos estacionales, como vimos con el pronóstico de demanda de electricidad del Reino Unido.

PARTE 2

Predicciones con regresión lineal para terremotos significativos entre 1965-2016.

Ingeniería de características de los componentes de la serie

Earth_df<-read.csv("database.csv")

class(Earth_df)
## [1] "data.frame"
library(dplyr)
Earth_df <-Earth_df  %>%
  arrange(Date)
Earth_df <- ts(Earth_df$Magnitude, start = c(1965, 1), end = c(2016, 12), frequency = 12)
class(Earth_df)
## [1] "ts"
head(Earth_df)
##      Jan Feb Mar Apr May Jun
## 1965 6.5 5.9 5.6 5.6 6.0 6.8
library(TSstudio)
data(Earth_df)
## Warning in data(Earth_df): data set 'Earth_df' not found
ts_plot(Earth_df,
 title = "Significant earthquakes between 1965-2016",
 Ytitle = "Magnitude",
 Xtitle = "Year")

En esta gráfica se puede observar el comportamiento de los componentes de la serie de tiempo de los terremotos significativos, este lleva un patrón continuo y con mucha ocurrencia en el que se puede observar la estacionalidad del comportamiento.

  • Además, repasemos las principales características de la serie usando la función ts_info:
ts_info(Earth_df)
##  The Earth_df series is a ts object with 1 variable and 624 observations
##  Frequency: 12 
##  Start time: 1965 1 
##  End time: 2016 12
  • Vamos a explorar los componentes de la serie usando la funcion
ts_decompose(Earth_df)

Se puede ver en el gráfico anterior que la tendencia de la serie es continua, también se puede observar que la estacionalidad de la serie es constante y nos presenta picos de valores atípicos.

  • Podemos observara en la grafica que el patron seasonal se mantiene constante durante todos los años

  • Antes de usar la función lm, la función de regresión lineal R incorporada de las estadísticas , tendremos que transformar la serie de un objeto ts a un objeto data.frame. Por lo tanto, utilizaremos la función ts_to_prophet del paquete TSstudio:

Earth2_df <- ts_to_prophet(Earth_df)
  • La función transforma el objeto ts en dos columnas de data.frame, donde las dos las columnas representan el tiempo y los componentes numéricos de la serie, respectivamente:
head(Earth2_df)
##           ds   y
## 1 1965-01-01 6.5
## 2 1965-02-01 5.9
## 3 1965-03-01 5.6
## 4 1965-04-01 5.6
## 5 1965-05-01 6.0
## 6 1965-06-01 6.8
  • Ahora que hemos convertido nuestra serie en un data.fame, procederemos a crear las caracteristicas de la entrada de la regresion.
Earth2_df$trend <- 1:nrow(Earth2_df)
  • Queremos crear es el componente estacional. Ya que queremos medir la contribución de cada unidad de frecuencia a la oscilación de la serie, vamos a utilizar un variable categórica para cada unidad de frecuencia. Vamos a utilizar la función de mes del paquete lubridate de extraer el mes del año de la variable ds date:
library(lubridate)
Earth2_df$seasonal <- factor(month(Earth2_df$ds, label = T), ordered = FALSE)
head(Earth2_df)
##           ds   y trend seasonal
## 1 1965-01-01 6.5     1      ene
## 2 1965-02-01 5.9     2      feb
## 3 1965-03-01 5.6     3      mar
## 4 1965-04-01 5.6     4      abr
## 5 1965-05-01 6.0     5      may
## 6 1965-06-01 6.8     6      jun
  • Finalmente, vamos a dividir la serie en pasting and training paste, estableciendo los ultimos 12 meses como una particion de la prueba.
h <- 12 # setting a testing partition length
train <- Earth2_df[1:(nrow(Earth2_df) - h), ]
test <- Earth2_df[(nrow(Earth2_df) - h + 1):nrow(Earth2_df), ]

Modelando la tendencia de la serie y estacional componentes

md_trend <- lm(y ~ trend, data = train)
summary(md_trend)
## 
## Call:
## lm(formula = y ~ trend, data = train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.4523 -0.3027 -0.1563  0.1497  1.9512 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  5.9541963  0.0357910 166.360   <2e-16 ***
## trend       -0.0001675  0.0001012  -1.656   0.0982 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4422 on 610 degrees of freedom
## Multiple R-squared:  0.004476,   Adjusted R-squared:  0.002844 
## F-statistic: 2.743 on 1 and 610 DF,  p-value: 0.09822
train$yhat <- predict(md_trend, newdata = train)
test$yhat <- predict(md_trend, newdata = test)
library(plotly)

plot_lm <- function(data, train, test, title = NULL){
 p <- plot_ly(data = data,
 x = ~ ds,
 y = ~ y,
 type = "scatter",
 mode = "line",
 name = "Actual") %>%
 add_lines(x = ~ train$ds,
 y = ~ train$yhat,
 line = list(color = "red"),
 name = "Fitted") %>%
 add_lines(x = ~ test$ds,
 y = ~ test$yhat,
 line = list(color = "green", dash = "dot", width = 3),
 name = "Forecasted") %>%
 layout(title = title,
 xaxis = list(title = "Year"),
 yaxis = list(title = "Magnitude"),
 legend = list(x = 0.05, y = 0.95))
 return(p) }
plot_lm(data = Earth2_df, train = train, test = test, title = "Predicting the Trend Component of the Series")

Los modelos de estas gráficas están diseñadas para capturar el movimiento general de una tendencia, la estructura y el patrón general de una serie. Por medio de estas se puede modelar y conocer la tendencia de una serie lo más acertada posible.

mape_trend <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_trend
## [1] 0.05435221 0.04106426
md_seasonal <- lm(y ~ seasonal, data = train)
summary(md_seasonal)
## 
## Call:
## lm(formula = y ~ seasonal, data = train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.4980 -0.3054 -0.1569  0.1657  1.9588 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   5.87255    0.06184  94.959   <2e-16 ***
## seasonalfeb  -0.01569    0.08746  -0.179    0.858    
## seasonalmar   0.09216    0.08746   1.054    0.292    
## seasonalabr   0.03922    0.08746   0.448    0.654    
## seasonalmay   0.08902    0.08746   1.018    0.309    
## seasonaljun   0.12549    0.08746   1.435    0.152    
## seasonaljul   0.03725    0.08746   0.426    0.670    
## seasonalago   0.06863    0.08746   0.785    0.433    
## seasonalsept -0.05882    0.08746  -0.673    0.501    
## seasonaloct   0.11569    0.08746   1.323    0.186    
## seasonalnov  -0.06863    0.08746  -0.785    0.433    
## seasonaldic  -0.06078    0.08746  -0.695    0.487    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4416 on 600 degrees of freedom
## Multiple R-squared:  0.02311,    Adjusted R-squared:  0.005199 
## F-statistic:  1.29 on 11 and 600 DF,  p-value: 0.2257
train$yhat <- predict(md_seasonal, newdata = train)
test$yhat <- predict(md_seasonal, newdata = test)
plot_lm(data = Earth2_df,
 train = train,
 test = test,
 title = "Predicting the Seasonal Component of the Series")
mape_seasonal <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_seasonal
## [1] 0.05383805 0.04855883
md1 <- lm(y ~ seasonal + trend, data = train)
summary(md1)
## 
## Call:
## lm(formula = y ~ seasonal + trend, data = train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.5457 -0.2986 -0.1457  0.1629  1.9132 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   5.9223487  0.0688236  86.051   <2e-16 ***
## seasonalfeb  -0.0155208  0.0873361  -0.178    0.859    
## seasonalmar   0.0924878  0.0873363   1.059    0.290    
## seasonalabr   0.0397120  0.0873366   0.455    0.649    
## seasonalmay   0.0896814  0.0873370   1.027    0.305    
## seasonaljun   0.1263174  0.0873375   1.446    0.149    
## seasonaljul   0.0382476  0.0873382   0.438    0.662    
## seasonalago   0.0697856  0.0873389   0.799    0.425    
## seasonalsept -0.0574999  0.0873398  -0.658    0.511    
## seasonaloct   0.1171753  0.0873408   1.342    0.180    
## seasonalnov  -0.0669730  0.0873419  -0.767    0.444    
## seasonaldic  -0.0589644  0.0873431  -0.675    0.500    
## trend        -0.0001654  0.0001009  -1.639    0.102    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.441 on 599 degrees of freedom
## Multiple R-squared:  0.02747,    Adjusted R-squared:  0.007988 
## F-statistic:  1.41 on 12 and 599 DF,  p-value: 0.1563
train$yhat <- predict(md1, newdata = train)
test$yhat <- predict(md1, newdata = test)
plot_lm(data = Earth2_df,
 train = train,
 test = test,
 title = "Predicting the Trend and Seasonal Components of the
Series")
mape_md1 <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_md1
## [1] 0.05375073 0.04350817
md2 <- lm(y ~ seasonal + trend + I(trend^2), data = train)
summary(md2)
## 
## Call:
## lm(formula = y ~ seasonal + trend + I(trend^2), data = train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.6391 -0.2895 -0.1362  0.1768  1.8339 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   6.035e+00  7.917e-02  76.231  < 2e-16 ***
## seasonalfeb  -1.550e-02  8.683e-02  -0.179  0.85836    
## seasonalmar   9.252e-02  8.683e-02   1.066  0.28707    
## seasonalabr   3.976e-02  8.683e-02   0.458  0.64723    
## seasonalmay   8.973e-02  8.683e-02   1.033  0.30184    
## seasonaljun   1.264e-01  8.683e-02   1.455  0.14610    
## seasonaljul   3.830e-02  8.683e-02   0.441  0.65930    
## seasonalago   6.984e-02  8.683e-02   0.804  0.42157    
## seasonalsept -5.746e-02  8.683e-02  -0.662  0.50843    
## seasonaloct   1.172e-01  8.684e-02   1.350  0.17760    
## seasonalnov  -6.696e-02  8.684e-02  -0.771  0.44098    
## seasonaldic  -5.896e-02  8.684e-02  -0.679  0.49739    
## trend        -1.266e-03  4.019e-04  -3.149  0.00172 ** 
## I(trend^2)    1.795e-06  6.349e-07   2.827  0.00486 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4385 on 598 degrees of freedom
## Multiple R-squared:  0.0403, Adjusted R-squared:  0.01943 
## F-statistic: 1.932 on 13 and 598 DF,  p-value: 0.02436
train$yhat <- predict(md2, newdata = train)
test$yhat <- predict(md2, newdata = test)
 plot_lm(data = Earth2_df,
 train = train,
 test = test,
 title = "Predicting the Trend (Polynomial) and Seasonal Components
of the Series")
mape_md2 <- c(mean(abs(train$y - train$yhat) / train$y),
 mean(abs(test$y - test$yhat) / test$y))
mape_md2
## [1] 0.05325876 0.05659700

La función TSLM

Earth_df_split <- ts_split(Earth_df, sample.out = h)
train.ts <- Earth_df_split$train
test.ts <- Earth_df_split$test
library(forecast)
md3 <- tslm(train.ts ~ season + trend + I(trend^2))

La función tslm del paquete forecast puede transformar un objeto ts en un modelo predictivo de regresión lineal, modifica y configura los componentes para obtener un modelo predictivo.

summary(md3)
## 
## Call:
## tslm(formula = train.ts ~ season + trend + I(trend^2))
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.6391 -0.2895 -0.1362  0.1768  1.8339 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  6.035e+00  7.917e-02  76.231  < 2e-16 ***
## season2     -1.550e-02  8.683e-02  -0.179  0.85836    
## season3      9.252e-02  8.683e-02   1.066  0.28707    
## season4      3.976e-02  8.683e-02   0.458  0.64723    
## season5      8.973e-02  8.683e-02   1.033  0.30184    
## season6      1.264e-01  8.683e-02   1.455  0.14610    
## season7      3.830e-02  8.683e-02   0.441  0.65930    
## season8      6.984e-02  8.683e-02   0.804  0.42157    
## season9     -5.746e-02  8.683e-02  -0.662  0.50843    
## season10     1.172e-01  8.684e-02   1.350  0.17760    
## season11    -6.696e-02  8.684e-02  -0.771  0.44098    
## season12    -5.896e-02  8.684e-02  -0.679  0.49739    
## trend       -1.266e-03  4.019e-04  -3.149  0.00172 ** 
## I(trend^2)   1.795e-06  6.349e-07   2.827  0.00486 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4385 on 598 degrees of freedom
## Multiple R-squared:  0.0403, Adjusted R-squared:  0.01943 
## F-statistic: 1.932 on 13 and 598 DF,  p-value: 0.02436

Modelando eventos aislados y eventos no estacionales

r <- which(Earth2_df$ds == as.Date("2014-01-01"))
Earth2_df$s_break <- ifelse(year(Earth2_df$ds) >= 2010, 1, 0)
Earth2_df$s_break[r] <- 1
md3 <- tslm(Earth_df ~ season + trend + I(trend^2) + s_break, data = Earth2_df)

Al modelar una serie de tiempo siempre se presentan datos inusuales o fuera de rango que pueden afectar las estimaciones de los coeficientes de la serie, por medio del proceso que se presenta a continuación podemos identificar los datos inusuales en los valores de la serie de tiempo de terremotos.

summary(md3)
## 
## Call:
## tslm(formula = Earth_df ~ season + trend + I(trend^2) + s_break, 
##     data = Earth2_df)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.6397 -0.2919 -0.1320  0.1736  1.8357 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  6.040e+00  8.040e-02  75.128  < 2e-16 ***
## season2     -1.143e-02  8.563e-02  -0.134  0.89383    
## season3      9.059e-02  8.563e-02   1.058  0.29052    
## season4      5.030e-02  8.563e-02   0.587  0.55714    
## season5      8.578e-02  8.563e-02   1.002  0.31688    
## season6      1.236e-01  8.563e-02   1.443  0.14957    
## season7      4.288e-02  8.564e-02   0.501  0.61678    
## season8      6.603e-02  8.564e-02   0.771  0.44096    
## season9     -5.505e-02  8.564e-02  -0.643  0.52062    
## season10     1.162e-01  8.564e-02   1.357  0.17541    
## season11    -5.683e-02  8.564e-02  -0.664  0.50723    
## season12    -6.061e-02  8.565e-02  -0.708  0.47940    
## trend       -1.373e-03  4.687e-04  -2.930  0.00352 ** 
## I(trend^2)   2.062e-06  8.338e-07   2.473  0.01365 *  
## s_break     -9.285e-02  8.792e-02  -1.056  0.29135    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4366 on 609 degrees of freedom
## Multiple R-squared:  0.03863,    Adjusted R-squared:  0.01653 
## F-statistic: 1.748 on 14 and 609 DF,  p-value: 0.04302

Previsión de una serie con componentes multiestacionales en terremotos

La serie UKgrid

library(UKgrid)
UKdaily <- extract_grid(type = "data.frame",
columns = "ND",
aggregate = "daily")
head(UKdaily)
##    TIMESTAMP      ND
## 1 2005-04-01 1920069
## 2 2005-04-02 1674699
## 3 2005-04-03 1631352
## 4 2005-04-04 1916693
## 5 2005-04-05 1952082
## 6 2005-04-06 1964584
ts_plot(UKdaily,

title = "The UK National Demand for Electricity",

Ytitle = "Magnitude",

Xtitle = "Year")

En la gráfica se puede observar que la mayor ocurrencia se encuentra en las primeras semanas de 1-10 y de 40-50. Sin embargo para el año 2019 entre las semanas 40-50 no existe ocurrencia.

ts_heatmap(UKdaily[which(year(UKdaily$TIMESTAMP) >= 2016),],
title = "UK the Daily National Grid Demand Heatmap")

Preprocesamiento e ingeniería de características de la serie UKdaily

library(dplyr)
UKdaily <- UKdaily %>%
mutate(wday = wday(TIMESTAMP, label = TRUE),
month = month(TIMESTAMP, label = TRUE),
lag365 = dplyr::lag(ND, 365)) %>%
filter(!is.na(lag365)) %>%
arrange(TIMESTAMP)
str(UKdaily)
## 'data.frame':    4939 obs. of  5 variables:
##  $ TIMESTAMP: Date, format: "2006-04-01" "2006-04-02" ...
##  $ ND       : int  1718405 1691341 1960325 2023886 2026204 2008422 1981175 1770440 1749715 2012865 ...
##  $ wday     : Ord.factor w/ 7 levels "dom\\."<"lun\\."<..: 7 1 2 3 4 5 6 7 1 2 ...
##  $ month    : Ord.factor w/ 12 levels "ene"<"feb"<"mar"<..: 4 4 4 4 4 4 4 4 4 4 ...
##  $ lag365   : int  1920069 1674699 1631352 1916693 1952082 1964584 1990895 2003982 1811436 1684720 ...
start_date <- min(UKdaily$TIMESTAMP)
start <- c(year(start_date), yday(start_date))
UK_ts <- ts(UKdaily$ND,
start = start,
frequency = 365)
library(TSstudio)
data(Earth2_df)
## Warning in data(Earth2_df): data set 'Earth2_df' not found
acf(UK_ts, lag.max = 365 * 4)

h <- 365
UKpartitions <- ts_split(UK_ts, sample.out = h)
train_ts <- UKpartitions$train
test_ts <- UKpartitions$test
train_df <- UKdaily[1:(nrow(UKdaily) - h), ]
test_df <- UKdaily[(nrow(UKdaily) - h + 1):nrow(UKdaily), ]

Capacitación y ensayo del modelo de prediccion.

md_tslm1 <- tslm(train_ts ~ season + trend)
fc_tslm1 <- forecast(md_tslm1, h = h)
test_forecast(actual = UK_ts,
 forecast.obj = fc_tslm1,
 test = test_ts)

En las gráficas se pueden observar tres modelos de previsión: Modelo de referencia, modelo multiestacional y modelo multiestacional con retraso. Los cuales capturan la tendencia de la serie, el dato de la estacionalidad, y cómo contribuye la estacionalidad en los cambios de la serie de tiempo.

accuracy(fc_tslm1, test_ts)
##                         ME     RMSE       MAE        MPE     MAPE      MASE
## Training set -9.030002e-12 121551.4 100439.64 -0.5721337 6.294111 0.8418677
## Test set     -1.740215e+04 123156.6  96785.27 -1.8735336 7.160573 0.8112374
##                   ACF1 Theil's U
## Training set 0.5277884        NA
## Test set     0.5106681  1.071899
md_tslm2 <- tslm(train_ts ~ season + trend + wday + month,
 data = train_df)
accuracy(fc_tslm2, test_ts)
##                         ME     RMSE      MAE        MPE     MAPE      MASE
## Training set -1.589161e-12 70032.14 51999.67 -0.1725754 3.158853 0.4358522
## Test set     -1.765395e+04 81683.91 65842.88 -1.3694262 4.703788 0.5518836
##                   ACF1 Theil's U
## Training set 0.7508301        NA
## Test set     0.6120506 0.6898049
fc_tslm2 <- forecast(md_tslm2, h = h,  newdata = test_df)
test_forecast(actual = UK_ts,
 forecast.obj = fc_tslm2,
 test = test_ts)
accuracy(fc_tslm2, test_ts)
##                         ME     RMSE      MAE        MPE     MAPE      MASE
## Training set -1.589161e-12 70032.14 51999.67 -0.1725754 3.158853 0.4358522
## Test set     -1.765395e+04 81683.91 65842.88 -1.3694262 4.703788 0.5518836
##                   ACF1 Theil's U
## Training set 0.7508301        NA
## Test set     0.6120506 0.6898049
md_tslm3 <- tslm(train_ts ~ season + trend + wday + month + lag365,
 data = train_df)
fc_tslm3 <- forecast(md_tslm3, h = h, newdata = test_df)
test_forecast(actual = UK_ts,
 forecast.obj = fc_tslm3,
 test = test_ts)
accuracy(fc_tslm3, test_ts)
##                         ME     RMSE      MAE        MPE     MAPE      MASE
## Training set -1.175109e-11 69904.92 52006.75 -0.1717563 3.163385 0.4359116
## Test set     -1.754061e+04 81783.55 65957.66 -1.3613252 4.722083 0.5528457
##                   ACF1 Theil's U
## Training set 0.7500146        NA
## Test set     0.6094666 0.6925767

Selección del modelo

summary(md_tslm3)$coefficients %>% tail(1)
##           Estimate Std. Error   t value     Pr(>|t|)
## lag365 -0.06038328 0.01545495 -3.907051 9.490321e-05
anova(md_tslm3)
## Analysis of Variance Table
## 
## Response: train_ts
##             Df     Sum Sq    Mean Sq    F value    Pr(>F)    
## season     364 1.4279e+14 3.9227e+11    73.5348 < 2.2e-16 ***
## trend        1 7.2634e+13 7.2634e+13 13615.7078 < 2.2e-16 ***
## wday         6 4.5009e+13 7.5016e+12  1406.2214 < 2.2e-16 ***
## month       11 1.3721e+11 1.2473e+10     2.3382  0.007266 ** 
## lag365       1 8.1432e+10 8.1432e+10    15.2650  9.49e-05 ***
## Residuals 4190 2.2352e+13 5.3345e+09                         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Como se vio durante el proceso el uso de varios modelos mejora la precisión de una predicción, de esta manera para escoger un modelo tendremos en cuenta si escogiendo un modelo que incluya una variable de retraso es de significancia para mejorar la predicción del modelo, en caso contrario será un recurso innecesario.

final_md <- tslm(UK_ts ~ season + trend + wday + month + lag365,
data = UKdaily)

## Análisis de los residuos

checkresiduals(final_md)

## 
##  Breusch-Godfrey test for serial correlation of order up to 730
## 
## data:  Residuals from Linear regression model
## LM test = 3301.1, df = 730, p-value < 2.2e-16

## Finalización de la previsión

UK_fc_df <- data.frame(date = seq.Date(from = max(UKdaily$TIMESTAMP) + days(1),
by = "day",
length.out = h))
UK_fc_df$wday <- factor(wday(UK_fc_df$date, label = TRUE), ordered = FALSE)
UK_fc_df$month <- factor(month(UK_fc_df$date, label = TRUE), ordered = FALSE)
UK_fc_df$lag365 <- tail(UKdaily$ND, h)
UKgrid_fc <- forecast(final_md, h = h, newdata = UK_fc_df)
plot_forecast(UKgrid_fc,
title = "The UK National Demand for Electricity Forecast",
Ytitle = "Magnitude",
 Xtitle = "Year")

Finalmente podemos utilizar y aplicar todas los modelos para realizar el proceso de predicción para 1 año del comportamiento futuro de la magnitud de los terremotos.

# CONCLUSIÓN En este proyecto aprendimos y dimos utilidad al modelo de regresión lineal, que tiene múltiples aplicaciones predictivas. Además nos resultó útil al realizar un análisis con nuestra base de datos enfocada en los terremotos, reconociendo que a pesar de que éste modelo no fue diseñado para datos de series de tiempo, es de gran importancia a la hora de transformar un problema predicción en un problema de regresión lineal.

El modelo de regresión lineal se destaca sobre los demás por tener en cuenta variables y factores externos. Además de series de tiempo con variedad de modelos estacionales.