# ══════════════════════════════════════════════════ # T12 · Series Temporales — Aprendizaje Automático para Series Temporales # Abre primero mSeriesTemporales.Rproj en RStudio # ══════════════════════════════════════════════════ library(tidyverse) library(timetk) library(modeltime) library(parsnip) library(rsample) library(workflows) library(recipes) pausa <- function(msg = "\n [Pulsa ENTER para continuar...]") { if (interactive()) { cat(msg); invisible(readline()) } } set.seed(2026) # ── 1. SERIE SIMULADA CON TENDENCIA Y ESTACIONALIDAD ─ n <- 200 t_idx <- 1:n serie <- tibble( fecha = seq(as.Date("2009-01-01"), by = "month", length.out = n), y = 100 + 0.3 * t_idx + 5 * sin(2 * pi * t_idx / 12) + rnorm(n, sd = 1) ) plot(serie$fecha, serie$y, type = "l", main = "Serie simulada: tendencia + estacionalidad + ruido") pausa() # ── 2. INGENIERIA DE CARACTERISTICAS ────────────── serie_feat <- serie |> tk_augment_lags(y, .lags = c(1, 12)) |> tk_augment_slidify(y_lag1, .f = mean, .period = 3, .align = "right", .partial = TRUE, .names = "roll3") |> drop_na() cat("Primeras filas de la tabla de caracteristicas:\n") print(head(serie_feat)) pausa() # ── 3. XGBOOST SOBRE EL NIVEL: EL PROBLEMA DE EXTRAPOLAR ─ split <- time_series_split(serie_feat, date_var = fecha, assess = "24 months", cumulative = TRUE) rec <- recipe(y ~ fecha + y_lag1 + y_lag12 + roll3, data = training(split)) |> step_timeseries_signature(fecha) |> step_rm(matches("(iso$)|(xts$)|(hour)|(minute)|(second)|(am.pm)|(lbl)")) |> step_normalize(matches("(index.num)|(year)")) |> step_rm(fecha) wflow <- workflow() |> add_model(boost_tree(mode = "regression") |> set_engine("xgboost")) |> add_recipe(rec) m_xgb <- recursive( fit(wflow, data = training(split)), transform = function(data) data |> tk_augment_lags(y, .lags = c(1, 12)) |> tk_augment_slidify(y_lag1, .f = mean, .period = 3, .align = "right", .partial = TRUE, .names = "roll3"), train_tail = tail(training(split), 13) ) fc <- predict(m_xgb, testing(split))$.pred real <- testing(split)$y cat(sprintf("Rango entrenamiento: [%.1f, %.1f] | Rango predicciones: [%.1f, %.1f]\n", min(training(split)$y), max(training(split)$y), min(fc), max(fc))) cat(sprintf("RECM = %.3f\n", sqrt(mean((real - fc)^2)))) cat("Nota: si la tendencia simulada es fuerte, las predicciones quedan por debajo del nivel real,\n") cat(" pegadas al limite superior de los valores vistos en entrenamiento.\n") # === FIN Script T12 — Aprendizaje Automático para Series Temporales ===