El análisis de una serie de tiempo es proceso que tiene el fin de encontrar un patrón o tendencia de los datos de la serie a analizar, en este caso nosotras analizaremos una serie de tiempo del precio de las acciones de Netflix en un periodo de 5 años (del 5 de febrero de 2018 al 5 de febrero de 2022), obtenida de la siguiente página https://www.kaggle.com/datasets/jainilcoder/netflix-stock-price-prediction, esto con el propósito de predecir el precio de dichas acciones a 30 días dado que los precios de las acciones son muy volátiles pues dependen del mercado es muy difícil de predecir correctamente a largo plazo.
El propósito de nuestro análisis es ayudar a los inversionistas (que son los principales interesados en dichas acciones) a tomar una decisión correcta para que puedan tener una inversión buena y exitosa, lo cual basados en estos datos al final podremos afirmar o refutar nuestra hipótesis, la cual es que el precio de las acciones de Netflix es una buena inversión.
library(readxl) ## Leer archivos de Excel
library(fpp3) ## Librería del libro de ST
## ── Attaching packages ────────────────────────────────────────────── fpp3 0.5 ──
## ✔ tibble 3.2.1 ✔ tsibble 1.1.3
## ✔ dplyr 1.1.3 ✔ tsibbledata 0.4.1
## ✔ tidyr 1.3.0 ✔ feasts 0.3.1
## ✔ lubridate 1.9.3 ✔ fable 0.3.3
## ✔ ggplot2 3.4.4 ✔ fabletools 0.3.4
## ── Conflicts ───────────────────────────────────────────────── fpp3_conflicts ──
## ✖ lubridate::date() masks base::date()
## ✖ dplyr::filter() masks stats::filter()
## ✖ tsibble::intersect() masks base::intersect()
## ✖ tsibble::interval() masks lubridate::interval()
## ✖ dplyr::lag() masks stats::lag()
## ✖ tsibble::setdiff() masks base::setdiff()
## ✖ tsibble::union() masks base::union()
library(forecast) ## Centrado de la serie de tiempo
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(zoo) ## Lo usamos para poder dividir los trimestres
##
## Attaching package: 'zoo'
## The following object is masked from 'package:tsibble':
##
## index
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(TSstudio) ## Para el análisis descriptivo y predictivo de datos de series temporales
library(fpp2)
## ── Attaching packages ────────────────────────────────────────────── fpp2 2.5 ──
## ✔ fma 2.5 ✔ expsmooth 2.3
##
##
## Attaching package: 'fpp2'
## The following object is masked from 'package:fpp3':
##
## insurance
library(readr)
# Instalar las bibliotecas si aún no están instaladas
# install.packages("xts")
# install.packages("ggplot2")
# Cargar las bibliotecas
library(xts)
##
## ######################### Warning from 'xts' package ##########################
## # #
## # The dplyr lag() function breaks how base R's lag() function is supposed to #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or #
## # source() into this session won't work correctly. #
## # #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop #
## # dplyr from breaking base R's lag() function. #
## # #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning. #
## # #
## ###############################################################################
##
## Attaching package: 'xts'
## The following objects are masked from 'package:dplyr':
##
## first, last
library(ggplot2)
En esta parte seguiremos una serie de pasos para saber si nuestra hipótesis es correcta o no,en general los análisis de series de tiempo tienen los siguientes tres pasos:
Dentro del análisis exploratorio transformaremos nuestros datos a una serie de tiempo para poner descomponer nuestra serie donde podemos ver en los componentes: tendencia, estacional, cíclico y aleatorio.
NFLX <- read.csv("NFLX.csv")
# Install and load the lubridate package
# install.packages("lubridate")
library(lubridate)
NFLX <- NFLX |>select(Date,Price)
# Crear una secuencia de fechas basada en el número de filas
NFLX$Date <- seq(as.Date("2018-02-05"), by = "days", length.out = nrow(NFLX))
# Convertir la columna "Date" a formato de fecha con lubridate
NFLX$Date <- lubridate::ymd(NFLX$Date)
# Verificar la clase de la columna "Date" después de la conversión
print(class(NFLX$Date))
## [1] "Date"
head(NFLX)
## Date Price
## 1 2018-02-05 254.26
## 2 2018-02-06 265.72
## 3 2018-02-07 264.56
## 4 2018-02-08 250.10
## 5 2018-02-09 249.47
## 6 2018-02-10 257.95
# Graficar la serie de tiempo
library(ggplot2)
ggplot(NFLX, aes(x = Date, y = Price)) +
geom_line() +
labs(title = "Serie Temporal de NFLX",
x = "Fecha",
y = "Precio")
### 2.1.1 Descomponer la serie
# Crear una serie de tiempo
ts_data <- ts(NFLX$Price, frequency = 365) # Ya que es una frecuencia diaria
datoprice <- as_tsibble(NFLX, index = "Date")
datoprice
## # A tsibble: 1,009 x 2 [1D]
## Date Price
## <date> <dbl>
## 1 2018-02-05 254.
## 2 2018-02-06 266.
## 3 2018-02-07 265.
## 4 2018-02-08 250.
## 5 2018-02-09 249.
## 6 2018-02-10 258.
## 7 2018-02-11 258.
## 8 2018-02-12 266
## 9 2018-02-13 280.
## 10 2018-02-14 279.
## # ℹ 999 more rows
# Descomponer la serie temporal
decomposition <- decompose(ts_data)
# Graficar la descomposición
par(mfrow = c(3, 1))
plot(decomposition)
El elemento estacional es un componente de la serie que recoge las oscilaciones que se producen en períodos iguales o inferiores a un año y que se repiten de forma regular en los diferentes años.
Si se considera el año como período marco o de repetición pueden observarse las fluctuaciones de la magnitud a lo largo de sus meses o de sus trimestres, cuatrimestres, etc. El origen de las variaciones estacionales (componente estacional) puede estar en factores físico-naturales como son las estaciones climatológicas o en factores culturales o de tradición: fiestas navideñas, vacaciones, horarios comerciales, etc.
En este caso vamos a estudiar la estacionalidad de nuestra serie de tiempo por medio de la descomposición que ya hicimos anteriormente, podemos observar que presenta un patrón, el cual nos hace ver que nuestra serie es estacional.
# Obtener la componente estacional
seasonal_component <- decomposition$seasonal
La tendencia secular o tendencia a largo plazo de una serie es por lo común el resultado de factores a largo plazo.Las tendencias a largo plazo se ajustan a diversos esquemas. Algunas se mueven continuamente hacía arriba, otras declinan, y otras más permanecen igual en un cierto período o intervalo de tiempo.
# Obtener la componente de tendencia
trend_component <- decomposition$trend
Las Series Temporales tienen como objetivo el de descomponer la serie observadas en dos partes: una de las partes es la que depende del pasado, la otra es la parte impredecible.
Un Ruido Blanco es una serie tal que su media es cero, la varianza es constante y es incorrelacionada.
#NOTA:Esta grafico lo podemos quitar por si quieres
# Obtener el ruido blanco (residuos)
residuals <- ts_data - trend_component - seasonal_component
# Graficar el ruido blanco
plot(residuals, main = "Ruido Blanco de la Serie Temporal", xlab = "Fecha", ylab = "Residuos")
Una forma de corregir la no estacionariedad es por el método de la raíz unitaria ya que esta prueba se usa para descubrir la primera diferencia o regresión que se debe usar para hacerla estacionaria.
# Cargar el paquete tseries
library(tseries)
# Realizar la prueba de Dickey-Fuller
adf_result <- adf.test(ts_data)
# Imprimir el resultado
print(adf_result)
##
## Augmented Dickey-Fuller Test
##
## data: ts_data
## Dickey-Fuller = -1.7847, Lag order = 10, p-value = 0.6695
## alternative hypothesis: stationary
Como podemos ver, nuestra serie de tiempo cumple con la estacionariedad por la prueba de raíz unitaria de Dickey-Fuller.
Ahora desestacionalizaremos los precios y así tener mejores datos para poder pronósticar a 30 días.
DesPrice <- datoprice |>
model(stl = STL(Price))
components(DesPrice)
## # A dable: 1,009 x 8 [1D]
## # Key: .model [1]
## # : Price = trend + season_year + season_week + remainder
## .model Date Price trend season_week season_year remainder season_adjust
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 stl 2018-02-05 254. 350. 1.34 -35.6 -60.9 289.
## 2 stl 2018-02-06 266. 349. 0.529 -31.6 -52.6 297.
## 3 stl 2018-02-07 265. 349. 3.42 -28.6 -59.6 290.
## 4 stl 2018-02-08 250. 349. -3.02 -34.0 -62.2 287.
## 5 stl 2018-02-09 249. 349. -3.89 -29.7 -66.2 283.
## 6 stl 2018-02-10 258. 349. -1.18 -28.7 -61.3 288.
## 7 stl 2018-02-11 258. 349. 2.72 -29.2 -64.3 285.
## 8 stl 2018-02-12 266 349. 1.45 -35.9 -48.6 300.
## 9 stl 2018-02-13 280. 349. 0.394 -32.3 -36.8 312.
## 10 stl 2018-02-14 279. 349. 3.43 -36.1 -37.7 311.
## # ℹ 999 more rows
Usaremos los datos desestacionalizados es decir la columna Season_adjust para tener menos variabilidad en la información.
ajustprice <- components(DesPrice)$season_adjust
trendprice <- components(DesPrice)$trend
fecha <- components(DesPrice)$Date
Fecha<-as.data.frame.Date(fecha)
datosajustados <- cbind(Fecha,ajustprice)
datosajustados1 <- as_tsibble(datosajustados, index = fecha)
datosajustados1
## # A tsibble: 1,009 x 2 [1D]
## fecha ajustprice
## <date> <dbl>
## 1 2018-02-05 289.
## 2 2018-02-06 297.
## 3 2018-02-07 290.
## 4 2018-02-08 287.
## 5 2018-02-09 283.
## 6 2018-02-10 288.
## 7 2018-02-11 285.
## 8 2018-02-12 300.
## 9 2018-02-13 312.
## 10 2018-02-14 311.
## # ℹ 999 more rows
Observamos que los datos llegan al 31 de octubre del 2020 y estamos proyectando a 30 días a futuro, es decir hasta el 30 de noviembre del 2020 con el modelo SNAIVE.
# Generamos el modelo de regresión múltiple
datosajustados1|>
model(SNAIVE(ajustprice)) |>
forecast(h=30) |>
autoplot(datosajustados1) +
labs(y = "Precios ajustados",
title = "Netflix")
datosajustados1
## # A tsibble: 1,009 x 2 [1D]
## fecha ajustprice
## <date> <dbl>
## 1 2018-02-05 289.
## 2 2018-02-06 297.
## 3 2018-02-07 290.
## 4 2018-02-08 287.
## 5 2018-02-09 283.
## 6 2018-02-10 288.
## 7 2018-02-11 285.
## 8 2018-02-12 300.
## 9 2018-02-13 312.
## 10 2018-02-14 311.
## # ℹ 999 more rows
Ocuparemos el modelo ARIMA pues proporcionan métodos más sofisticados para crear modelos de los componentes de tendencia y estacionales que los modelos de suavizado exponencial y disponen de la ventaja añadida de poder incluir variables predictoras en el modelo.
fit <- datosajustados1 |>
model(ARIMA(ajustprice))
report(fit)
## Series: ajustprice
## Model: ARIMA(2,1,2)(0,0,2)[7]
##
## Coefficients:
## ar1 ar2 ma1 ma2 sma1 sma2
## 0.0677 0.8694 -0.0258 -0.7837 -0.3687 -0.2197
## s.e. 0.1034 0.1008 0.1139 0.1065 0.0324 0.0316
##
## sigma^2 estimated as 61.1: log likelihood=-3501.13
## AIC=7016.26 AICc=7016.37 BIC=7050.67
fit |> forecast(h=30) |>
autoplot(datosajustados1) +
labs(y = "Precio de Netflix", title = "Stock de Netflix")
fit |>gg_tsresiduals()
Podemos observar en el gráfico del apartado 2.2.2 “Stock de Netflix” que los precios de la acción se mantienen “estables”, es decir no tienden a una alza tan pronunciada, por lo que se consideraría que por el momento puede ser riesgoso invertir en esta acción, ya que después de la perdida notoria que tuvo en los ultimos días uno podria pensar que ya toco su punto más bajo y ahora subira el precio de la acción por lo que seria conveninete comprar, pero dado el pronóstico con el modelo ARIMA, se visualiza que es probable que siga a la baja, es un riesgo que podemos tomar o no.
Rojas-Jimenez, K. (s/f). Capítulo 8 análisis de series de tiempo. Bookdown.org. Recuperado el 21 de noviembre de 2023, de https://bookdown.org/keilor_rojas/CienciaDatos/an%C3%A1lisis-de-series-de-tiempo.html
Mordán, N. R., & Perfil, V. T. mi. (s/f). Economía Aplicada. Blogspot.com. Recuperado el 21 de noviembre de 2023, de https://betaeconomia.blogspot.com/2020/03/modificando-la-frecuencia-de-una-serie.html
IBM Documentation. (2021, agosto 17). Ibm.com. https://www.ibm.com/docs/es/spss-modeler/saas?topic=series-arima