#install.packages("TSstudio")
library(randomForest)
## randomForest 4.7-1.1
## Type rfNews() to see new features/changes/bug fixes.
install.packages ("h2o")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.3'
## (as 'lib' is unspecified)
library(h2o)
## 
## ----------------------------------------------------------------------
## 
## Your next step is to start H2O:
##     > h2o.init()
## 
## For H2O package documentation, ask for help:
##     > ??h2o
## 
## After starting H2O, you can use the Web UI at http://localhost:54321
## For more information visit https://docs.h2o.ai
## 
## ----------------------------------------------------------------------
## 
## Attaching package: 'h2o'
## The following objects are masked from 'package:stats':
## 
##     cor, sd, var
## The following objects are masked from 'package:base':
## 
##     &&, %*%, %in%, ||, apply, as.factor, as.numeric, colnames,
##     colnames<-, ifelse, is.character, is.factor, is.numeric, log,
##     log10, log1p, log2, round, signif, trunc
library(TSstudio)
library(plotly)
## Loading required package: ggplot2
## 
## Attaching package: 'ggplot2'
## The following object is masked from 'package:randomForest':
## 
##     margin
## 
## 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
library(lubridate) 
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:h2o':
## 
##     day, hour, month, week, year
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:randomForest':
## 
##     combine
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
require(randomForest)

Pronóstico con Máquina

Modelos de aprendizaje

Este capítulo requiere algunos conocimientos básicos del proceso de entrenamiento y ajuste de los modelos de aprendizaje automático. En este capítulo, cubriremos los siguientes temas:

-Introducción al paquete h20 y su funcionalidad -Ingeniería de características de datos de series de tiempo -Predicción con el modelo Random Forest -Pronóstico con el modelo de aprendizaje automático de aumento de gradiente -Pronóstico con el modelo de aprendizaje automático automatizado

Requerimiento técnico

En este capítulo se utilizarán los siguientes paquetes:

-h2o: Versión 3.22.1.1 y superior y Java versión 7 y superior -TSstudio: Versión 0.1.4 y superior -plotly: Versión 4.8 y superior -Lubridate: Versión 1.7.4 y superior

¿Por qué y cuándo debemos usar el aprendizaje automático?

En los últimos años, el uso de modelos de aprendizaje automático (ML) se ha vuelto popular y accesible debido a la mejora significativa en el poder de cómputo estándar.

Antes de comenzar a profundizar en los detalles, es importante advertir el uso de modelos ML en el contexto de la previsión de series temporales:

-Costo: el uso de modelos ML suele ser más costoso que los modelos de regresión típicos, tanto en potencia informática como en tiempo. -Precisión: el rendimiento del modelo ML depende en gran medida de la calidad (es decir, una fuerte relación de causalidad con la variable dependiente) de los predictores. Es probable que los modelos ML tengan un rendimiento superior al de los métodos tradicionales, como la regresión lineal, cuando se dispone de predictores fuertes. -Ajuste: el procesamiento de modelos ML típicos es más complejo que con los modelos de regresión comunes, ya que esos modelos tienen más parámetros de ajuste y, por lo tanto, requieren cierta experiencia. -Black-box: la mayoría de los modelos de ML se consideran cajas negras, ya que es difícil interrumpir su salida. -Incertidumbre: Generalmente, no existe un método directo para cuantificar la incertidumbre de pronóstico con intervalos de confianza como lo hace el modelo tradicional de series de tiempo.

En este capítulo, nos centraremos en el pronóstico de las ventas mensuales de vehículos en EE. UU. utilizando los siguientes modelos:

-Bosque aleatorio -Máquina de aumento de gradiente -Modelo automático de aprendizaje automático

¿Por qué h20?

En este capítulo, usaremos el paquete h20 para construir y entrenar modelos de pronóstico con el uso de modelos ML. H20 es una biblioteca de código abierto, distribuida y basada en Java para aplicaciones de aprendizaje automático. Tiene API para R (el paquete h20) y Python, e incluye aplicaciones para modelos de aprendizaje supervisado y no supervisado.

Los algoritmos del paquete h20 proporcionan varios métodos para que podamos entrenar y ajustar los modelos de aprendizaje automático, como el método de validación cruzada y la función de búsqueda de cuadrícula integrada.

Pronóstico de las ventas mensuales de vehículos en los EE. UU.: un estudio de caso

En este capítulo, nos centraremos en pronosticar las ventas mensuales totales de vehículos en los EE. UU. en los próximos 12 meses con métodos ML. Las ventas mensuales totales de vehículos en la serie de EE. UU. están disponibles en el paquete TSstudio:

library(TSstudio)

data(USVSales)

Análisis exploratorio de la serie USVSales

En este apartado nos centraremos en explorar y conocer las principales características de la serie. Estos conocimientos se utilizarán para crear nuevas funciones como entradas para el modelo ML. El análisis exploratorio de la serie USVSales se centrará en los siguientes temas: Ver la estructura de la serie temporal (frecuencia, inicio y final de la serie, etc.)

