Fundamentos de series de tiempo
Introducción
Una serie temporal es una secuencia de observaciones de una variable registradas en un orden cronológico. Se puede representar como:
\[ y_{\scriptscriptstyle 1}, y_{\scriptscriptstyle 2}, y_{\scriptscriptstyle 3},..., y_{\scriptscriptstyle t},..., y_{\scriptscriptstyle T} \]
O de manera compacta:
\[ \{y_{\scriptscriptstyle t} \}_{t=1}^T \]
Donde:
- \(y_t\): valor observado de \(y\) en el instante \(t\).
- \(t\): índice temporal.
- \(T\): número total de observaciones.
El propósito principal de analizar series temporales es comprender el comportamiento histórico de una variable a lo largo del tiempo para predecir sus valores futuros y tomar decisiones informadas.
Este análisis busca responder a cuatro objetivos clave:
Pronóstico (Forecasting): estimar qué sucederá en el futuro con base en los patrones del pasado (ejemplo: ventas del próximo mes, demanda eléctrica o inflación).
Identificación de patrones y tendencias: detectar si los datos van al alza o a la baja a largo plazo (tendencia) y si existen comportamientos cíclicos o estacionales que se repiten en períodos fijos (ejemplo: aumento de ventas en Navidad).
Explicación del comportamiento: evaluar cómo influyen factores externos, eventos especiales o intervenciones en la variable analizada (ejemplo: el impacto de una campaña publicitaria).
Detección de anomalías y control: identificar desviaciones inusuales respecto al comportamiento esperado para reaccionar a tiempo (ejemplo: detección de fraudes o fallas en maquinaria).
Algunos ejemplos de series de tiempo
Las gráficas de series temporales pueden revelar patrones tales como variaciones aleatorias, tendencias, cambios de nivel, períodos o ciclos, observaciones inusuales o una combinación de patrones. A continuación se analizan los patrones que se encuentran comúnmente en los datos de series temporales, junto con ejemplos de situaciones que los impulsan.
Ejemplo 1: sin patrones evidentes.
A partir de datos semanales de ventas de un producto farmacéutico:
Se puede obtener un gráfico, usando `ggplot2() de la serie así:
library(readxl)
library(ggplot2)
datos_farmacias <- read_excel("datos_farmacias.xlsx")
promedio <- mean(datos_farmacias$ventas, na.rm = TRUE)
datos_farmacias %>%
ggplot(aes(x = semana, y = ventas)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
geom_hline(
yintercept = promedio,
linetype = "dashed",
linewidth = 0.8
) +
labs(
title = "Serie temporal de ventas",
x = expression("Semana (" * t * ")"),
y = expression(y[t])
) +
theme_classic()O usando plot():
library(readxl)
datos_farmacias <- read_excel("datos_farmacias.xlsx")
promedio <- mean(datos_farmacias$ventas, na.rm = TRUE)
plot(
datos_farmacias$semana,
datos_farmacias$ventas,
type = "o",
pch = 16,
xlab = "Semana (t)",
ylab = expression(Y[t]),
main = "Serie temporal de ventas"
)
abline(
h = promedio,
lty = 2,
lwd = 2
)Las ventas de un producto farmacéutico maduro pueden permanecer relativamente estables si no se modifican las estrategias de comercialización o fabricación. Las ventas semanales de un producto farmacéutico genérico representadas en la parecen mantenerse constantes a lo largo del tiempo, alrededor de \(10400 \times 10^3 \text{ unidades}\), en una secuencia aleatoria sin patrones evidentes.
Ejemplo 2: autocorrelacionadas
Para garantizar el cumplimiento de los requisitos del cliente y las especificaciones del producto, la producción de productos químicos se monitorea mediante diversas características.
Estas pueden ser variables de entrada, tales como la temperatura y el caudal, y propiedades de salida, tales como la viscosidad y la pureza. Debido a la naturaleza continua de los procesos de fabricación química, las propiedades de salida suelen presentar una autocorrelación positiva; es decir, un valor por encima del promedio a largo plazo tiende a estar seguido por otros valores por encima del promedio, mientras que un valor por debajo del promedio tiende a estar seguido por otros valores por debajo del promedio.
Considere los siguientes datos de viscosidad:
library(readxl)
library(dplyr)
library(DT)
datos_viscosidad <- read_excel("datos_viscosidad.xlsx")
datos_viscosidad %>%
select(t, viscosidad) %>%
slice_head(n = 20) %>%
datatable(
colnames = c(
" <span class='math-inline'>t</span>",
"Viscosidad <span class='math-inline'>cP</sub></span>"
),
options = list(
pageLength = 10,
scrollX = TRUE,
columnDefs = list(
list(
className = "dt-center",
targets = "_all"
)
)
),
rownames = FALSE,
escape = FALSE
)Se puede graficar la serie usando ggplot2():
library(readxl)
library(ggplot2)
datos_viscosidad <- read_excel("datos_viscosidad.xlsx")
promedio <- mean(datos_viscosidad$viscosidad, na.rm = TRUE)
datos_viscosidad %>%
ggplot(aes(x = t, y = viscosidad)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
labs(
title = "Serie temporal de viscosidad",
x = expression("(" * t * ")"),
y = expression(cP)
) +
theme_classic()También se puede obtener el gráfico usando plot():
library(readxl)
datos_viscosidad <- read_excel("datos_viscosidad.xlsx")
#promedio <- mean(datos_viscosidad$viscosidad, na.rm = TRUE)
plot(
datos_viscosidad$t,
datos_viscosidad$viscosidad,
type = "o",
pch = 16,
xlab = expression(t),
ylab = expression(cP),
main = "Serie temporal de viscosidad"
)Las lecturas de viscosidad graficadas anteriormente exhiben un comportamiento autocorrelacionado, tendiendo a un promedio a largo plazo de aproximadamente 85 centipoise (cP), pero con una apariencia estructurada, no completamente aleatoria.
Ejemplo 3: con tendencia
El Servicio Nacional de Estadísticas Agrícolas del USDA (USDA-NASS) publica estadísticas agrícolas para numerosos productos, incluyendo la producción anual de derivados lácteos tales como mantequilla, queso, helado, leche, yogur y suero de leche. Estas estadísticas se utilizan para el análisis e inteligencia de mercado, como indicadores económicos y para la identificación de problemas emergentes. El queso azul y el gorgonzola conforman una de las 32 categorías de queso sobre las cuales se publican datos. A continuación se muestra una tabla con los datos de la producción anual estadounidense de quesos azul y gorgonzola:
Se puede graficar la serie usando ggplot2():
library(readxl)
library(ggplot2)
datos_gorgonzola <- read_excel("datos_gorgonzola.xlsx")
datos_gorgonzola %>%
ggplot(aes(x = Año, y = Produccion)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
labs(
title = "Serie temporal de Producción de queso azul y gorgonzola",
x = expression("(" * t * ")"),
y = expression("10^3 lb")
) +
theme_classic()También se puede obtener el gráfico usando plot():
library(readxl)
datos_gorgonzola <- read_excel("datos_gorgonzola.xlsx")
plot(
datos_gorgonzola$Año,
datos_gorgonzola$Produccion,
type = "o",
pch = 16,
xlab = expression(t),
ylab = expression(cP),
main = "Serie temporal de producción de queso azul y gorgonzola"
)La producción se cuadruplicó entre \(1950\) y \(1997\), y la tendencia lineal presenta una pendiente positiva constante con una variación aleatoria año tras año.
Ejemplo 4: con estacionalidad
La Oficina del Censo de los EE. UU. publica estadísticas históricas sobre envíos, inventarios y pedidos de los fabricantes. Las estadísticas se basan en el código del Sistema de Clasificación Industrial de América del Norte (NAICS) y se utilizan para fines tales como medir la productividad y analizar las relaciones entre el empleo y la producción manufacturera.
La fabricación de bebidas y productos de tabaco se reporta como parte del subsector no duradero. La información se puede ver en la siguiente tabla:
Se puede graficar la serie usando ggplot2():
library(readxl)
library(ggplot2)
datos_bebidas <- read_excel("datos_bebidas.xlsx")
datos_bebidas %>%
ggplot(aes(x = Mes, y = Millones)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
labs(
title = "Serie temporal de bebidas manufacturadas",
x = expression("(" * t * ")"),
y = expression("Millones USD")
) +
theme_classic()También se puede obtener el gráfico usando plot():
library(readxl)
datos_bebidas <- read_excel("datos_bebidas.xlsx")
plot(
datos_bebidas$Mes,
datos_bebidas$Millones,
type = "o",
pch = 16,
xlab = expression(t),
ylab = expression("Millones USD"),
main = "Serie temporal de bebidas manufacturadas"
)El gráfico de los envíos mensuales de productos de bebidas revela una tendencia general creciente, con un patrón cíclico distintivo que se repite dentro de cada año. Los envíos de enero parecen ser los más bajos, alcanzando máximos en mayo y junio. Esta variación mensual, o estacional, puede atribuirse a alguna causa tal como el impacto del clima en la demanda de bebidas.
Ejemplo 5: no estacionarias
Los datos empresariales, tales como los precios de las acciones y las tasas de interés, a menudo exhiben un comportamiento no estacionario; es decir, la serie temporal no tiene una media natural. El precio de cierre diario de las acciones de Whole Foods Market (WFMI) en 2001 se muestra en la siguiente tabla:
Se puede graficar la serie usando ggplot2():
library(readxl)
library(ggplot2)
datos_acciones %>%
ggplot(aes(x = Dia, y = USD)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
labs(
title = "Serie temporal precio de la acción WFMI",
x = expression("(" * t * ")"),
y = expression("USD")
) +
theme_classic()También se puede obtener el gráfico usando plot():
library(readxl)
datos_acciones <- read_excel("datos_acciones.xlsx")
plot(
datos_acciones$Dia,
datos_acciones$USD,
type = "o",
pch = 16,
xlab = expression(t),
ylab = expression("PrecioUSD"),
main = "Serie temporal precio de la acción WFMI"
)Aunque el precio se mantiene constante en algunos períodos cortos, no existe un nivel medio constante a lo largo del tiempo. En otros períodos, el precio cambia a diferentes ritmos, incluyendo cambios abruptos ocasionales en el nivel. Este es un ejemplo de comportamiento no estacionario.
Bases estadísticas para el modelado de series de tiempo y el pronóstico
Gráficos de series suavizadas
En ocasiones, resulta útil superponer una versión suavizada de los datos originales sobre el gráfico de la serie temporal, con el fin de facilitar la identificación de patrones en los datos. Existen varios tipos de suavizadores que pueden emplearse. Uno de los más sencillos y ampliamente utilizados es la media móvil simple.
Una media móvil simple de amplitud \(N\) asigna un peso de \(\frac{1}{N}\) a cada una de las \(N\) observaciones más recientes \(y_{\scriptscriptstyle T}, y_{\scriptscriptstyle T-1}, y_{\scriptscriptstyle T-2}, y_{\scriptscriptstyle T-3},..., y_{\scriptscriptstyle T-n+1}\) y asigna un peso igual a cero a todas las demás observaciones. Si se denota por \(M_{\scriptscriptstyle T}\) el promedio móvil, entonces el promedio móvil de amplitud \(N\) en el período \(T\) se define como muestra la Ecuación 1:
\[\begin{align} \frac{1}{N} \sum_{t=T-N+1}^T y_{\scriptscriptstyle t} \end{align} \tag{1}\]
Claramente, cada vez que se dispone de una nueva observación, esta se incorpora a la suma con la que se calcula el promedio móvil, mientras que la observación más antigua se elimina. El promedio móvil presenta una menor variabilidad que las observaciones originales. De hecho, si la varianza de una observación individual \(y_{\scriptscriptstyle t}\) es \(\sigma^2\), y suponiendo que las observaciones no están correlacionadas, la varianza del promedio móvil se puede expresar como muestra la Ecuación 2:
\[\begin{align} Var(M_{\scriptscriptstyle T}) &= Var \left( \frac{1}{N} \sum_{t=T-N+1}^N y_{\scriptscriptstyle t} \right) \\ Var(M_{\scriptscriptstyle T}) &= \frac{1}{N^2} \sum_{t=T-N+1}^N Var(y_{\scriptscriptstyle t}) \\ Var(M_{\scriptscriptstyle T}) &= \frac{\sigma^2}{N} \end{align} \tag{2}\]
En ocasiones se utiliza un versión centrada de la media movil como se muestra en la Ecuación 3
\[\begin{align} M_{\scriptscriptstyle T} &= \frac{1}{S+1} \sum_{i=-S}^S y_{\scriptscriptstyle t-1} \end{align} \tag{3}\]
Donde la amplitud del promedio móvil centrado es \(N=2S +1\),
Se puede realizar gráficamente suavizaciones con media móvil en ggplot2(), con por ejemplo \(3\) observaciones, de la siguiente forma:
- Para los datos de viscosidad
library(readxl)
library(ggplot2)
library(dplyr)
library(zoo)
library(plotly)
datos_viscosidad <- read_excel("datos_viscosidad.xlsx")
# Media móvil de orden 3
datos_viscosidad <- datos_viscosidad %>%
mutate(
media_movil = rollmean(
viscosidad,
k = 3,
fill = NA,
align = "center"
)
)
grafico<-datos_viscosidad %>%
ggplot(aes(x = t)) +
geom_line(aes(y = viscosidad, color = "Serie original"),
linewidth = 0.7) +
geom_point(aes(y = viscosidad, color = "Serie original"),
size = 1.5) +
geom_line(aes(y = media_movil, color = "Media móvil"),
linewidth = 1.1,
na.rm = TRUE) +
labs(
title = "Serie temporal de viscosidad",
x = expression(t),
y = expression(cP),
color = NULL
) +
scale_color_manual(
values = c(
"Serie original" = "gray60",
"Media móvil" = "red"
)
) +
theme_classic()
ggplotly(grafico)- Para los datos de producción anual de queso azul y gorgonzola
library(readxl)
library(ggplot2)
library(dplyr)
library(zoo)
library(plotly)
datos_gorgonzola <- read_excel("datos_gorgonzola.xlsx")
datos_gorgonzola <- datos_gorgonzola %>%
mutate(
media_movil = rollmean(
Produccion,
k = 3,
fill = NA,
align = "center"
)
)
grafico<-datos_gorgonzola %>%
ggplot(aes(x = Año)) +
geom_line(aes(y= Produccion, color="Serie original"), linewidth = 0.7) +
geom_point(aes(y=Produccion, color= "Serie original"), size=1.5) +
geom_line(aes(y=media_movil, color="Media móvil"), linewidth = 1.1, na.rm=TRUE) +
labs(
title = "Serie temporal de Producción de queso azul y gorgonzola",
x = expression(t),
y = expression(10^3 * lb),
color= NULL
) +
scale_color_manual(
values = c(
"Serie original" = "gray60",
"Media móvil" = "red"
)
) +
theme_classic()
ggplotly(grafico)- Para los datos de Whole Foods Market (WFMI)
library(readxl)
library(ggplot2)
library(dplyr)
library(zoo)
library(plotly)
datos_acciones <- datos_acciones %>%
mutate(
media_movil = rollmean(
USD,
k = 5,
fill = NA,
align = "center"
)
)
grafico<-datos_acciones %>%
ggplot(aes(x = Dia)) +
geom_line(aes(y=USD, color="Serie original"), linewidth = 0.7) +
geom_point(aes(y=USD, color= "Serie original"), size=1.5) +
geom_line(aes(y=media_movil, color = "Media móvil"), linewidth = 1.1, na.rm=TRUE) +
labs(
title = "Serie temporal precio de la acción WFMI",
x = expression(t),
y = "USD",
color=NULL
) +
scale_color_manual(
values = c(
"Serie original" = "gray60",
"Media móvil" = "red"
)
) +
theme_classic()
ggplotly(grafico)La media móvil simple es un suavizador lineal de datos o filtro lineal, por que reemplaza cada observación \(y_{\scriptscriptstyle t}\) por una combinación lineal de otros puntos de datos cercanos a ella en el tiempo. Los pesos de esta combinación lineal son iguales, por lo que, en este caso, la combinación lineal corresponde a un promedio. Por supuesto, también pueden utilizarse pesos diferentes. Por ejemplo, el filtro de Hanning (usado en meteorología) es un promedio móvil centrado y ponderado, que se calcula como se muestra en la Ecuación 4:
\[\begin{align} M_{\scriptscriptstyle T}^{\scriptscriptstyle H} &= 0.25 y_{\scriptscriptstyle t+1} + 0.5 y + 0.25 y_{\scriptscriptstyle t-1} \end{align} \tag{4}\]
Una desventaja evidente de un filtro lineal, como el promedio móvil, es que un dato inusual, erróneo o atípico puede tener una influencia considerable sobre los promedios móviles que incluyen dicha observación, contaminándolos durante un período cuya duración es igual a la amplitud del filtro.
Por ejemplo, considérese la siguiente secuencia de observaciones:
\[ \{ 15,18,13,12,16,14,16,17,18,15,18,200,19,14,21,24,19,25 \} \]
La secuencia presenta una tendencia general de aumento relativamente constante, desde \(15\) hasta \(25\), con excepción del valor inusual de \(200\). Cualquier versión suavizada razonable de estos datos también debería mostrar un incremento gradual desde \(15\) hasta \(25\), sin otorgar una importancia excesiva al valor \(200\).
Ahora bien, incluso si el valor \(200\) corresponde a una observación legítima y no es el resultado de un error en el registro o la comunicación de los datos (quizás el valor correcto debería ser \(20\)), se trata de un valor tan inusual que merece una atención especial y probablemente no debería analizarse junto con el resto de los datos.
Realizando la suavización mediante media móvil se obtiene lo siguiente:
library(ggplot2)
library(dplyr)
library(zoo)
library(plotly)
datos <- data.frame(
t = 1:18,
x = c(15, 18, 13, 12, 16, 14, 16, 17, 18,
15, 18, 200, 19, 14, 21, 24, 19, 25)
)
datos <- datos %>%
mutate(
media_movil = rollmean(
x,
k = 3,
fill = NA,
align = "center"
)
)
grafico<-datos %>%
ggplot(aes(x = t)) +
geom_line(aes(y = x, color = "Serie original"), linewidth = 0.7) +
geom_point(aes(y = x, color = "Serie original"), size = 1.5) +
geom_line(aes(y = media_movil, color = "Media móvil"),
linewidth = 1.1, na.rm = TRUE) +
labs(
title = "Serie temporal con media móvil",
x = expression(t),
y = expression(x[t]),
color = NULL
) +
scale_color_manual(
values = c(
"Serie original" = "gray60",
"Media móvil" = "red"
)
) +
theme_classic()
ggplotly(grafico)Nota: la media móvil de orden 3 permite observar cómo el valor atípico de \(200\) afecta el suavizado en las observaciones cercanas.
Una alternativa a la desventaja expuesta de las medias móviles, son las Medianas Móviles de Amplitud Impar, son suavizadores de datos eficaces cuando la serie temporal puede estar contaminada por valores inusuales o atípicos. La mediana móvil de amplitud \(N\) se define como se muestra en la Ecuación 5:
\[\begin{align} M_{\scriptscriptstyle t}^{\scriptscriptstyle [N]} &= Med(y_{\scriptscriptstyle t-u},..., y_{\scriptscriptstyle t},..., y_{\scriptscriptstyle t=u}) \end{align} \tag{5}\]
Donde \(N = 2u+1\),
La mediana es la observación central cuando los datos se ordenan según su magnitud. La mediana móvil de amplitud \(3\) es un suavizador muy utilizado y eficaz, definido como se muestra en la Ecuación 6:
\[\begin{align} M_{\scriptscriptstyle t}^{\scriptscriptstyle [3]} &= Med(y_{\scriptscriptstyle t-1}, y_{\scriptscriptstyle t}, y_{\scriptscriptstyle t=1}) \end{align} \tag{6}\]
Este suavizador procesa los datos de tres en tres y reemplaza las tres observaciones originales por su mediana. Si aplicamos este procedimiento a los datos anteriores, se obtiene:
library(ggplot2)
library(dplyr)
library(zoo)
library(plotly)
datos <- data.frame(
t = 1:18,
x = c(15, 18, 13, 12, 16, 14, 16, 17, 18,
15, 18, 200, 19, 14, 21, 24, 19, 25)
)
datos <- datos %>%
mutate(
mediana_movil = rollapply(
x,
width = 3,
FUN = median,
fill = NA,
align = "center"
)
)
grafico<-datos %>%
ggplot(aes(x = t)) +
geom_line(aes(y = x, color = "Serie original"), linewidth = 0.7) +
geom_point(aes(y = x, color = "Serie original"), size = 1.5) +
geom_line(
aes(y = mediana_movil, color = "Mediana móvil"),
linewidth = 1.1,
na.rm = TRUE
) +
labs(
title = "Serie temporal con mediana móvil de orden 3",
x = expression(t),
y = expression(x[t]),
color = NULL
) +
scale_color_manual(
values = c(
"Serie original" = "gray60",
"Mediana móvil" = "red"
)
) +
theme_classic()
ggplotly(grafico)Diferencia importante: la mediana móvil de orden \(3\) calcula la mediana de cada grupo de tres observaciones consecutivas, en esta serie, el valor atípico de \(200\) tendrá mucho menos efecto sobre la mediana móvil que sobre la media móvil, porque la mediana es robusta frente a valores extremos.
Estos datos suavizados constituyen una representación razonable de los datos originales, pero ignoran convenientemente el valor \(200\). Los valores extremos se pierden al utilizar la mediana móvil y se representan mediante espacios en blanco.
En general, una mediana móvil deja sin cambios las secuencias de datos monótonas. Sigue los cambios escalonados presentes en los datos, pero elimina los picos o las perturbaciones más persistentes cuya duración no supera \(u\) observaciones consecutivas. Si se desea obtener una serie de observaciones aún más suavizada, las medianas móviles pueden aplicarse más de una vez.
Descripción numérica de series de tiempo
Series estacionarias
Un tipo muy importante de series de tiempo son las series estacionarias:
Una serie de tiempo se dice estrictamente estacionaria si sus propiedades no se ven afectadas por un cambio en el origen del tiempo.
Es decir, si la distribución de probabilidad conjunta de las observaciones \(y_{\scriptscriptstyle t},y_{\scriptscriptstyle t+1}, y_{\scriptscriptstyle t+2}, ..., y_{\scriptscriptstyle t+n}\) es exactamente la misma distribución de probabilidad conjunta de las observaciones \(y_{\scriptscriptstyle t+k},y_{\scriptscriptstyle t+k+1}, y_{\scriptscriptstyle t+k+2}, ..., y_{\scriptscriptstyle t+k+n}\), entonces la serie es extrictamente estacionaeria.
Cuando \(n=0\) el supuesto de estacionaridad implica que la distribución de probabildiad de \(y_{\scriptscriptstyle t}\) es la misma para todos los períodos de tiempo y puede expresarse como \(f(y)\).
Los ejemplos se series de tiempo para los datos de ventas de productos farmaceúticos, así como los datos de la viscosidad son ejemplos de series estacionarias, se muestran gráficamente a continuación:
library(readxl)
library(ggplot2)
library(dplyr)
library(patchwork)
datos_farmacias <- read_excel("datos_farmacias.xlsx")
datos_viscosidad <- read_excel("datos_viscosidad.xlsx")
# Gráfico de ventas
g1 <- datos_farmacias %>%
ggplot(aes(x = semana, y = ventas)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
labs(
title = "Serie temporal de ventas",
x = expression("Semana (" * t * ")"),
y = expression(y[t])
) +
theme_classic()
# Gráfico de viscosidad
g2 <- datos_viscosidad %>%
ggplot(aes(x = t, y = viscosidad)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
labs(
title = "Serie temporal de viscosidad",
x = expression(t),
y = expression(cP)
) +
theme_classic()
g1g2Obsérvese que ambas series temporales parecen fluctuar alrededor de un nivel fijo. De acuerdo con la definición presentada anteriormente, esta es una característica de las series temporales estacionarias.
Por el contrario, los datos del precio de las acciones de Whole Foods Market, tienden a fluctuar de manera errática sin mostrar un nivel fijo evidente. Este comportamiento es característico de una serie temporal no estacionaria. Como se muestra a continuación:
library(readxl)
library(ggplot2)
datos_acciones %>%
ggplot(aes(x = Dia, y = USD)) +
geom_line(linewidth = 0.8) +
geom_point(size = 1.5) +
labs(
title = "Serie temporal precio de la acción WFMI",
x = expression("(" * t * ")"),
y = expression("USD")
) +
theme_classic()La estacionariedad implica una forma de equilibrio o estabilidad estadística en los datos. En consecuencia, la serie temporal tiene una media constante, definida como se muestra en la Ecuación 7:
\[\begin{align} \mu_y = E[y] = \int_{-\infty}^{\infty} y f(y) dy \end{align} \tag{7}\]
Y una varianza constante definida como se muestra en la Ecuación 8:
\[\begin{align} \sigma_y^2 = Var[y] = \int_{-\infty}^{\infty} (y-\mu_y)^2 f(y) dy \end{align} \tag{8}\]
La media muestral y la varianza muestral son usadas para estimar estos parámetros. Si las observaciones en una serie de tiempo son \(y_{\scriptscriptstyle 1}, y_{\scriptscriptstyle 2},...,y_{\scriptscriptstyle T}\), entonces la media muestral se calcula como se muestra en la Ecuación 9:
\[\begin{align} \bar{y} = \hat{\mu}_y = \frac{1}{T} \sum_{t=1}^T y_{\scriptscriptstyle t} \end{align} \tag{9}\]
Y la varianza muestral se calcula como se muestra en la Ecuación 10:
\[\begin{align} s^2 = \hat{\sigma}_y^2 = \frac{1}{T} \sum_{t=1}^T (y_{\scriptscriptstyle t} - \bar{y})^2 \end{align} \tag{10}\]
Observe que el divisor en la Ecuación 10 \(T\), en lugar del más conocido \(T-1\). Esta es la convención habitual en muchas aplicaciones de series temporales y, dado que \(T\) generalmente no es pequeño, la diferencia entre utilizar \(T\) en lugar de \(T-1\) será mínima.
Analizar la estacionariedad es importante porque permite determinar si las propiedades estadísticas de una serie de tiempo se mantienen estables a lo largo del tiempo. Esto influye directamente en la selección, estimación y validez de los modelos utilizados para analizar y pronosticar los datos.
Construcción de modelos: muchos modelos clásicos de series de tiempo, como ARMA, se formulan bajo el supuesto de estacionariedad. Si la serie no es estacionaria, puede ser necesario transformarla o utilizar modelos específicos, como ARIMA.
Interpretar correctamente la dependencia temporal: la estacionariedad débil implica que la media y la varianza son constantes y que la covarianza depende únicamente del rezago, lo cual facilita el análisis de la autocorrelación.
Determinar las transformaciones necesarias: permite evaluar si conviene diferenciar la serie, eliminar una tendencia determinista o aplicar una diferencia estacional.
Pruebas estadísticas para evaluar la estacionariedad
Existen varias pruebas estadisticas para determinar si una serie de tiempo es estacionaria o presenta características de no estacionariedad. Las más utilizadas son:
- Prueba de Dickey-Fuller aumentada (ADF)
- Prueba de Phillips-Perron (PP)
- Prueba KPSS (Kwiatkowski-Phillips-Schmidt-Shin)
En el análisis de series de tiempo, una raíz unitaria es una característica matemática que indica que una serie es no estacionaria y que sus propiedades estadísticas (como la media y la varianza) cambian a lo largo del tiempo. El término proviene de las raíces de la ecuación característica de un proceso autorregresivo. Si una de esas raíces es numéricamente igual a 1 (la unidad), la serie presenta un comportamiento errático y carece de memoria a corto plazo, lo que significa que los impactos o shocks del pasado no se desvanecen.
El funcionamiento de las pruebas se muestra en la Tabla 1:
| Prueba | Hipótesis nula (\(H_0\)) | Hipótesis alternativa (\(H_1\)) |
|---|---|---|
| Dickey-Fuller aumentada (ADF) | La serie tiene raíz unitaria, por lo que es no estacionaria bajo las especificaciones habituales. | La serie no tiene raíz unitaria. |
| Phillips-Perron (PP) | La serie tiene raíz unitaria. | La serie no tiene raíz unitaria. |
| KPSS | La serie es estacionaria alrededor de una constante o de una tendencia, según el modelo. | La serie no es estacionaria alrededor de esa constante o tendencia. |
La diferencia más importante es que ADF y PP parten de la no estacionariedad como hipótesis nula, mientras que KPSS parte de la estacionariedad. Por eso, utilizar pruebas complementarias permite obtener conclusiones más sólidas.
Para un nivel de significancia \(\alpha =0.05\), las pruebas se analizan como se muestra en la Tabla 2:
| Resultado | Interpretación |
|---|---|
| ADF: \(p-value < 0.05\) | Se rechaza la hipótesis de raíz unitaria; hay evidencia de estacionariedad respecto de la especificación utilizada. |
| ADF: \(p-value \geq 0.05\) | No se rechaza la hipótesis de raíz unitaria; no hay evidencia suficiente para descartar la no estacionariedad. |
| KPSS: \(p-value < 0.05\) | Se rechaza la hipótesis de estacionariedad. |
| KPSS: \(p-value \geq 0.05\) | No se rechaza la hipótesis de estacionariedad. |
Es recomendable interpretar conjuntamente ambas pruebas: - ADF rechaza y KPSS no rechaza: evidencia compatible con estacionariedad. - ADF no rechaza y KPSS rechaza: evidencia compatible con no estacionariedad. - Ambas rechazan o ambas no rechazan: el diagnóstico es ambiguo y requiere examinar la tendencia, posibles cambios estructurales y la especificación de las pruebas.
No rechazar una hipótesis nula no demuestra que esta sea verdadera.
Para los datos sobre Ventas de productos farmaceúticos las pruebas se haría en R de la siguiente manera:
#Datos
datos_farmacias <- read_excel("datos_farmacias.xlsx")
#Paquete necesario
library(tseries)
#Datos de serie de tiempo
y <- na.omit(datos_farmacias$ventas)
# Prueba Dickey-Fuller aumentada
adf.test(y)
Augmented Dickey-Fuller Test
data: y
Dickey-Fuller = -6.2859, Lag order = 4, p-value = 0.01
alternative hypothesis: stationary
# Prueba Phillips-Perron
pp.test(y)
Phillips-Perron Unit Root Test
data: y
Dickey-Fuller Z(alpha) = -93.452, Truncation lag parameter = 4, p-value
= 0.01
alternative hypothesis: stationary
# Prueba KPSS: estacionariedad alrededor de una constante
kpss.test(y, null = "Level")
KPSS Test for Level Stationarity
data: y
KPSS Level = 0.054387, Truncation lag parameter = 4, p-value = 0.1
# KPSS: estacionariedad alrededor de una tendencia
kpss.test(y, null = "Trend")
KPSS Test for Trend Stationarity
data: y
KPSS Trend = 0.04624, Truncation lag parameter = 4, p-value = 0.1
Los resultados se resumen en la Tabla 3:
| Prueba | Estadístico | \(p-value\) | Decisión |
|---|---|---|---|
| ADF | \(-6.2859\) | \(0.01\) | Rechazar \(H_0\) |
| Phillips-Perron | \(-93.452\) | \(0.01\) | Rechazar \(H_0\) |
| KPSS, nivel | \(0.054387\) | \(0.10\) | No rechazar \(H_0\) |
| KPSS, tendencia | \(0.04624\) | \(0.10\) | No rechazar \(H_0\) |
ADF y PP: ambas pruebas tienen como \(H_0\) la presencia de una raíz unitaria. En los dos casos, el \(p-value\) reportado es inferior a \(0.05\), por lo que se rechaza \(H_0\). Existe evidencia estadística contra la presencia de una raíz unitaria. La prueba considera a la serie de tiempo estacioanria.
KPSS para nivel: \(H_0\) establece que la serie es estacionaria alrededor de una constante. Como \(p-value=0.10 \nless \alpha= 0.05\), no se rechaza \(H_0\). Esto es compatible con una serie estacionaria en nivel, es decir, con una media constante.
KPSS para tendencia: \(H_0\) establece que la serie es estacionaria alrededor de una tendencia determinista. Como \(p-value \nless \alpha=0.05\), tampoco se rechaza \(H_0\). Esto también es compatible con la estacionariedad alrededor de una tendencia.
En caso de no ser estacionaria, las series temporales se suelen diferenciar, especialmente si presenta una tendencia estocástica o una raíz unitaria. A continuación se muestra como se haría en R.
La diferencia se define como:
\[ \Delta y_{\scriptscriptstyle t} = y_{\scriptscriptstyle t} - y_{\scriptscriptstyle t-1} \]
# Primera diferencia
dy <- diff(y)
# Evaluar estacionariedad
library(tseries)
adf.test(dy)
kpss.test(dy, null = "Level")Funciones de autocovarianza y autocorrelación
Si una serie de tiempo es estacionaria, esto significa que la distribución de probabilidad conjunta de dos observaciones cualquiera, por ejemplo, \(y_{\scriptscriptstyle t}\) y \(y_{\scriptscriptstyle t+k}\), es la misma para cualquier par de períodos \(t\) y \(t+k\) separados por un mismo intervalo \(k\).
Se puede obtener información útil sobre esta distribución conjunta y, por tanto, sobre la naturaleza de la serie temporal, mediante un diagrama de dispersión de todos los pares de datos \(y_{\scriptscriptstyle t}\), \(y_{\scriptscriptstyle t+k}\) separados por el mismo intervalo \(k\). Este intervalo se denomina rezago (lag).