#install.packages("readxl")
#install.packages("forecast")

library(readxl)
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(lubridate)
## 
## Adjuntando el paquete: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(ggplot2)
library(forecast)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo

3.1 Limpieza y procesamiento de los datos

El proceso comienza con la importación y preparación de los datos desde un archivo Excel. Se realizan tareas de limpieza, como la eliminación de caracteres especiales en la columna de costos y la conversión de la fecha de transacción al formato adecuado. Finalmente, se eliminan las filas con valores faltantes en la columna de costos.

Para facilitar el análisis de la estacionalidad, se crea una columna “Mes” a partir de las fechas de transacción.

datos <- read_excel("C:/Users/Windows/Documents/maestria Ciencia de datos/series de tiempo/entregas/MUESTRA SERIE TIEMPO.xlsX", col_types = c("numeric", "numeric", "date", "numeric", "text", "numeric", "text", "numeric", "text", "numeric"))



# Agregar una columna de mes
datos <- datos %>% mutate(Mes = month(transaction_date, label = TRUE, abbr = TRUE))


# Limpiar y transformar los datos
datos <- datos %>%
  mutate(cost = as.numeric(gsub("[\\$, ]", "", cost)), # Elimina $, espacios y comas de 'cost' y lo convierte a numérico
         transaction_date = ymd(transaction_date)) %>%
  filter(!is.na(cost))  # Elimina filas con costos NA (Producto 23)

# 3.2 Análisis con Promedio Móvil:

Se crea una serie de tiempo (ventas_ts) a partir de las ventas diarias totales. Para suavizar la serie y visualizar tendencias, se calcula el promedio móvil con ventanas de 7 y 30 días. La gráfica resultante “Ventas Diarias Totales y Promedio Móvil” muestra la serie original junto con los promedios móviles. Se observa que el promedio móvil de 30 días suaviza aún más la serie, mostrando con mayor claridad las tendencias a largo plazo y minimizando las fluctuaciones diarias. El promedio móvil de 7 días, por otro lado, permite observar patrones semanales o de corto plazo.

# Promedio móvil
# Crear una serie de tiempo para las ventas diarias totales
ventas_ts <- ts(datos %>% group_by(transaction_date) %>% summarise(VentasTotales = sum(cost)) %>% pull(VentasTotales), frequency = 365)


# Calcular el promedio móvil (ejemplo con ventana de 7 días y 30 días)
ventas_ma7 <- ma(ventas_ts, order = 7)
ventas_ma30 <- ma(ventas_ts, order = 30)


# Graficar la serie de tiempo y el promedio móvil
autoplot(ventas_ts) +
  autolayer(ventas_ma7, series="Promedio Móvil 7 días") +
  autolayer(ventas_ma30, series = "Promedio Móvil 30 días")+
  ggtitle("Ventas Diarias Totales y Promedio Móvil") +
  xlab("Fecha") + ylab("Ventas")
## Warning: Removed 6 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 30 rows containing missing values or values outside the scale range
## (`geom_line()`).

3.3 Análisis de Rezagos:

Se calcula el rezago de las ventas con 1 y 7 días para explorar la autocorrelación en la serie. Estos rezagos se visualizan en la gráfica “Ventas Diarias Totales y Rezagos”, que permite observar la relación entre las ventas de un día y las ventas de uno o siete días anteriores. Esta información es relevante para entender la dependencia temporal de las ventas y puede ser útil en modelos predictivos.

# 2. Rezagos (lags)
# Calcular el rezago de las ventas (ejemplo con 1 y 7 días de rezago)
ventas_lag1 <- lag(as.numeric(ventas_ts), 1)

ventas_lag7 <- lag(as.numeric(ventas_ts), 7)


# Crear el data.frame con los vectores numéricos
df_lags <- data.frame(Fecha = time(ventas_ts),
                     cost = ventas_ts,
                     Lag1 = ventas_lag1,
                     Lag7 = ventas_lag7)