-Explore los componentes de la serie (componentes estacionales, de ciclo, de tendencia y aleatorios) -Análisis de estacionalidad -Análisis de correlación

La estructura de la serie

Comencemos con ts_info y revisemos la estructura de la serie USVSales:

ts_info(USVSales)
##  The USVSales series is a ts object with 1 variable and 528 observations
##  Frequency: 12 
##  Start time: 1976 1 
##  End time: 2019 12

La serie UsvSales es un objeto ts mensual que representa las ventas totales de vehículos en los EE. UU. entre 1976 y 2018 en miles de unidades. Grafiquemos la serie y revisemos su estructura con la función ts_plot:

ts_plot(USVSales,
        title = "US Total Monthly Vehicle Sales",
        Ytitle = "Thousands of Units",
        Xtitle = "Year")

Figura 1. Como puede ver en el gráfico anterior, la serie tiene patrones de ciclo, lo cual es común para un indicador de macroeconomía. En este caso, es un indicador macro de la economía estadounidense.

Los componentes de la serie

Podemos obtener una vista más profunda de los componentes de la serie al descomponer la serie en sus componentes y trazarlos con la función t s_decompose:

ts_decompose(USVSales)

Figura 2. Además del componente ciclo-tendencia, podemos observar que el gráfico tiene un fuerte patrón estacional, que exploraremos a continuación.

Análisis estacional

Para ver más de cerca el componente estacional de la serie, restaremos de la serie, descompondremos la tendencia que analizamos anteriormente y usaremos la función t s_seasonal para trazar el diagrama de caja del componente estacional de la serie sin tendencia:

USVSales_detrend <- USVSales - decompose(USVSales)$trend

ts_seasonal(USVSales_detrend, type = "box")
## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

## Warning: Ignoring 1 observations

Figura 3. Podemos ver en el gráfico estacional anterior que, típicamente, el pico del año ocurrió durante los meses de marzo, mayo y junio. Además, puede ver que las ventas decaen a partir de los meses de verano y vuelven a alcanzar su punto máximo en diciembre durante las temporadas navideñas. Por otro lado, el mes de enero suele ser el mes más bajo del año en términos de ventas.

Análisis de correlación

Como vimos en el Capítulo 7, Análisis de correlación, la serie USVSales tiene una alta correlación con su primer retraso estacional. Podemos revisar esta evaluación con el uso de la función ts_acf del paquete TSstudio para revisar la autocorrelación de la serie:

library(TSstudio)
ts_cor(USVSales)

Figura 4.

Podemos ampliar la relación de la serie con los tres últimos desfases estacionales utilizando la función ts_lags:

ts_lags(USVSales, lags = c(12, 24, 36))

Figura 5. La relación de la serie con el primer y segundo rezagos estacionales tiene una fuerte relación lineal, como se muestra en el diagrama de rezagos anterior.

Análisis exploratorio: hallazgos clave

Podemos concluir nuestro breve análisis exploratorio de la serie USVSales con las siguientes observaciones:

-La serie USVSales es una serie mensual con una clara estacionalidad mensual -La tendencia de la serie tiene una forma cíclica, por lo que la serie tiene un componente de ciclo incrustado en la tendencia. -El ciclo más reciente de la serie comienza justo después del final de la crisis económica de 2008, entre 2009 y 2010 -Parece que el ciclo actual alcanzó su punto máximo a medida que la tendencia comienza a aplanarse -La serie tiene una fuerte correlación con su primer desfase estacional

Usaremos la función ts_to_prophet del paquete TSstudio para transformar la serie de un objeto ts en un data. marco y la función de ventana para crear un subconjunto de las observaciones de la serie desde enero de 2010:

library(dplyr)

df <- ts_to_prophet(window(USVSales, start = c(2010,1))) #%>% 

names(df) <- c("date", "y")

head(df)
##         date        y
## 1 2010-01-01  712.469
## 2 2010-02-01  793.362
## 3 2010-03-01 1083.953
## 4 2010-04-01  997.334
## 5 2010-05-01 1117.570
## 6 2010-06-01 1000.455

Antes de avanzar y comenzar con la etapa de ingeniería de características, tracemos y revisemos la serie de subconjuntos de USVSales con la función ts_plot:

ts_plot(df,
        title = "US Total Monthly Vehicle Sales (Subset)",
        Ytitle = "Thousands of Units",
        Xtitle = "Year")

Ingeniería de características

La ingeniería de características juega un papel fundamental cuando se modela con algoritmos ML. Nuestro próximo paso, basado en las observaciones anteriores, es crear nuevas características que puedan usarse como entrada informativa para el modelo.

Usaremos los paquetes dplyr y lubridate para crear esas funciones, como podemos ver en el siguiente código:

library(dplyr)
library(lubridate)

