Suavizado exponencial

1 Introducción

A menudo podemos considerar que un conjunto de datos consta de dos componentes distintos: la señal y el ruido. La señal representa cualquier patrón causado por la dinámica intrínseca del proceso a partir del cual se recopilan los datos. Estos patrones pueden adoptar diversas formas, desde un proceso constante simple hasta una estructura más complicada que no se puede extraer visualmente ni con ninguna herramienta estadística básica. El proceso constante, por ejemplo, se representa como se muestra en la Ecuación 1:

\[\begin{align} y_{\scriptscriptstyle t} = \mu + \varepsilon_t \end{align} \tag{1}\]

Donde \(\mu\) representa el nivel constante \(\varepsilon_t\) es el ruido en el tiempo \(t\). \(\varepsilon_t\) se asume no correlaciodado, con una media \(0\) y varianza \(\sigma^2_{\varepsilon}\).

El Suavizado se puede ver como una técnica para separar la señal y el ruido tanto como sea posible y, en ese sentido, un suavizador actúa como un filtro para obtener una “estimación” de la señal. Los suavizadores que se analizan en este curso logran esto simplemente relacionando la observación actual con las anteriores. Para un conjunto de datos dado, se pueden diseñar suavizadores hacia adelante y/o hacia atrás, aunque solo consideraremos los suavizadores hacia atrás. Es decir, en cualquier \(T\) dado, la observación \(y_{\scriptscriptstyle T}\) será reemplazada por una combinación de observaciones en \(T\) y anteriores a \(T\). Por lo tanto, resulta intuitivamente lógico utilizar algún tipo de “promedio” de la observación actual y las anteriores para suavizar los datos. Una opción obvia es reemplazar la observación actual con el promedio de las observaciones en \(T, T−1,…,1\).

Un proceso constante puede suavizarse reemplazando la observación actual con la mejor estimación para \(\mu\). Utilizando el criterio de mínimos cuadrados, se define la Suma de Cuadrados del error, \(SSE\), para un proceso constante como se= muestra en la Ecuación 2:

\[\begin{align} SS_E = \sum_{t=1}^T (y_{\scriptscriptstyle t} - \mu)^2 \end{align} \tag{2}\]

La estimación mediante mínimos cuadrados para \(\mu\) se puede hallar derivando con respecto a \(\mu\) la Ecuación 2 e igualandola a cero, obteniendo \(\hat{\mu}\) como se muestra en la Ecuación 3:

\[\begin{align} \hat{\mu} = \frac{1}{T} \sum_{t=1}^T y_{\scriptscriptstyle t} \end{align} \tag{3}\]

1.1 Suavizado para procesos “constantes”: serie Dow Jones

A partir de datos de cierre mensual del Índice Dow Jones:

Descarga datos de la tabla