# Graficar la serie y los rezagos
ggplot(df_lags, aes(x = Fecha)) +
  geom_line(aes(y = cost, color = "cost")) +
  geom_line(aes(y = Lag1, color = "Lag 1 día")) +
  geom_line(aes(y = Lag7, color = "Lag 7 días")) +
  ggtitle("Ventas Diarias Totales y Rezagos") +
  xlab("Fecha") + ylab("cost") +
  scale_color_manual(values = c("cost" = "blue", "Lag 1 día" = "red", "Lag 7 días" = "green"))
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 7 rows containing missing values or values outside the scale range
## (`geom_line()`).

#3.4 Análisis de Estacionalidad (Descomposición):

Para analizar la estacionalidad, se utiliza la función decompose que descompone la serie de tiempo en sus componentes: tendencia, estacionalidad y residuos. La gráfica resultante “Descomposición de la serie de tiempo de Ventas” muestra cada componente por separado. Se observa la tendencia general de las ventas a lo largo del tiempo, así como un patrón estacional recurrente. El componente de residuos representa la variabilidad que no se explica por la tendencia ni la estacionalidad.

# 3. Estacionalidad (usando descomposición)

ventas_decomp <- decompose(ventas_ts)

autoplot(ventas_decomp) + ggtitle("Descomposición de la serie de tiempo de Ventas")

3.5 Análisis de Estacionalidad (Promedio Mensual):

Para una visión más clara de la estacionalidad, se agrega un análisis de las ventas totales mensuales. La gráfica “Ventas Totales Mensuales” muestra las ventas agregadas por mes. Esta visualización permite identificar patrones estacionales a lo largo del año, como picos o valles de ventas en determinados meses. La configuración del eje x con intervalos de un mes y etiquetas que indican el mes y el año facilita la interpretación de la estacionalidad en la serie.

# Análisis con promedio mensual para ver la estacionalidad
ventas_mensual <- datos %>%
  group_by(Mes, transaction_date = floor_date(transaction_date, "month")) %>% # Agrupa por mes y primer día del mes.
  summarise(VentasTotales = sum(cost))
## `summarise()` has grouped output by 'Mes'. You can override using the `.groups`
## argument.
ggplot(ventas_mensual, aes(x = transaction_date, y = VentasTotales)) +
  geom_line() +
  ggtitle("Ventas Totales Mensuales") +
  xlab("Fecha") + ylab("Ventas")+
  scale_x_date(date_breaks = "1 month", date_labels = "%b %Y") # Ajusta etiquetas del eje x

3.6 Conclusión En resumen, este capítulo realiza un análisis exploratorio de las ventas utilizando diferentes técnicas de series de tiempo. El uso de promedios móviles, rezagos y descomposición permite identificar tendencias, patrones estacionales y autocorrelación en los datos, sentando las bases para un análisis más profundo y la construcción de modelos predictivos en capítulos posteriores.

AVANCE 4

Introducción

En este capítulo se seguirá con pasos esenciales en el análisis de las series de tiempo de la variable #ventas totales mensuales . En primer lugar, se procederá a diferenciar la serie, si es necesario para hacer que la serie sea estacionaria.

A continuación, se llevará a cabo un análisis de rezagos utilizando las funciones de autocorrelación (ACF) y autocorrelación parcial (PACF), que son herramientas para identificar la estructura de dependencia temporal en los datos.

Posteriormente, se descompondrá la serie de tiempo para examinar sus componentes fundamentales: tendencia, estacionalidad y ruido (cómo ya se adelantó en el capítulo anterior). Esto nos ayudará a comprender mejor el comportamiento subyacente de las compras a lo largo del tiempo. Además, se detectar cambios en la media, lo cual es crucial para identificar períodos de crecimiento o declive en las compras.

Una vez que se haya establecido una comprensión clara de la serie, se identificará el modelo ARIMA más adecuado para capturar la dinámica de la serie. Finalmente, con el modelo ARIMA validado, se realizará la predicción de futuras compras, lo que permitirá a las empresas anticiparse a la demanda y tomar decisiones informadas.

4.1 Descomposición y estacionalidad

library(ggplot2)

ventas_mes <- ts(ventas_mensual$VentasTotales, start = c(2017, 1), frequency = 12)