df <- df %>% mutate(month = factor(lubridate::month(date, label = TRUE), ordered = FALSE),
                    lag12 = lag(y, n = 12)) %>%
  filter(!is.na(lag12))

Luego agregaremos el componente de tendencia y su segundo polinomio (tendencia al cuadrado)

df$trend <- 1:nrow(df)
df$trend_sqr <- df$trend ^ 2

Veamos la estructura del objeto df después de agregar las nuevas funciones:

str(df)
## 'data.frame':    108 obs. of  6 variables:
##  $ date     : Date, format: "2011-01-01" "2011-02-01" ...
##  $ y        : num  836 1007 1277 1174 1081 ...
##  $ month    : Factor w/ 12 levels "Jan","Feb","Mar",..: 1 2 3 4 5 6 7 8 9 10 ...
##  $ lag12    : num  712 793 1084 997 1118 ...
##  $ trend    : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ trend_sqr: num  1 4 9 16 25 36 49 64 81 100 ...

Entrenamiento, pruebas y evaluación de modelos.

Para comparar los diferentes modelos que probaremos en este capítulo, usaremos las mismas entradas que usamos anteriormente. Esto incluye ejecutar las mismas particiones de entrenamiento y prueba a lo largo de este capítulo.

Dado que nuestro horizonte de pronóstico es de 12 meses, dejaremos los últimos 12 meses de la serie como particiones de prueba y utilizaremos el resto de la serie como partición de entrenamiento:

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

Además de las particiones de entrenamiento y prueba, necesitamos crear las entradas para el pronóstico mismo. Crearemos un data. marco con las fechas de los siguientes 12 meses y construye el resto de las características:

forecast_df <- data.frame(date = seq.Date(from = max(df$date) + lubridate::month(1),
                                          length.out = h, by = "month"),
                          trend = seq(from = max(df$trend) + 1, length.out = h, by = 1))
forecast_df$trend_sqr <- forecast_df$trend ^ 2

# to avoid conflict with the h2o `month` function use the "lubridate::month" to explicly call the month from the lubridate function 
forecast_df$month <- factor(lubridate::month(forecast_df$date, label = TRUE), ordered= FALSE) 
forecast_df$lag12 <- tail(df$y, 12)

Modelo de referencia

Presentado en el Capítulo 8, Estrategias de pronóstico, el rendimiento de un modelo de pronóstico debe medirse por la tasa de error, principalmente en la partición de prueba, pero también en la partición de entrenamiento.

En este capítulo, dado que estamos usando una familia de modelos de regresión de ML, tiene más sentido usar un modelo de regresión como punto de referencia para los modelos de ML. Usando las particiones de entrenamiento y prueba que creamos anteriormente, entrenemos el modelo de regresión lineal y evaluemos su rendimiento con las particiones de prueba:

lr <- lm(y ~ month + lag12 + trend + trend_sqr, data = train_df)

Usaremos la función de resumen para revisar los detalles del modelo:

summary(lr)
## 
## Call:
## lm(formula = y ~ month + lag12 + trend + trend_sqr, data = train_df)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -146.625  -38.997    0.111   39.196  112.577 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 542.93505   72.59490   7.479 7.91e-11 ***
## monthFeb    112.73160   34.16141   3.300 0.001439 ** 
## monthMar    299.20932   54.24042   5.516 4.03e-07 ***
## monthApr    182.52406   42.53129   4.292 4.88e-05 ***
## monthMay    268.75603   51.28464   5.240 1.24e-06 ***
## monthJun    224.66897   44.26374   5.076 2.41e-06 ***
## monthJul    177.88564   42.21898   4.213 6.49e-05 ***
## monthAug    241.63260   47.00693   5.140 1.86e-06 ***
## monthSep    152.99058   37.04199   4.130 8.76e-05 ***
## monthOct    125.16484   35.04896   3.571 0.000601 ***
## monthNov    127.97288   34.18772   3.743 0.000338 ***
## monthDec    278.67994   51.09552   5.454 5.21e-07 ***
## lag12         0.33906    0.10738   3.158 0.002236 ** 
## trend         7.73667    1.72415   4.487 2.36e-05 ***
## trend_sqr    -0.05587    0.01221  -4.576 1.69e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 59.6 on 81 degrees of freedom
## Multiple R-squared:  0.9198, Adjusted R-squared:  0.9059 
## F-statistic: 66.36 on 14 and 81 DF,  p-value: < 2.2e-16

A continuación, predeciremos los valores correspondientes de la serie en la partición de prueba con la función de predicción usando test _df como entrada:

test_df$yhat <- predict(lr, newdata = test_df)

mape_lr <- mean(abs(test_df$y - test_df$yhat) / test_df$y)
mape_lr
## [1] 0.03594578

Inicio de un grupo de h2o

El paquete h2o se basa en el uso de computación distribuida y paralela para acelerar el tiempo de computación y poder escalar para big data. ¡Todo esto se hace en memoria (basado en la memoria RAM interna de la computadora) o en paralelo! clústeres de procesamiento distribuido (por ejemplo, AWS, Google Cloud, etc.). Por lo tanto, cargaremos el paquete y luego configuraremos el clúster en memoria con la función h20.init:

library(h2o)

h2o.init(max_mem_size = "16G")
##  Connection successful!
## 
## R is connected to the H2O cluster: 
##     H2O cluster uptime:         2 minutes 57 seconds 
##     H2O cluster timezone:       UTC 
##     H2O data parsing timezone:  UTC 
##     H2O cluster version:        3.42.0.2 
##     H2O cluster version age:    3 months and 6 days 
##     H2O cluster name:           H2O_started_from_R_r2182125_zft554 
##     H2O cluster total nodes:    1 
##     H2O cluster total memory:   15.41 GB 
##     H2O cluster total cores:    1 
##     H2O cluster allowed cores:  1 
##     H2O cluster healthy:        TRUE 
##     H2O Connection ip:          localhost 
##     H2O Connection port:        54321 
##     H2O Connection proxy:       NA 
##     H2O Internal Security:      FALSE 
##     R Version:                  R version 4.3.1 (2023-06-16)

Todos los datos que el paquete h20 utiliza a lo largo del proceso de entrenamiento y prueba de los modelos deben cargarse en el propio clúster. La función as .h20 nos permite transformar cualquier dato. encuadre el objeto en un clúster h20:

train_h <- as.h2o(train_df)
## Warning in use.package("data.table"): data.table cannot be used without R
## package bit64 version 0.9.7 or higher.  Please upgrade to take advangage of
## data.table speedups.
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |======================================================================| 100%
test_h <- as.h2o(test_df)
## Warning in use.package("data.table"): data.table cannot be used without R
## package bit64 version 0.9.7 or higher.  Please upgrade to take advangage of
## data.table speedups.
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |======================================================================| 100%
forecast_h <- as.h2o(forecast_df)
## Warning in use.package("data.table"): data.table cannot be used without R
## package bit64 version 0.9.7 or higher.  Please upgrade to take advangage of
## data.table speedups.
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |======================================================================| 100%

Para nuestra comodidad, etiquetaremos los nombres de las variables dependientes e independientes:

x <- c("month", "lag12", "trend", "trend_sqr")
y <- "y"

Entrenamiento de un modelo de ML

El paquete h20 proporciona un conjunto de herramientas para entrenar y probar modelos ML. Los enfoques de entrenamiento de modelos más comunes son los siguientes:

-Entrenamiento/pruebas -Entrenamiento/prueba/validación -Validación cruzada

A lo largo de este capítulo, utilizaremos el enfoque de validación cruzada (CV) para entrenar estos modelos.

Predicción con el modelo Random Forest

Ahora que preparamos los datos, creamos nuevas funciones y lanzamos un clúster h20, estamos listos para construir nuestro primer modelo de pronóstico con el algoritmo Random Forest (RF).

Comenzaremos con un modelo de RF simplista utilizando 500 árboles y 5 carpetas de entrenamiento CV. Además, agregaremos un criterio de parada para evitar que el modelo se ajuste al modelo mientras no haya un cambio significativo en el rendimiento del modelo. En este caso, estableceremos la métrica de parada como RMSE, la tolerancia de parada como 0,0001 y los redondeos de parada en 10:

rf_md <- h2o.randomForest(training_frame = train_h,
                          nfolds = 5,
                          x = x,
                          y = y,
                          ntrees = 500,
                          stopping_rounds = 10,
                          stopping_metric = "RMSE",
                          score_each_iteration = TRUE,
                          stopping_tolerance = 0.0001,
                          seed = 1234)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |======================================================================| 100%

Podemos ver la contribución de las entradas del modelo con la función n20.varimp_plot. Esta función devuelve un gráfico con la clasificación de la contribución de las variables de entrada al rendimiento del modelo utilizando una escala entre 0 y 1, como se muestra en el siguiente código:

h2o.varimp_plot(rf_md)

gráfico de importancia de la variable anterior, la variable de retraso, 1ag12, es la más importante para el modelo. Esto no debería ser una sorpresa ya que vimos la fuerte relación entre la serie y su retraso estacional en el análisis de correlación. Inmediatamente después de esto, las variables más importantes son trend_sgr, month y trend.

La salida del modelo contiene (además del propio modelo) información sobre el rendimiento y los parámetros del modelo. Repasemos el resumen del modelo:

rf_md@model$model_summary
## Model Summary: 
##   number_of_trees number_of_internal_trees model_size_in_bytes min_depth
## 1              41                       41               31588         8
##   max_depth mean_depth min_leaves max_leaves mean_leaves
## 1        12   10.04878         45         66    56.70732

La siguiente gráfica demuestra el proceso de aprendizaje del modelo en función del número de árboles:

library(plotly)
library(ggplot2)