Si se observa el Índice Dow Jones desde Junio de \(1999\) hasta Junio de \(2001\), se puede obtener un gráfico, usando `ggplot2() de la serie así:

library(readxl)
library(ggplot2)
library(dplyr)
datos_dowjones <- read_excel("datos_dowjones.xlsx")
# Asegurarnos de que 'mes' esté en formato POSIXct o Date estándar,
# y filtrar usando el mismo tipo de objeto:
datos_dowjones %>%
  filter(mes >= as.POSIXct("1999-05-01") & mes <= as.POSIXct("2001-06-30")) %>%
  ggplot(aes(x = mes, y = dow_jones)) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 1.5) +
  labs(
    title = "Serie temporal Índice Dow Jones (Jun 1999 - Jun 2001)",
    x = expression("Mes (" * t * ")"),
    y = expression(y[t])
  ) +
  theme_classic()

La inspección visual del gráfico anterior sugiere que se puede utilizar un modelo constante para describir el patrón general de los datos. Para confirmar esta afirmación, se utilizó el suavizador descrito en la Ecuación 3 para cada punto de datos tomando el promedio de los datos disponibles hasta ese momento en el tiempo. Las observaciones suavizadas se muestran mediante los segmentos de línea en la siguiente figura. Se puede ver que el suavizador de la Ecuación 3 efectivamente extrae el patrón principal; el índice Dow Jones era bastante estable:

library(readxl)
library(ggplot2)
library(dplyr)
datos_dowjones <- read_excel("datos_dowjones.xlsx")
# 1. Filtrar los datos y calcular la media acumulada (el suavizador)
datos_filtrados <- datos_dowjones %>%
  filter(mes >= as.POSIXct("1999-05-01") & mes <= as.POSIXct("2001-06-30")) %>%
  mutate(
    # cummean calcula el promedio de las observaciones desde el inicio hasta el tiempo t (T, T-1, ..., 1)
    mu_estimada = cummean(dow_jones)
  )
# 2. Crear el gráfico con ggplot2
datos_filtrados %>%
  ggplot(aes(x = mes)) +
  # Serie original
  geom_line(aes(y = dow_jones, color = "Serie Original"), linewidth = 0.8) +
  geom_point(aes(y = dow_jones, color = "Serie Original"), size = 1.5) +
  # Línea suavizada con la estimación de mu (media acumulada)
  geom_line(aes(y = mu_estimada, color = "Suavizado (μ acumulada)"), linewidth = 1, linetype = "dashed") +
  labs(
    title = "Suavizado de la Serie Temporal (Dow Jones)",
    subtitle = "Junio 1999 - Junio 2001",
    x = expression("Mes (" * t * ")"),
    y = expression(y[t]),
    color = "Leyenda"
  ) +
  theme_classic() +
  scale_color_manual(values = c("Serie Original" = "black", "Suavizado (μ acumulada)" = "blue"))

1.2 Suavizado para procesos “no constantes”.

¿Qué ocurre si el proceso no es constante, sino que presenta un patrón más complicado? Considere de nuevo, por ejemplo, el índice Dow Jones de junio de 1999 a junio de 2006 que se muestra a continuación:

library(readxl)
library(ggplot2)
library(dplyr)
datos_dowjones <- read_excel("datos_dowjones.xlsx")
datos_dowjones %>%  ggplot(aes(x = mes, y = dow_jones)) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 1.5) +
  labs(
    title = "Serie temporal Índice Dow Jones",
    x = expression("Mes (" * t * ")"),
    y = expression(y[t])
  ) +
  theme_classic()

Está claro que los datos no siguen el comportamiento típico de un proceso constante durante este período. En la siguiente figura también podemos ver el patrón que extrae el suavizador de la Ecuación 3 para el mismo período.

library(readxl)
library(ggplot2)
library(dplyr)
datos_dowjones <- read_excel("datos_dowjones.xlsx")
# 1. Calcular la media acumulada (el suavizador)
datos_completos <- datos_dowjones %>%
  mutate(
    # cummean calcula el promedio de las observaciones desde el inicio hasta el tiempo t (T, T-1, ..., 1)
    mu_estimada = cummean(dow_jones)
  )
# 2. Crear el gráfico con ggplot2
datos_completos %>%
  ggplot(aes(x = mes)) +
  # Serie original
  geom_line(aes(y = dow_jones, color = "Serie Original"), linewidth = 0.8) +
  geom_point(aes(y = dow_jones, color = "Serie Original"), size = 1.5) +
  # Línea suavizada con la estimación de mu (media acumulada)
  geom_line(aes(y = mu_estimada, color = "Suavizado (μ acumulada)"), linewidth = 1, linetype = "dashed") +
  labs(
    title = "Suavizado de la Serie Temporal (Dow Jones)",
    x = expression("Mes (" * t * ")"),
    y = expression(y[t]),
    color = "Leyenda"
  ) +
  theme_classic() +
  scale_color_manual(values = c("Serie Original" = "black", "Suavizado (μ acumulada)" = "blue"))

A medida que el proceso cambia, este suavizador tiene problemas para seguir el ritmo del proceso. ¿Cuál podría ser la razón de su mal rendimiento después de junio de 2001? La respuesta es bastante simple: la hipótesis de proceso constante ya no es válida. A medida que pasa el tiempo, el suavizador de la Ecuación 3 acumula cada vez más puntos de datos y adquiere una especie de “inercia”. Por lo tanto, cuando se produce un cambio en el proceso, le resulta cada vez más difícil reaccionar ante él. De hecho, cuando hay un cambio en el proceso, los datos anteriores no contienen la información sobre dicho cambio, pero aun así contribuyen a esta inercia en la misma proporción que los datos más recientes (y probablemente más útiles). La opción más obvia es descontar de algún modo los datos más antiguos. En un promedio simple, todas las observaciones tienen la misma ponderación y, por lo tanto, la misma cantidad de influencia en el promedio. Por lo tanto, si se modifican los pesos de cada observación para que las observaciones anteriores tengan menos peso, se debería obtener un suavizador que reaccione más rápido. Una solución común es utilizar la media móvil simple, como se muestra en la Ecuación 4:

\[\begin{align} M_{\scriptscriptstyle T} = \frac{1}{N} \sum_{t=T - N +1}^N y_{\scriptscriptstyle t} \end{align} \tag{4}\]

Donde \(N\) representa el intervalo, cantidad de observaciones a tener en cuenta; si se utiliza la media móvil simple para los datos de Sección 1.1, para \(N=5\), y \(N=10\) se obtiene el siguiente suavizado:

library(readxl)
library(ggplot2)
library(dplyr)
library(zoo) # Necesario para calcular la media móvil fácilmente con rollmean

datos_dowjones <- read_excel("datos_dowjones.xlsx")

# 1. Calcular la media acumulada y las medias móviles de N=5 y N=10
datos_completos <- datos_dowjones %>%
  mutate(
    mu_estimada = cummean(dow_jones),
    # rollmean con align = "right" toma los últimos N puntos (hacia atrás)
    ma_5  = rollmean(dow_jones, k = 5, fill = NA, align = "right"),
    ma_10 = rollmean(dow_jones, k = 10, fill = NA, align = "right")
  )

# 2. Crear el gráfico con ggplot2
datos_completos %>%
  ggplot(aes(x = mes)) +
  # Serie original
  geom_line(aes(y = dow_jones, color = "Serie Original"), linewidth = 0.8) +
  geom_point(aes(y = dow_jones, color = "Serie Original"), size = 1.5) +
  # Suavizado (μ acumulada)
  geom_line(aes(y = mu_estimada, color = "Suavizado (μ acumulada)"), linewidth = 0.9, linetype = "dashed") +
  # Media móvil N = 5
  geom_line(aes(y = ma_5, color = "Media Móvil (N = 5)"), linewidth = 0.9) +
  # Media móvil N = 10
  geom_line(aes(y = ma_10, color = "Media Móvil (N = 10)"), linewidth = 0.9) +
  labs(
    title = "Comparación de Suavizados: Acumulado vs. Medias Móviles",
    x = expression("Mes (" * t * ")"),
    y = expression(y[t]),
    color = "Leyenda"
  ) +
  theme_classic() +
  scale_color_manual(values = c(
    "Serie Original" = "gray", 
    "Suavizado (μ acumulada)" = "blue",
    "Media Móvil (N = 5)" = "red",
    "Media Móvil (N = 10)" = "darkgreen"
  ))

2 Suavizado Exponencial de Primer Orden - Suavizado Exponencial Simple (SES)

Otro enfoque para obtener un suavizador que reaccione más rápido a los cambios del proceso consiste en dar ponderaciones geométricamente decrecientes a las observaciones pasadas. Por lo tanto, se obtiene un suavizador ponderado exponencialmente al introducir un factor de descuento \(\theta\) como se muestra en la Ecuación 5:

\[\begin{align} \sum_{t=0}^{T-1} \theta^t y_{\scriptscriptstyle T-t} = y_{\scriptscriptstyle T} + \theta y_{\scriptscriptstyle T-1} + \theta^2 y_{\scriptscriptstyle T-2}+...+ \theta^{T-1} y_{\scriptscriptstyle 1 } \end{align} \tag{5}\]

Tenga en cuenta que si el peso las observaciones anteriores a \(T\) se van a descontar de manera decreciente entonces se debe tener \(\theta < 1\). Además el suavizador de la Ecuación 5, no es un promedio, la suma de los ponderadores se calcula como se muestra en la Ecuación 6:

\[\begin{align} \sum_{t=0}^T \theta^t = \frac{1-\theta^T}{1-\theta} \end{align} \tag{6}\]

Por lo tanto no suma, necesariamente \(1\). Para ellos se puede ajusta el suavizador de la Ecuación 5, multiplicándolo por \(\frac{1-\theta}{1-\theta^T}\). Para valores grandes de \(T\), \(\theta^T\) tiende a \(0\), entonces, el promedio ponderado exponencialmente tendrá la forma que se muestra en la Ecuación 7:

\[\begin{align} \tilde{y}_{\scriptscriptstyle T} &= (1-\theta) \sum_{t=0}^{T-1} \theta^t y_{\scriptscriptstyle T-t}\\ \tilde{y}_{\scriptscriptstyle T} &= (1-\theta) (y_{\scriptscriptstyle T} + \theta y_{\scriptscriptstyle T-1} + \theta^2 y_{\scriptscriptstyle T-2} + \dots + \theta^{T-1}y_1) \end{align} \tag{7}\]

La expresión de la Ecuación 7 se denomina Suavizador Exponencial Simple o Suavizador de Primer Orden.

Una expresión alternativa de manera recursiva para el Suavizador Exponencial simple se muestra en la Ecuación 8:

\[\begin{align} \tilde{y}_{\scriptscriptstyle T} &= (1-\theta) (y_{\scriptscriptstyle T} + \theta y_{\scriptscriptstyle T-1} + \theta^2 y_{\scriptscriptstyle T-2} + \dots + \theta^{T-1}y_1) \\ \tilde{y}_{\scriptscriptstyle T} &= (1-\theta) y_{\scriptscriptstyle T} + (1-\theta)(\theta y_{\scriptscriptstyle T-1} + \theta^2 y_{\scriptscriptstyle T-2} + \dots + \theta^{T-1}y_1) \\ \tilde{y}_{\scriptscriptstyle T} &= (1-\theta) y_{\scriptscriptstyle T} + \theta (1-\theta) (y_{\scriptscriptstyle T-1} + \theta^1 y_{\scriptscriptstyle T-2} + \dots + \theta^{T-2} y_1) \\ \tilde{y}_{\scriptscriptstyle T} &= (1-\theta) y_{\scriptscriptstyle T} + \theta \tilde{y}_{\scriptscriptstyle T-1} \end{align} \tag{8}\]

La forma recursiva de la Ecuación 8 muestra que el suavizado exponencial de primer orden también puede verse como la combinación lineal de la observación actual y la observación suavizada en la unidad de tiempo anterior. Dado que esta última contiene los datos de todas las observaciones previas, la observación suavizada en el tiempo \(T\) es, de hecho, la combinación lineal de la observación actual y la suma descontada de todas las observaciones anteriores. El suavizador exponencial simple se representa a menudo de una forma diferente al establecer \(\lambda =1 - \theta\), y la Ecuación 8 se suele presentar como se muestra en la Ecuación 9:

\[\begin{align} \tilde{y}_{\scriptscriptstyle T} &= \lambda y_{\scriptscriptstyle T} + (1-\lambda) \tilde{y}_{\scriptscriptstyle T-1} \end{align} \tag{9}\]

En la Ecuación 9 el factor de descuento \(\lambda\) representa el peso otorgado a la última observación, y \((1-\lambda)\) representa el peso= otorgado al valor suavizado de las observaciones anteriores.

De forma análoga al tamaño del intervalo \(N\) en los suavizadores de media móvil, un aspecto importante para los suavizadores exponenciales es la elección del factor de descuento, \(\lambda\). Además, a partir de la Ecuación 9 se puede observar que para el cálculo de \(\tilde{y}_{\scriptscriptstyle 1}\) requiere conocer \(\tilde{y}_{\scriptscriptstyle 0}\), estas cuestiones se tratarán a continuación.

2.1 Valor inicial \(\tilde{y}_{\scriptscriptstyle 0}\)

Como \(\tilde{y}_{\scriptscriptstyle 0}\) es necesario para calcular \(\tilde{y}_{\scriptscriptstyle 1}\):

\[\begin{align} \tilde{y}_{\scriptscriptstyle 1} &= \lambda y_{\scriptscriptstyle 1} + (1-\lambda) \tilde{y}_{\scriptscriptstyle 0} \end{align}\]

El valor de \(\tilde{y}_{\scriptscriptstyle 0}\) debe ser estimado. De la Ecuación 9 se tiene que:

\[\begin{align} \tilde{y}_{\scriptscriptstyle 1} &= \lambda y_{\scriptscriptstyle 1} + (1-\lambda) \tilde{y}_{\scriptscriptstyle 0} \\ \tilde{y}_{\scriptscriptstyle 2} &= \lambda y_{\scriptscriptstyle 2} + (1-\lambda) \tilde{y}_{\scriptscriptstyle 1} = \lambda y_{\scriptscriptstyle 2} + (1-\lambda)(\lambda y_{\scriptscriptstyle 1} + (1-\lambda) \tilde{y}_{\scriptscriptstyle 0})\\ &= \lambda(y_{\scriptscriptstyle 2} +(1-\lambda)y_{\scriptscriptstyle 1}) + (1-\lambda)^2 \tilde{y}_{\scriptscriptstyle 0}\\ \tilde{y}_{\scriptscriptstyle 3} &= \lambda(y_{\scriptscriptstyle 3} +(1-\lambda)y_{\scriptscriptstyle 2} + (1-\lambda)^2 y_{\scriptscriptstyle 1}) + (1-\lambda)^3 \tilde{y}_{\scriptscriptstyle 0}\\ .\\ .\\ .\\ \tilde{y}_{\scriptscriptstyle T} &= \lambda (y_{\scriptscriptstyle T} + (1-\lambda) y_{\scriptscriptstyle T-1}+ \dots + (1-\lambda)^{T-1} y_{\scriptscriptstyle 1}) + (1-\lambda)^T \tilde{y}_{\scriptscriptstyle 0} \end{align}\]

Lo que significa que a medida que \(T\) se hace grande y, por lo tanto, \((1-\lambda)^T\) se vuelve pequeño, la contribución de \(\tilde{y}_{\scriptscriptstyle 0}\) a \(\tilde{y}_{\scriptscriptstyle T}\) se vuelve insignificante. Por lo tanto, para conjuntos de datos grandes, la estimación de \(\tilde{y}_{\scriptscriptstyle 0}\) tiene poca relevancia. Sin embargo, dos estimaciones comúnmente utilizadas para \(\tilde{y}_{\scriptscriptstyle 0}\) son las siguientes:

  1. Establecer \(\tilde{y}_{\scriptscriptstyle 0} = y_{\scriptscriptstyle 1}\). Si se espera que los cambios en el proceso ocurran de forma temprana y rápida, esta elección para el valor inicial de \(\tilde{y}_{\scriptscriptstyle T}\) es razonable.

  2. Tomar el promedio de los datos disponibles o de un subconjutno de los datos disponibles \(\bar{y}\) y establecer \(\tilde{y}_{\scriptscriptstyle 0} = \bar{y}\). Si el proceso es localmente constante, al menos al principio, se puede preferir este valor inicial.

2.2 El valor de \(\lambda\)

En general, a medida que \(\lambda\) se acerca a \(1\) y se pone más énfasis en la última observación, los valores suavizados se aproximarán a las observaciones originales. Dos casos extremos ocurren cuando \(\lambda=0\) y \(\lambda=1\). En el primero, todos los valores suavizados serán iguales a una constante, a saber, \(y_{\scriptscriptstyle 0}\). Por lo tanto, la cuestión será cuánta suavización se necesita. En la literatura, a menudo se recomiendan valores de \(\lambda\) entre \(0.1\) y \(0.4\), los cuales de hecho funcionan bien en la práctica. Este proceso se tratará de manera rigurosa cuando se vean otros métodos de suavizado exponencial.

2.3 Pronóstico en Suavizado Exponencial Simple o de Primer Orden

Como se vió en Ecuación 9, el suavizado exponencial para un proceso constante se expresa como:

\[\begin{align} \tilde{y}_{\scriptscriptstyle T} &= \lambda y_{\scriptscriptstyle T} + (1-\lambda) \tilde{y}_{\scriptscriptstyle T-1} \end{align}\]

El pronóstico para la observación futura es simplemente igual al valor actual del suavizador exponencial, como se muestra en la Ecuación 10:

\[\begin{align} \hat{y}_{\scriptscriptstyle T+\tau} = \tilde{y}_{\scriptscriptstyle T} \end{align} \tag{10}\]

Tenga en cuenta que, para el proceso constante, el pronóstico en la Ecuación 10 es el mismo para todos los valores futuros. Dado que puede haber cambios en el nivel del proceso constante, pronosticar todas las observaciones futuras con el mismo valor probablemente sea engañoso. Sin embargo, a medida que se comienza a acumular más observaciones, se puede actualizar el pronóstico. Por ejemplo, si los datos en \(T+1\) están disponibles, el pronóstico para las observaciones futuras se convierte en:

\[\begin{align} \tilde{y}_{\scriptscriptstyle T+1} &= \lambda y_{\scriptscriptstyle T+1} + (1-\lambda) \tilde{y}_{\scriptscriptstyle T} \end{align}\]

O

\[\begin{align} \hat{y}_{\scriptscriptstyle T+1+\tau} (T+1) &= \lambda y_{\scriptscriptstyle T+1} + (1-\lambda) \hat{y}_{\scriptscriptstyle T+\tau}(T) \end{align} \tag{11}\]

Para \(\tau=1\), la Ecuación 11 se peude reescribir como:

\[\begin{align} \hat{y}_{\scriptscriptstyle T+2} (T+1) &= \hat{y}_{\scriptscriptstyle T+1} (T)+ \lambda (y_{\scriptscriptstyle T+1} - \hat{y}_{\scriptscriptstyle T+1} (T))\\ \hat{y}_{\scriptscriptstyle T+2} (T+1) &= \hat{y}_{\scriptscriptstyle T+1} (T) + \lambda e_{\scriptscriptstyle T+1}(1) \end{align} \tag{12}\]

Donde \(e_{\scriptscriptstyle T+1} (1) = y_{\scriptscriptstyle T+1} - \hat{y}_{\scriptscriptstyle T+1}(T)\) se denomina error de pronóstico o de predicción a un paso adelante. La interpretación de la Ecuación 12 facilita la comprensión del proceso de pronóstico mediante el suavizado exponencial: nuestro pronóstico para la siguiente observación es simplemente nuestro pronóstico anterior para la observación actual más una fracción del error de pronóstico que cometimos al pronosticar la observación actual. La fracción en esta suma está determinada por \(\lambda\). Por lo tanto, la velocidad con la que nuestro pronóstico reaccionará ante el error de pronóstico depende del factor de descuento. Un factor de descuento grande conducirá a una reacción rápida ante el error de pronóstico, pero también puede hacer que nuestro pronóstico reaccione rápidamente ante fluctuaciones aleatorias. Esto plantea una vez más la cuestión de la elección del factor de descuento.

3 Modelado de series de tiempo usando Suavizado Exponencial Simple con R

Para realizar un ejemplo completo de Suavizado Exponencial Simple en RStudio que incluya el modelado, la evaluación del ajuste y la evaluación del pronóstico, se utilizará el paquete forecast.

library(readxl)
library(forecast)
library(ggplot2)

# --- 1. CARGAR DATOS Y CREAR MODELO ---
datos_dowjones <- read_excel("datos_dowjones.xlsx")
serie_dowjones <- ts(datos_dowjones$dow_jones, start = c(1999, 6), frequency = 12)

# División entrenamiento y prueba
n_test <- 12
train  <- window(serie_dowjones, end = c(2005, 6))
test   <- window(serie_dowjones, start = c(2005, 7))

# Ajustar modelo SES y generar pronóstico
modelo_ses <- ets(train, model = "ANN")
pronostico <- forecast(modelo_ses, h = length(test))

# --- 2. ORGANIZAR DATOS EN UN DATAFRAME ---
# Extraer tiempos (fechas)
tiempo_train <- time(train)
tiempo_test  <- time(test)

# Dataframe de entrenamiento: Serie Real vs Ajuste del Modelo (Fitted)
df_ajuste <- data.frame(
  Tiempo = as.numeric(tiempo_train),
  Real = as.numeric(train),
  Ajustado = as.numeric(fitted(modelo_ses))
)

# Dataframe de pronóstico futuro (Valores Reales de prueba vs Pronóstico)
df_pronostico <- data.frame(
  Tiempo = as.numeric(tiempo_test),
  Real_Futuro = as.numeric(test),
  Pronostico = as.numeric(pronostico$mean)
)

# --- 3. GRÁFICA COMPLETA CON GGPLOT2 ---
ggplot() +
  # 1. Serie Original Histórica (Entrenamiento)
  geom_line(data = df_ajuste, aes(x = Tiempo, y = Real, color = "1. Serie Original (Histórica)"), linewidth = 0.8) +
  
  # 2. Serie Ajustada por el Modelo SES (In-Sample)
  geom_line(data = df_ajuste, aes(x = Tiempo, y = Ajustado, color = "2. Serie Ajustada (Modelo)"), linetype = "dashed", linewidth = 0.9) +
  
  # 3. Serie Real Futura (Prueba)
  geom_line(data = df_pronostico, aes(x = Tiempo, y = Real_Futuro, color = "3. Serie Real Futura (Prueba)"), linewidth = 0.8) +
  
  # 4. Pronóstico Futuro (Out-of-Sample)
  geom_line(data = df_pronostico, aes(x = Tiempo, y = Pronostico, color = "4. Pronóstico (SES)"), linewidth = 1.1) +
  
  # Configurar Colores y Leyenda
  scale_color_manual(values = c(
    "1. Serie Original (Histórica)" = "black",
    "2. Serie Ajustada (Modelo)"    = "blue",
    "3. Serie Real Futura (Prueba)" = "gray40",
    "4. Pronóstico (SES)"           = "red"
  )) +
  labs(
    title = "Suavizado Exponencial Simple: Serie Real, Ajuste Histórico y Pronóstico",
    subtitle = "Comparación completa del comportamiento del modelo SES en el Dow Jones",
    x = "Tiempo (Años)",
    y = "Índice Dow Jones",
    color = "Leyenda"
  ) +
  theme_classic() +
  theme(legend.position = "bottom")