descomp_ventas_mes <- decompose(ventas_mes)

plot(descomp_ventas_mes) 

  1. Tendencia

La línea de tendencia muestra que la serie de ventas mensual es ascendente a lo largo del tiempo, es decir, que se observa un aumento sostenido de las ventas durante el periodo de tiempo estudiado

  1. Estacionalidad

La estacionalidad describe un patrón al final y al inicio del año y en los meses de mitad de año, se ven dos picos de venta en estos periodos siendo enero y diciembre el mayor volumen de ventas en el trasncurso de cada año.

  1. Residuales

La componente residual muestra la variación en las ventas que no se explica por la tendencia o la estacionalidad. Se considera el “ruido” en la serie de tiempo. El que se observa, parece ser un comportamiento aleatorio en los errores.

Prueba de estacionalidad

#install.packages("tseries")
library(tseries)

adf_test <- adf.test(ventas_mes)
## Warning in adf.test(ventas_mes): p-value smaller than printed p-value
print(adf_test)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  ventas_mes
## Dickey-Fuller = -5.3651, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary

al aplicar la prueba Dickey fuller, el p-valor = 0.01. Un p-valor menor a 0.05 sugiere que la serie de tiempo ventas_mes es estacionaria. Una serie estacionaria no necesitara diferenciación en el componente autorregresivo.

4.2 Funciones ACF y PACF

# Gráfica de ACF
par(mfrow = c(1, 2))  # Configura el área de gráficos para mostrar 2 gráficas en una fila
acf(ventas_mes, main = "ACF de la Serie ventas_mes")

# Gráfica de PACF
pacf(ventas_mes, main = "PACF de la Serie ventas_mes")

par(mfrow = c(1, 1))  # Restaura la configuración a un solo gráfico

Los gráficos ACF y PACF NO señalan componenetes autoregresivos ni de medias movil sobre la serie de ventas mensuales, lo que indica que un modelo sencillo de ARIMA(0,0,0) podría ajustarse a los datos

4.3 Modelo ARIMA

#install.packages("tseries")
library(tseries)
#install.packages("forecast")
library(forecast)
modelo_arima <- auto.arima(ventas_mes)
summary(modelo_arima)
## Series: ventas_mes 
## ARIMA(0,0,1) with non-zero mean 
## 
## Coefficients:
##          ma1        mean
##       0.2486  2469011.71
## s.e.  0.1467    95220.84
## 
## sigma^2 = 2.937e+11:  log likelihood = -700.86
## AIC=1407.71   AICc=1408.26   BIC=1413.33
## 
## Training set error measures:
##                    ME     RMSE      MAE       MPE     MAPE      MASE
## Training set 1942.299 530494.4 461796.1 -4.898511 19.90717 0.7047782
##                     ACF1
## Training set -0.01150845

Se ha obtenido un modelo ARIMA(0,0,1), es decir, un modelo de media móvil de orden 1, MA(1)) para la serie de tiempo ventas_mes proporciona una serie de información valiosa sobre el ajuste del modelo.

ARIMA(0,0,1) significa que el modelo no tiene componentes autorregresivos (AR) ni diferencias (d), y tiene un componente de media móvil de orden 1 (MA(1)). Con media no cero indica que el modelo incluye una constante en la serie.

Coeficientes del Modelo ma1 = 0.2486: Este es el coeficiente de la parte MA(1). Un valor positivo indica que un aumento en el error de predicción en un periodo se asocia con un aumento en el valor predicho en el siguiente periodo, pero en una proporción del 24.86%.

mean = 2469011.71: Este es el valor medio de la serie. Esto sugiere que, en promedio, las ventas mensuales son aproximadamente 2,469,012.

Punto de cambio

#detectar punto de cambio en la media

# Cargar librerías necesarias
library(changepoint)
## Cargando paquete requerido: zoo
## 
## Adjuntando el paquete: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## Successfully loaded changepoint package version 2.2.4
##  See NEWS for details of changes.
# Aplicar cpt.mean
cambio_media <- cpt.mean(ventas_mes, method = "PELT")