tree_score <- rf_md@model$scoring_history$training_rmse
plot_ly(x = seq_along(tree_score), y = tree_score,
        type = "scatter", mode = "line") %>%
  layout(title = "Random Forest Model - Trained Score History",
         yaxis = list(title = "RMSE"),
         xaxis = list(title = "Num. of Trees"))
## Warning: Ignoring 1 observations

Figura 8.

Por último, pero no menos importante, midamos el rendimiento del modelo en la partición de prueba. Usaremos la función h20.predict para predecir los valores correspondientes de la serie en la partición de prueba:

test_h$pred_rf <- h2o.predict(rf_md, test_h)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |======================================================================| 100%

A continuación, transferiremos el marco de datos h20 a un data. objeto marco con el as .data. función de cuadro:

test_1 <- as.data.frame(test_h)

Ahora, podemos calcular la puntuación MAPE del modelo RF en la partición de prueba:

mape_rf <- mean(abs(test_1$y - test_1$pred_rf) / test_1$y)
mape_rf
## [1] 0.04647164

Cualquiera de los enfoques de entrenamiento del paquete h20 (como CV, entrenamiento con validación) se puede aplicar con la función h20.grid.

Comenzaremos configurando los parámetros de búsqueda:

search_criteria_rf <- list(
  strategy = "RandomDiscrete",
  stopping_metric = "rmse",
  stopping_tolerance = 0.0001,
  stopping_rounds = 10,
  max_runtime_secs = 60 * 20
)

hyper_params_rf <- list(mtries = c(2, 3, 4),
                        sample_rate = c(0.632, 0.8, 0.95),
                        col_sample_rate_per_tree = c(0.5, 0.9, 1.0),
                        max_depth = c(seq(1, 30, 3)),
                        min_rows = c(1, 2, 5, 10))

Tendría sentido usar el método cartesiano cuando el número de combinaciones de búsqueda es bastante pequeño o cuando no está limitado en el tiempo de búsqueda. Por otro lado, para una gran cantidad de combinaciones de búsqueda, o cuando tenemos limitaciones de tiempo, se recomienda utilizar la búsqueda aleatoria. Por razones de eficiencia, estableceremos una búsqueda aleatoria y restringiremos el tiempo de búsqueda a 20 minutos con max_runtime_sec. Usaremos la misma métrica de parada que usamos anteriormente:

search_criteria_rf <- list(strategy = "RandomDiscrete",
                           stopping_metric = "rmse",
                           stopping_tolerance = 0.0001,
                           stopping_rounds = 10,
                           max_runtime_secs = 60 * 20)

hyper_params_rf <- list(mtries = c(2, 3, 4),
                        sample_rate = c(0.632, 0.8, 0.95),
                        col_sample_rate_per_tree = c(0.5, 0.9, 1.0),
                        max_depth = c(seq(1, 30, 3)),
                        min_rows = c(1, 2, 5, 10))

search_criteria_rf <- list(strategy = "RandomDiscrete",
                           stopping_metric = "rmse",
                           stopping_tolerance = 0.0001,
                           stopping_rounds = 10,
                           max_runtime_secs = 60 * 20)

#rf2 <- h2o.grid(algorithm = "randomForest",
                #search_criteria = search_criteria_rf,
                #hyper_params = hyper_params_rf,
                #x = x,
                #y = y,
                #training_frame = train_h,
                #ntrees = 5000,
                #nfolds = 5,
                #grid_id = "rf_grid",
                #seed = 1234)

Ahora extraeremos los resultados de la cuadrícula, ordenaremos los modelos por su puntaje RMSE y extraeremos el modelo principal:

rf2_grid_search <- h2o.getGrid(grid_id = "rf_grid",                                sort_by = "rmse",                                decreasing = FALSE)  rf_grid_model <- h2o.getModel(rf2_grid_search@model_ids[[1]])   test_h$rf_grid  <- h2o.predict(rf_grid_model, test_h)
##    |                                                                               |                                                                      |   0%   |                                                                               |======================================================================| 100%
mape_rf2 <- mean(abs(test_1$y - test_1$rf_grid) / test_1$y)
mape_rf2
## [1] NaN

Probemos el modelo en la partición de prueba y evaluemos su rendimiento:

test_h$rf_grid  <- h2o.predict(rf_grid_model, test_h)
##    |                                                                               |                                                                      |   0%   |                                                                               |======================================================================| 100%
mape_rf2 <- mean(abs(test_1$y - test_1$rf_grid) / test_1$y)
mape_rf2
## [1] NaN

El paso de optimización adicional contribuyó al aumento de la precisión del modelo, con una puntuación MAPE de 3,33 % en comparación con 3,7 % y 4 % para el primer modelo de RF que entrenamos y el modelo de regresión lineal, respectivamente. El siguiente gráfico proporciona una vista adicional del rendimiento del modelo:

plot_ly(data = test_1) %>%
  add_lines(x = ~ date, y = ~y, name = "Actual") %>%
  add_lines(x = ~ date, y = ~ yhat, name = "Linear Regression", line = list(dash = "dot")) %>%
  add_lines(x = ~ date, y = ~ pred_rf, name = "Random Forest", line = list(dash = "dash")) %>%
  add_lines(x = ~ date, y = ~ "rf_grid", name = "Random Forest (grid)", line = list(dash = "dash")) %>%
  layout(title = "Total Vehicle Sales - Actual vs. Prediction (Random Forest)",
         yaxis = list(title = "Thousands of Units"),
         xaxis = list(title = "Month"))
## Warning: Can't display both discrete & non-discrete data on same axis

Figura 9.

Predicción con el modelo GBM

El algoritmo GBM es otro modelo basado en conjuntos y árboles. Utiliza el enfoque de impulso para entrenar diferentes subconjuntos de datos y repite el entrenamiento de subconjuntos que tenía el modelo con una alta tasa de error.

El siguiente ejemplo demuestra el uso de la función h20.gbm para entrenar el modelo GBM con los mismos datos de entrada que usamos anteriormente:

gbm_md <- h2o.gbm(
  training_frame = train_h,
  nfolds = 5,
  x = x,
  y = y,
  max_depth = 20,
  distribution = "gaussian",
  ntrees = 500,
  learn_rate = 0.1,
  score_each_iteration = TRUE
)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |=======                                                               |   9%
  |                                                                            
  |====================                                                  |  29%
  |                                                                            
  |==================================                                    |  48%
  |                                                                            
  |================================================                      |  69%
  |                                                                            
  |=================================================================     |  93%
  |                                                                            
  |======================================================================| 100%

Similar al modelo RF, podemos revisar el rango de importancia de las variables del modelo con la función h20.varimp_plot:

h2o.varimp_plot(gbm_md)

test_h$pred_gbm  <- h2o.predict(gbm_md, test_h)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |======================================================================| 100%
test_1 <- as.data.frame(test_h)

mape_gbm <- mean(abs(test_1$y - test_1$pred_gbm) / test_1$y)
mape_gbm
## [1] 0.03857898

El modelo GBM obtuvo el MAPE más bajo entre los modelos que probamos hasta ahora con una tasa de error del 2,7 %, en comparación con el 3,3 % y el 4 % con el modelo RF (con búsqueda en cuadrícula) y el modelo de regresión lineal, respectivamente. Sería un gran ejercicio aplicar una búsqueda en cuadrícula en el modelo GBM y probar si se pueden lograr mejoras adicionales.

Visualicemos los resultados y comparemos la predicción con la predicción real y de referencia:

plot_ly(data = test_1) %>% add_lines(x = ~ date, y = ~y, name = “Actual”) %>% add_lines(x = ~ date, y = ~ yhat, name = “Linear Regression”, line = list(dash = “dot”)) %>% add_lines(x = ~ date, y = ~ pred_gbm, name = “Gradient Boosting Machine”, line = list(dash = “dash”)) %>% layout(title = “Total Vehicle Sales - Actual vs. Prediction (Gradient Boosting Machine)”, yaxis = list(title = “Thousands of Units”), xaxis = list(title = “Month”))

Pronóstico con el modelo de AutoML

Hasta ahora, en este capítulo, hemos analizado dos enfoques de modelado: el primero utiliza la configuración predeterminada del algoritmo con los modelos RF y GBM, y el segundo aplica una búsqueda de cuadrícula con el modelo RF.

De manera similar, la función h20.grid puede aplicar cualquiera de los enfoques de entrenamiento (CV, entrenamiento con validación, etc.) durante el proceso de entrenamiento de los modelos. Usemos la misma entrada que antes y entrenemos el modelo de pronóstico:

autoML1 <- h2o.automl(training_frame = train_h,                       x = x,                       y = y,                       nfolds = 5,                       max_runtime_secs = 60*20,                       seed = 1234)
##    |                                                                               |                                                                      |   0%   |                                                                               |======                                                                |   8% ## 22:10:06.242: AutoML: XGBoost is not available; skipping it. ## 22:10:06.371: _min_rows param, The dataset size is too small to split for min_rows=100.0: must have at least 200.0 (weighted) rows, but have only 96.0.   |                                                                               |===========                                                           |  16%   |                                                                               |==================                                                    |  26%   |                                                                               |===================                                                   |  27%   |                                                                               |===================                                                   |  28%   |                                                                               |====================                                                  |  28%   |                                                                               |====================                                                  |  29%   |                                                                               |============================                                          |  39%   |                                                                               |============================                                          |  40%   |                                                                               |============================                                          |  41%   |                                                                               |=============================                                         |  41%   |                                                                               |=============================                                         |  42%   |                                                                               |==============================                                        |  42%   |                                                                               |==============================                                        |  43%   |                                                                               |==============================                                        |  44%   |                                                                               |===============================                                       |  44%   |                                                                               |===============================                                       |  45%   |                                                                               |================================                                      |  45%   |                                                                               |================================                                      |  46%   |                                                                               |=================================                                     |  46%   |                                                                               |=================================                                     |  47%   |                                                                               |=================================                                     |  48%   |                                                                               |==================================                                    |  48%   |                                                                               |==================================                                    |  49%   |                                                                               |===================================                                   |  49%   |                                                                               |===================================                                   |  50%   |                                                                               |===================================                                   |  51%   |                                                                               |====================================                                  |  51%   |                                                                               |====================================                                  |  52%   |                                                                               |=====================================                                 |  52%   |                                                                               |=====================================                                 |  53%   |                                                                               |======================================                                |  54%   |                                                                               |======================================                                |  55%   |                                                                               |=======================================                               |  55%   |                                                                               |=======================================                               |  56%   |                                                                               |========================================                              |  57%   |                                                                               |========================================                              |  58%   |                                                                               |=========================================                             |  58%   |                                                                               |=========================================                             |  59%   |                                                                               |==========================================                            |  59%   |                                                                               |==========================================                            |  60%   |                                                                               |==========================================                            |  61%   |                                                                               |===========================================                           |  61%   |                                                                               |===========================================                           |  62%   |                                                                               |============================================                          |  62%   |                                                                               |============================================                          |  63%   |                                                                               |=============================================                         |  64%   |                                                                               |=============================================                         |  65%   |                                                                               |==============================================                        |  65%   |                                                                               |==============================================                        |  66%   |                                                                               |===============================================                       |  67%   |                                                                               |===============================================                       |  68%   |                                                                               |================================================                      |  68%   |                                                                               |================================================                      |  69%   |                                                                               |=================================================                     |  69%   |                                                                               |=================================================                     |  70%   |                                                                               |=================================================                     |  71%   |                                                                               |==================================================                    |  71%   |                                                                               |==================================================                    |  72%   |                                                                               |===================================================                   |  72%   |                                                                               |===================================================                   |  73%   |                                                                               |====================================================                  |  74%   |                                                                               |====================================================                  |  75%   |                                                                               |=====================================================                 |  75%   |                                                                               |=====================================================                 |  76%   |                                                                               |======================================================                |  77%   |                                                                               |======================================================                |  78%   |                                                                               |=======================================================               |  78%   |                                                                               |=======================================================               |  79%   |                                                                               |========================================================              |  79%   |                                                                               |========================================================              |  80%   |                                                                               |=========================================================             |  81%   |                                                                               |=========================================================             |  82%   |                                                                               |==========================================================            |  82%   |                                                                               |==========================================================            |  83%   |                                                                               |==========================================================            |  84%   |                                                                               |===========================================================           |  84%   |                                                                               |===========================================================           |  85%   |                                                                               |============================================================          |  85%   |                                                                               |============================================================          |  86%   |                                                                               |=============================================================         |  87%   |                                                                               |=============================================================         |  88%   |                                                                               |==============================================================        |  88%   |                                                                               |==============================================================        |  89%   |                                                                               |===============================================================       |  89%   |                                                                               |===============================================================       |  90%   |                                                                               |===============================================================       |  91%   |                                                                               |================================================================      |  91%   |                                                                               |================================================================      |  92%   |                                                                               |=================================================================     |  92%   |                                                                               |=================================================================     |  93%   |                                                                               |==================================================================    |  94%   |                                                                               |==================================================================    |  95%   |                                                                               |===================================================================   |  95%   |                                                                               |===================================================================   |  96%   |                                                                               |====================================================================  |  97%   |                                                                               |====================================================================  |  98%   |                                                                               |===================================================================== |  98%   |                                                                               |===================================================================== |  99%   |                                                                               |======================================================================| 100%

En el ejemplo anterior, el tiempo de ejecución de la función se estableció en 20 minutos. La función devuelve una lista con la clasificación de todos los modelos probados:

## model_id rmse mse ## 1 StackedEnsemble_BestOfFamily_5_AutoML_3_20230502_221006 56.73875 3219.286 ## 2 StackedEnsemble_AllModels_6_AutoML_3_20230502_221006 57.69617 3328.848 ## 3 StackedEnsemble_BestOfFamily_3_AutoML_3_20230502_221006 58.64979 3439.798 ## 4 DeepLearning_grid_1_AutoML_3_20230502_221006_model_4 59.90874 3589.057 ## 5 DeepLearning_grid_1_AutoML_3_20230502_221006_model_5 60.05911 3607.097 ## 6 DeepLearning_grid_1_AutoML_3_20230502_221006_model_15 60.06403 3607.688 ## mae rmsle mean_residual_deviance ## 1 45.59482 0.04325613 3219.286 ## 2 46.08902 0.04440253 3328.848 ## 3 45.81140 0.04479125 3439.798 ## 4 46.72747 0.04613536 3589.057 ## 5 49.66899 0.04539493 3607.097 ## 6 49.14844 0.04544088 3607.688 ## ## [218 rows x 6 columns]

test_h$pred_autoML  <- h2o.predict(autoML1@leader, test_h)
##    |                                                                               |                                                                      |   0%   |                                                                               |======================================================================| 100%
test_1 <- as.data.frame(test_h)  mape_autoML <- mean(abs(test_1$y - test_1$pred_autoML) / test_1$y) mape_autoML
## [1] 0.04177911

El modelo líder de la salida de h20.automl logró una puntuación MAPE de 3,48 %. Aunque los modelos anteriores lograron una puntuación más alta, todavía proporciona un impulso significativo con respecto al modelo de referencia. Visualicemos la predicción del modelo en las particiones de prueba con respecto a la predicción real y de referencia:

plot_ly(data = test_1) %>% add_lines(x = ~ date, y = ~y, name = “Actual”) %>% add_lines(x = ~ date, y = ~ yhat, name = “Linear Regression”, line = list(dash = “dot”)) %>% add_lines(x = ~ date, y = ~ pred_autoML, name = “autoML”, line = list(dash = “dash”)) %>% layout(title = “Total Vehicle Sales - Actual vs. Prediction (Auto ML Model)”, yaxis = list(title = “Thousands of Units”), xaxis = list(title = “Month”))

Figura . La principal ventaja de la función h20.automl es que puede escalar mientras tiene varias series para pronosticar con una intervención mínima por parte del usuario. Esto, por supuesto, viene con potencia de cómputo adicional y costo de tiempo.

Selección del modelo final

Ahora que hemos terminado el proceso de entrenamiento y prueba de los modelos, es hora de finalizar el proceso y elegir el modelo para pronosticar con la serie. Entrenamos a los siguientes modelos:

-Modelo base -RF -GBM -AutoML

Antes de trazar los resultados, usemos estos tres modelos para pronosticar los próximos 12 meses usando los datos. pronóstico marco que creamos en las secciones Pronóstico con el modelo Random Forest y Pronóstico con el modelo GBM:

forecast_h$pred_gbm  <- h2o.predict(gbm_md, forecast_h)
##    |                                                                               |                                                                      |   0%   |                                                                               |======================================================================| 100%
forecast_h$pred_gbm  <- h2o.predict(gbm_md, forecast_h)
##    |                                                                               |                                                                      |   0%   |                                                                               |======================================================================| 100%
forecast_h$pred_automl  <- h2o.predict(autoML1@leader, forecast_h)
##    |                                                                               |                                                                      |   0%   |                                                                               |======================================================================| 100%
final_forecast <- as.data.frame(forecast_h)  plot_ly(x = df$date, y = df$y,         type = "scatter",         mode = "line",          name = "Actual") %>%    add_lines(x = final_forecast$date, y = final_forecast$pred_rf, name = "Random Forest") %>%   add_lines(x = final_forecast$date, y = final_forecast$pred_gbm, name = "GBM") %>%   add_lines(x = final_forecast$date, y = final_forecast$pred_automl, name = "Auto ML") %>%   layout(title = "Total Vehicle Sales - Final Forecast",          yaxis = list(title = "Thousands of Units", range = c(1100, 1750)),          xaxis = list(title = "Month", range = c(as.Date("2016-01-01"), as.Date("2020-01-01"))))

Figura . Parece que los tres modelos capturan el componente estacional de la serie de ventas de vehículos. Sin embargo, parece que la oscilación de AutoML es mayor con respecto a uno de los modelos RF y GBM. Por lo tanto, tendría sentido seleccionar los modelos GBM o RF como pronóstico final. Un enfoque más conservador sería crear y agrupar los tres pronósticos ponderados en promedio regular. Por ejemplo, puede usar una función simple para probar los diferentes promedios de diferentes modelos y seleccionar la combinación que minimiza la tasa de error de pronóstico en el conjunto de prueba.

Resumen

En este capítulo, se presentan las aplicaciones de los modelos de aprendizaje automático (ML) para pronosticar datos de series temporales. El capítulo comienza con un análisis exploratorio de la serie de ventas de vehículos de EE. UU., utilizando análisis de correlación y estacionalidad. Este análisis permite identificar las principales tendencias y patrones de la serie.

A continuación, se presentan los principales conceptos de modelado de series temporales con ML. Estos conceptos incluyen la creación de características, el ajuste de modelos y la evaluación de resultados.

El capítulo también presenta la búsqueda en cuadrícula, una técnica para ajustar y optimizar modelos de ML. La búsqueda en cuadrícula permite explorar un espacio de parámetros amplio y encontrar la combinación de parámetros que produce el mejor modelo.

Por último, se presenta el modelo AutoML del paquete h2o. AutoML es una herramienta que automatiza los procesos de creación, ajuste y evaluación de modelos de ML.

En resumen, este capítulo proporciona una introducción a las aplicaciones de los modelos de ML para pronosticar datos de series temporales. El capítulo cubre los principales conceptos de modelado de series temporales con ML, así como las herramientas y técnicas que se pueden utilizar para crear modelos precisos.