# Resumen de los resultados
summary(cambio_media)
## Created Using changepoint version 2.2.4 
## Changepoint type      : Change in mean 
## Method of analysis    : PELT 
## Test Statistic  : Normal 
## Type of penalty       : MBIC with value, 11.6136 
## Minimum Segment Length : 1 
## Maximum no. of cpts   : Inf 
## Number of changepoints: 47
# Graficar los resultados
plot(cambio_media, main = "Detección de Cambio en la Media")

4.4 Validación del modelo

Prueba de media 0 de los errores

##Prueba de media de los residuos

residuos <- residuals(modelo_arima)

# Realizar la prueba t de Student
resultado_t <- t.test(residuos, mu = 0)
print(resultado_t)
## 
##  One Sample t-test
## 
## data:  residuos
## t = 0.025101, df = 47, p-value = 0.9801
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -153726.3  157610.9
## sample estimates:
## mean of x 
##  1942.299
# Realizar la prueba de Wilcoxon
resultado_wilcox <- wilcox.test(residuos, mu = 0)
print(resultado_wilcox)
## 
##  Wilcoxon signed rank exact test
## 
## data:  residuos
## V = 583, p-value = 0.9635
## alternative hypothesis: true location is not equal to 0

La prueba t-test indica que la media de los residuos es estadísticamente no diferente de cero, lo cual significa que el modelo ARIMA está capturando adecuadamente la estructura de la serie de tiempo.

La prueba de Wilcoxon refuerza la conclusión de la prueba t, indicando que no hay evidencia significativa para afirmar que la media de los residuos son diferentes de cero.

##Independencia de los residuos

# Instalar el paquete si no está instalado
#install.packages("lmtest")


# Cargar el paquete
library(lmtest)


# Crear un modelo lineal de los residuos
modelo_lineal <- lm(residuos ~ time(residuos))

# Realizar la prueba de Durbin-Watson
library(lmtest)
dw_resultado <- dwtest(modelo_lineal)

# Mostrar los resultados
print(dw_resultado)
## 
##  Durbin-Watson test
## 
## data:  modelo_lineal
## DW = 2.1253, p-value = 0.6119
## alternative hypothesis: true autocorrelation is greater than 0
# Graficar ACF de los residuos
acf(residuos, main = "ACF de los Residuos del Modelo ARIMA")

Cuando los valores del ACF están dentro del intervalo de confianza (usualmente el 95%), significa que no hay evidencia de autocorrelación significativa en los residuos. Esto sugiere que los residuos son aproximadamente aleatorios.

4.5 Pronóstico

library(forecast)

library(zoo)

#install.packages("ggplot2")
library(ggplot2)

# Hacer la predicción para los próximos 6 meses
prediccion <- forecast(modelo_arima, h = 6)

# Ver los resultados de la predicción
print(prediccion)
##          Point Forecast   Lo 80   Hi 80   Lo 95   Hi 95
## Jan 2021        2565147 1870669 3259625 1503034 3627260
## Feb 2021        2469012 1753388 3184635 1374560 3563464
## Mar 2021        2469012 1753388 3184635 1374560 3563464
## Apr 2021        2469012 1753388 3184635 1374560 3563464
## May 2021        2469012 1753388 3184635 1374560 3563464
## Jun 2021        2469012 1753388 3184635 1374560 3563464
# Graficar la serie original y la predicción
autoplot(prediccion) +
  ggtitle("Predicción de ventas_mes para los próximos 6 meses") +
  xlab("Fecha") + ylab("ventas_mes")

Habíamos anticipado que el modelo ARIMA (0,0,1) predeciría la variable sobre el valor promedio de las ventas, lo cual se refleja en el gráfico del pronóstico

4.6 Prueba de otro abordaje: ventas diarias

Intentando otro abordaje del análisis se repetirán los pasos anteriores de análisis sobre la variable ventas diarias para conocer si esta variable permite aplicar otro tipo de trasnformaciones o modelos:

Crear variable ventas_dia

#install.packages("dplyr")
library(dplyr)

ventas_diarias <- datos %>%
  group_by(transaction_date) %>%
  summarise(ventas_dia = sum(cost))

# Cargar ggplot2
library(ggplot2)
# Ordenar por fecha
ventas_diarias <- ventas_diarias %>% arrange(transaction_date)

# Crear la serie de tiempo
ventas_ts <- ts(ventas_diarias$ventas_dia, 
                start = c(as.numeric(format(min(ventas_diarias$transaction_date), "%Y")), 
                          as.numeric(format(min(ventas_diarias$transaction_date), "%j"))), 
                frequency = 365)

# Graficar la serie de tiempo
plot(ventas_ts, main = "Serie de Tiempo de Ventas Diarias", ylab = "Ventas", xlab = "Fecha")

Funciones ACF y PACF de ventas_dia

# Gráfica de ACF
par(mfrow = c(1, 2))  # Configura el área de gráficos para mostrar 2 gráficas en una fila
acf(ventas_ts, main = "ACF de la Serie ventas_dia")

# Gráfica de PACF
pacf(ventas_ts, main = "PACF de la Serie ventas_dia")

par(mfrow = c(1, 1))  # Restaura la configuración a un solo gráfico

#modelo ARIMA ventas_dia

library(forecast)
modelo_arima_dia <- auto.arima(ventas_ts)
summary(modelo_arima_dia)
## Series: ventas_ts 
## ARIMA(0,0,0) with non-zero mean 
## 
## Coefficients:
##             mean
##       136702.422
## s.e.    3246.091
## 
## sigma^2 = 9.149e+09:  log likelihood = -11172.88
## AIC=22349.75   AICc=22349.77   BIC=22359.28
## 
## Training set error measures:
##                        ME     RMSE      MAE       MPE     MAPE      MASE
## Training set 1.188283e-10 95595.92 74101.14 -117.4418 144.8628 0.7065294
##                     ACF1
## Training set 0.006163691
prediccion_dia <- forecast(modelo_arima_dia, h = 6)

# Graficar la predicción
plot(prediccion_dia, main = "Predicción de Ventas para los Próximos 6 Días",
     ylab = "Ventas", xlab = "Fecha")

print(prediccion_dia)
##           Point Forecast   Lo 80    Hi 80     Lo 95    Hi 95
## 2019.3863       136702.4 14120.6 259284.2 -50770.29 324175.1
## 2019.3890       136702.4 14120.6 259284.2 -50770.29 324175.1
## 2019.3918       136702.4 14120.6 259284.2 -50770.29 324175.1
## 2019.3945       136702.4 14120.6 259284.2 -50770.29 324175.1
## 2019.3973       136702.4 14120.6 259284.2 -50770.29 324175.1
## 2019.4000       136702.4 14120.6 259284.2 -50770.29 324175.1

Al hacer un análisis de las ventas diarias se llega a la misma conclusión de las ventas mensuales, la mejor predicción de esta serie de tiempo es su promedio histórico

Conclusión

El objetivo de este avance fue descomponer la serie temporal de la variable de ventas con el fin de aplicar diferencias u otras transformaciones necesarias para ajustar un modelo ARIMA adecuado. En una primera fase de análisis sobre las ventas mensuales, se observó que la serie era estacionaria, por lo que no requirió diferenciación. Los gráficos de autocorrelación (ACF) y autocorrelación parcial (PACF) indicaron la ausencia de componentes autoregresivos o de media móvil significativos, y el mejor modelo identificado fue un ARIMA(0,0,1). Este modelo cumplió con los criterios de validación, confirmando una media cercana a cero y la independencia en los residuos. El pronóstico generado sugirió que las ventas futuras se mantendrán en un valor promedio similar al histórico de alrededor de 2.500.000 por mes.

En un segundo ejercicio, se analizó la serie de ventas diarias, cuyos resultados corroboraron que el mejor modelo proyecta las ventas diarias en torno al promedio histórico. En conjunto, estos análisis refuerzan que el comportamiento de las ventas es consistente y no presenta variaciones significativas más allá de su media histórica, lo que permite utilizar el modelo como una herramienta confiable para prever el comportamiento de ventas en el corto plazo.