En la actualidad, el comercio electrónico se ha consolidado como uno de los principales canales de venta para empresas de todos los tamaños, especialmente aquellas dedicadas a nichos específicos del mercado. En este contexto, el análisis de datos históricos de ventas se convierte en una herramienta esencial para comprender el comportamiento de los consumidores, optimizar procesos operativos y mejorar la rentabilidad del negocio.
El presente estudio se basa en el conjunto de datos Online Retail comprende transacciones registradas entre el 1 de diciembre de 2010 y el 9 de diciembre de 2011 en una tienda minorista en línea con sede en el Reino Unido. Esta empresa se dedica a la venta de regalos únicos para distintas ocasiones, y cuenta con una importante base de clientes mayoristas. El análisis de este conjunto de datos busca identificar tendencias y patrones en el comportamiento de los clientes, así como detectar posibles problemáticas que puedan estar afectando el rendimiento del negocio. Con base en estos hallazgos, se pretende proponer soluciones prácticas y generar información útil para la toma de decisiones estratégicas en un entorno digital cada vez más competitivo.
require(sp)
## Loading required package: sp
library(readxl)
Online_Retail <- read_excel("~/Downloads/ESTADISTICA APLICADA /Online Retail.xlsx")
head(Online_Retail)
| InvoiceNo | StockCode | Description | Quantity | InvoiceDate | UnitPrice | CustomerID | Country |
|---|---|---|---|---|---|---|---|
| 536365 | 85123A | WHITE HANGING HEART T-LIGHT HOLDER | 6 | 2010-12-01 08:26:00 | 2.55 | 17850 | United Kingdom |
| 536365 | 71053 | WHITE METAL LANTERN | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom |
| 536365 | 84406B | CREAM CUPID HEARTS COAT HANGER | 8 | 2010-12-01 08:26:00 | 2.75 | 17850 | United Kingdom |
| 536365 | 84029G | KNITTED UNION FLAG HOT WATER BOTTLE | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom |
| 536365 | 84029E | RED WOOLLY HOTTIE WHITE HEART. | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom |
| 536365 | 22752 | SET 7 BABUSHKA NESTING BOXES | 2 | 2010-12-01 08:26:00 | 7.65 | 17850 | United Kingdom |
El comportamiento de las ventas en entornos digitales está sujeto a dinámicas complejas influenciadas por factores estacionales, tendencias de mercado y variables externas. En este contexto, surge la necesidad de implementar metodologías analíticas que permitan descomponer y proyectar los patrones de transacciones comerciales con base en datos históricos registrados en plataformas de venta en línea.
Las empresas de comercio electrónico generan grandes volúmenes de datos transaccionales a lo largo del tiempo. Sin embargo, convertir esos datos en información útil para la toma de decisiones requiere herramientas analíticas adecuadas. El problema estadístico que se plantea en este estudio es el análisis y modelado de series de tiempo con el propósito de entender el comportamiento temporal de las ventas diarias o mensuales y prever su evolución futura.
Esto implica enfrentar desafíos como la estacionalidad de las ventas, los picos de demanda, y la identificación de posibles anomalías que puedan impactar la planificación comercial. Resolver este problema permite anticiparse a periodos de alta o baja demanda, optimizar la gestión del inventario y diseñar campañas de marketing más efectivas.
Desarrollar modelos de series de tiempo que permitan predecir el volumen de ventas de una tienda de comercio electrónico con base en los datos históricos de transacciones. A través de estos modelos, se busca identificar tendencias, patrones estacionales y eventos atípicos, con el fin de mejorar la toma de decisiones en áreas clave como la planificación de inventario, gestión de demanda y estrategia comercial. Este enfoque busca proporcionar una ventaja competitiva al anticipar el comportamiento del mercado y mejorar la eficiencia operativa.
El conjunto de datos Online Retail contiene aproximadamente 541,909 registros distribuidos en 8 variables, que corresponden a transacciones realizadas entre diciembre de 2010 y diciembre de 2011 por una tienda minorista en línea con sede en el Reino Unido. Esta tienda se dedica a la venta de productos de regalo únicos, y atiende tanto a clientes individuales como a mayoristas, con una fuerte concentración de ventas en el mercado británico.
Cada fila representa una línea de detalle dentro de una factura, e incluye información relacionada con el producto vendido, la cantidad, el precio, el cliente y la fecha de compra. Las facturas pueden contener varios productos, por lo que hay múltiples registros con el mismo número de factura (InvoiceNo).
# Cargar librerías necesarias
library(readxl)
library(knitr)
# Leer el archivo Excel (usa la ruta correcta)
Retail <- read_excel("~/Downloads/ESTADISTICA APLICADA /Online Retail.xlsx")
# Crear data frame para almacenar resultados
result <- data.frame(Índice = integer(0), Columna = character(0))
# Recorrer nombres de columnas
for (i in seq_along(colnames(Retail))) {
result <- rbind(result, data.frame(Índice = i, Columna = colnames(Retail)[i]))
}
# Mostrar tabla
kable(result,
col.names = c("Índice", "Columna"),
caption = "Tabla de Índices y Nombres de Columnas",
align = c("c", "l"))
| Índice | Columna |
|---|---|
| 1 | InvoiceNo |
| 2 | StockCode |
| 3 | Description |
| 4 | Quantity |
| 5 | InvoiceDate |
| 6 | UnitPrice |
| 7 | CustomerID |
| 8 | Country |
A continuación vamos a analizar cada variable:
InvoiceNo: Es el número de factura. Es un código único asignado a cada transacción. Como se dijo anteriormente las facturas que comienzan con la letra “C” indican que la transacción fue cancelada o devuelta.
StockCode: Es el código del producto. Es un identificador único para cada artículo en el inventario.
Description: Como su nombre lo indica es la descripción del producto. Indica el nombre o detalles del artículo vendido. Algunos valores están vacíos, lo cual puede dificultar el análisis si no se corrige.
Quantity: Es la cantidad de productos comprados (puede ser negativa, lo que indica una devolución).
InvoiceDate: Fecha y hora en que se realizó la transacción. Es útil para el análisis temporal (tendencias diarias, mensuales, estacionales).
UnitPrice: Es el precio unitario del producto, expresado en libras esterlinas
CustomerID: Es el código único asignado a cada cliente. Algunos registros no tienen este valor (clientes no identificados), lo que puede limitar ciertos análisis como segmentación o fidelización.
Country: Es el país del cliente. Ayuda a identificar el origen geográfico de la compra y a segmentar el mercado por región. El Reino Unido es el país predominante.
A continuacion se hace un resumen estadistico de la informacion
summary(Retail)
## InvoiceNo StockCode Description Quantity
## Length:541909 Length:541909 Length:541909 Min. :-80995.00
## Class :character Class :character Class :character 1st Qu.: 1.00
## Mode :character Mode :character Mode :character Median : 3.00
## Mean : 9.55
## 3rd Qu.: 10.00
## Max. : 80995.00
##
## InvoiceDate UnitPrice CustomerID
## Min. :2010-12-01 08:26:00.00 Min. :-11062.06 Min. :12346
## 1st Qu.:2011-03-28 11:34:00.00 1st Qu.: 1.25 1st Qu.:13953
## Median :2011-07-19 17:17:00.00 Median : 2.08 Median :15152
## Mean :2011-07-04 13:34:57.16 Mean : 4.61 Mean :15288
## 3rd Qu.:2011-10-19 11:27:00.00 3rd Qu.: 4.13 3rd Qu.:16791
## Max. :2011-12-09 12:50:00.00 Max. : 38970.00 Max. :18287
## NA's :135080
## Country
## Length:541909
## Class :character
## Mode :character
##
##
##
##
se pueden observar que antes de aplicar cualquier modelo de series temporales, es imprescindible realizar un proceso de depuración de datos, ya que el conjunto presenta diversos problemas de calidad. Entre los más relevantes se encuentran las facturas canceladas, fácilmente reconocibles porque su número comienza con la letra “C”; los valores negativos en la columna de cantidad, que reflejan devoluciones de productos y deben tratarse adecuadamente para evitar distorsiones en el análisis; los valores faltantes en el identificador del cliente, que dificultan la desagregación de patrones individuales de compra; y los precios unitarios iguales a cero, que pueden indicar errores de registro o promociones mal documentadas. Adicionalmente, es necesario construir nuevas variables temporales a partir de la fecha y hora de la transacción, tales como el mes, el día de la semana o la hora del día, que permiten captar comportamientos cíclicos y estacionales más finos.
A continuacion se realizara una limpieza en la cual se desea eliminar las variables customerID que no tienenen clientes(estan en blanco) , tambien eliminar los precios menores a 0, las devoluciones y cancelaciones de los productos. Tambien se desa calcular el monto total y extraer solamente la fecha de compra del producto sin importar la hora.
library(readxl)
library(dplyr)
##
## Attaching package: '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)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
retail <- read_excel("~/Downloads/ESTADISTICA APLICADA /Online Retail.xlsx")
retail_clean <- retail %>%
filter(!is.na(CustomerID),
Quantity > 0,
UnitPrice > 0,
!grepl("^C", InvoiceNo)) %>%
mutate(TotalSales = Quantity * UnitPrice,
InvoiceDate = as.POSIXct(InvoiceDate),
Date = as.Date(InvoiceDate))
glimpse(retail_clean)
## Rows: 397,884
## Columns: 10
## $ InvoiceNo <chr> "536365", "536365", "536365", "536365", "536365", "536365"…
## $ StockCode <chr> "85123A", "71053", "84406B", "84029G", "84029E", "22752", …
## $ Description <chr> "WHITE HANGING HEART T-LIGHT HOLDER", "WHITE METAL LANTERN…
## $ Quantity <dbl> 6, 6, 8, 6, 6, 2, 6, 6, 6, 32, 6, 6, 8, 6, 6, 3, 2, 3, 3, …
## $ InvoiceDate <dttm> 2010-12-01 08:26:00, 2010-12-01 08:26:00, 2010-12-01 08:2…
## $ UnitPrice <dbl> 2.55, 3.39, 2.75, 3.39, 3.39, 7.65, 4.25, 1.85, 1.85, 1.69…
## $ CustomerID <dbl> 17850, 17850, 17850, 17850, 17850, 17850, 17850, 17850, 17…
## $ Country <chr> "United Kingdom", "United Kingdom", "United Kingdom", "Uni…
## $ TotalSales <dbl> 15.30, 20.34, 22.00, 20.34, 20.34, 15.30, 25.50, 11.10, 11…
## $ Date <date> 2010-12-01, 2010-12-01, 2010-12-01, 2010-12-01, 2010-12-0…
summary(retail_clean)
## InvoiceNo StockCode Description Quantity
## Length:397884 Length:397884 Length:397884 Min. : 1.00
## Class :character Class :character Class :character 1st Qu.: 2.00
## Mode :character Mode :character Mode :character Median : 6.00
## Mean : 12.99
## 3rd Qu.: 12.00
## Max. :80995.00
## InvoiceDate UnitPrice CustomerID
## Min. :2010-12-01 08:26:00.00 Min. : 0.001 Min. :12346
## 1st Qu.:2011-04-07 11:12:00.00 1st Qu.: 1.250 1st Qu.:13969
## Median :2011-07-31 14:39:00.00 Median : 1.950 Median :15159
## Mean :2011-07-10 23:41:23.50 Mean : 3.116 Mean :15294
## 3rd Qu.:2011-10-20 14:33:00.00 3rd Qu.: 3.750 3rd Qu.:16795
## Max. :2011-12-09 12:50:00.00 Max. :8142.750 Max. :18287
## Country TotalSales Date
## Length:397884 Min. : 0.00 Min. :2010-12-01
## Class :character 1st Qu.: 4.68 1st Qu.:2011-04-07
## Mode :character Median : 11.80 Median :2011-07-31
## Mean : 22.40 Mean :2011-07-10
## 3rd Qu.: 19.80 3rd Qu.:2011-10-20
## Max. :168469.60 Max. :2011-12-09
dim(retail_clean)
## [1] 397884 10
Después de realizar el proceso de limpieza de datos, se ha obtenido una base de datos con 397884 columnas y 10 variables, donde se han corregido inconsistencias y valores faltantes.
Para construir un modelo de series de tiempo que permita predecir el comportamiento futuro de las ventas, se seleccionó la variable TotalSales como variable dependiente (Y), la cual representa el monto total de ventas realizadas por día. Esta variable fue calculada multiplicando la cantidad de productos vendidos por su precio unitario en cada transacción.
Como variable independiente (X), se utilizó la variable InvoiceDate, que registra la fecha y hora de cada transacción. Esta variable es esencial para estructurar la serie temporal, ya que permite organizar los datos cronológicamente y detectar patrones de comportamiento a lo largo del tiempo, como tendencias, estacionalidades y anomalías.
Por lo cual con de la base de datos que fue limpiada previamente y las 2 variables mecionadas, se construyendo una nueva base de datos
datos_modelo <- retail_clean[, c("InvoiceDate", "TotalSales")]
dim(datos_modelo)
## [1] 397884 2
str(datos_modelo)
## tibble [397,884 × 2] (S3: tbl_df/tbl/data.frame)
## $ InvoiceDate: POSIXct[1:397884], format: "2010-12-01 08:26:00" "2010-12-01 08:26:00" ...
## $ TotalSales : num [1:397884] 15.3 20.3 22 20.3 20.3 ...
head(datos_modelo)
| InvoiceDate | TotalSales |
|---|---|
| 2010-12-01 08:26:00 | 15.30 |
| 2010-12-01 08:26:00 | 20.34 |
| 2010-12-01 08:26:00 | 22.00 |
| 2010-12-01 08:26:00 | 20.34 |
| 2010-12-01 08:26:00 | 20.34 |
| 2010-12-01 08:26:00 | 15.30 |
Se realiza ademas una extraccion de datos de la variable InvoiceDate para separar los años, meses y dias
library(lubridate)
retail_clean <- retail_clean %>%
mutate(
Year = year(Date),
Month = month(Date),
Day = day(Date)
)
retail_clean <- retail_clean %>%
mutate(TotalSales = Quantity * UnitPrice)
head(retail_clean)
| InvoiceNo | StockCode | Description | Quantity | InvoiceDate | UnitPrice | CustomerID | Country | TotalSales | Date | Year | Month | Day |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 536365 | 85123A | WHITE HANGING HEART T-LIGHT HOLDER | 6 | 2010-12-01 08:26:00 | 2.55 | 17850 | United Kingdom | 15.30 | 2010-12-01 | 2010 | 12 | 1 |
| 536365 | 71053 | WHITE METAL LANTERN | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom | 20.34 | 2010-12-01 | 2010 | 12 | 1 |
| 536365 | 84406B | CREAM CUPID HEARTS COAT HANGER | 8 | 2010-12-01 08:26:00 | 2.75 | 17850 | United Kingdom | 22.00 | 2010-12-01 | 2010 | 12 | 1 |
| 536365 | 84029G | KNITTED UNION FLAG HOT WATER BOTTLE | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom | 20.34 | 2010-12-01 | 2010 | 12 | 1 |
| 536365 | 84029E | RED WOOLLY HOTTIE WHITE HEART. | 6 | 2010-12-01 08:26:00 | 3.39 | 17850 | United Kingdom | 20.34 | 2010-12-01 | 2010 | 12 | 1 |
| 536365 | 22752 | SET 7 BABUSHKA NESTING BOXES | 2 | 2010-12-01 08:26:00 | 7.65 | 17850 | United Kingdom | 15.30 | 2010-12-01 | 2010 | 12 | 1 |
library(lubridate)
library(dplyr)
datos_modelo<- datos_modelo %>%
mutate(
year = year(InvoiceDate),
month = factor(month(InvoiceDate)),
day_of_month = day(InvoiceDate),
day_of_year = yday(InvoiceDate)
)
model_lm <- lm(TotalSales ~ year + month + day_of_month, data = datos_modelo)
summary(model_lm)
##
## Call:
## lm(formula = TotalSales ~ year + month + day_of_month, data = datos_modelo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -30 -17 -11 -3 168440
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.587e+04 6.114e+03 -2.596 0.009422 **
## year 7.908e+00 3.040e+00 2.601 0.009298 **
## month2 -4.456e+00 3.051e+00 -1.460 0.144180
## month3 -4.924e+00 2.831e+00 -1.739 0.081984 .
## month4 -6.205e+00 2.959e+00 -2.097 0.035988 *
## month5 -2.918e+00 2.808e+00 -1.039 0.298622
## month6 -2.567e+00 2.833e+00 -0.906 0.364873
## month7 -4.471e+00 2.839e+00 -1.575 0.115350
## month8 -2.989e+00 2.837e+00 -1.054 0.292031
## month9 -3.025e+00 2.624e+00 -1.153 0.249082
## month10 -5.876e+00 2.536e+00 -2.317 0.020480 *
## month11 -8.859e+00 2.446e+00 -3.621 0.000293 ***
## month12 2.735e+00 3.247e+00 0.842 0.399693
## day_of_month -3.202e-02 5.980e-02 -0.535 0.592321
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 309.1 on 397870 degrees of freedom
## Multiple R-squared: 8.319e-05, Adjusted R-squared: 5.052e-05
## F-statistic: 2.546 on 13 and 397870 DF, p-value: 0.001645
Este modelo corresponde a una regresión lineal múltiple en la que se busca predecir el total de ventas diarias (TotalSales) a partir de variables temporales derivadas de la fecha de cada transacción, específicamente: año (year), mes (month) y día del mes (day_of_month). Estas variables fueron extraídas de la variable original InvoiceDate, con el objetivo de capturar posibles efectos temporales sobre el comportamiento de las ventas.
En términos de desempeño, el modelo presenta un coeficiente de determinación R² muy bajo (0.00008319), lo que indica que menos del 0.01% de la variabilidad observada en las ventas es explicada por las variables incluidas en el modelo. Esto sugiere que la estructura temporal básica utilizada (año, mes y día del mes como variables categóricas) no es suficiente para capturar patrones significativos en las ventas. Además, el error estándar de los residuos (309.1) es relativamente alto, lo cual refuerza la idea de que las predicciones del modelo difieren considerablemente de los valores reales.
Si se analiza cada coeficiente , se observa que la variable year tiene un efecto positivo y significativo (p = 0.0093), lo que sugiere un leve crecimiento de las ventas a lo largo del tiempo. Tambien que algunos meses muestran efectos significativos en comparación con el mes de referencia (probablemente enero), como abril (month4, p = 0.0359), octubre (month10, p = 0.0205) y especialmente noviembre (month11, p = 0.0003), que tiene un efecto negativo más marcado. Ademas la variable day_of_month no es significativa (p = 0.5923), lo que indica que el número del día en sí mismo no influye en las ventas de manera sistemática.
Se realizara una evalucion del modelo en base a las ventas diarias segun las fechas. Se hara un analisis de los dias de los mese y de los años.
Se iniciara haciendo una grafica de las ventas diarias en los meses del 2011
library(ggplot2)
ventas_diarias <- retail_clean %>%
group_by(Date) %>%
summarise(TotalVentas = sum(TotalSales))
ggplot(ventas_diarias, aes(x = Date, y = TotalVentas)) +
geom_line(color = "steelblue") +
labs(title = "Ventas Diarias", x = "Fecha", y = "Total de Ventas") +
theme_minimal()
Se observa un inicio de año con volúmenes de venta no tan buenos, seguido de una caída pronunciada en los ultimos dias del mes inicial. Tras esta disminución, las ventas se recuperan alcanzando un nuevo pico temporal. Iniciando abril se registra un nuevo descenso el cual sigue continuo todos los dias de dicho mes, y de los meses siguientes del cual se logra repuntar los primeros dias de octubre. En los ultimos dias de octubre hay un retroseso del cual se recuperran en los meses siguientes llegando Finalmente al pico anual máximo, concentrado en los últimos meses del año. Este comportamiento sugiere que el desempeño de la empresa vende mas en los ultimos meses del año.
Para observar mejor esta informacion se realizara una grafica solamente mes año para analizar en que meses son mejores las ventas
retail_clean <- retail_clean %>%
mutate(YearMonth = format(Date, "%Y-%m"))
ventas_mensuales <- retail_clean %>%
group_by(YearMonth) %>%
summarise(TotalVentas = sum(TotalSales))
ggplot(ventas_mensuales, aes(x = YearMonth, y = TotalVentas, group = 1)) +
geom_line(color = "darkgreen") +
labs(title = "Ventas Mensuales", x = "Mes-Año", y = "Total de Ventas") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
En este gráfico se puede observar la evolución de las ventas diarias de la empresa a lo largo del tiempo. A finales de 2010 e inicios de 2011, las ventas se mantienen relativamente constantes. En febrero se presenta una caída significativa, de la cual la empresa logra recuperarse en marzo. Posteriormente, en abril ocurre otra disminución, seguida por un ascenso notable en mayo.
Entre junio y julio, las ventas vuelven a disminuir, aunque de forma menos marcada que en caídas anteriores. A partir de agosto, se observa una tendencia creciente, con un repunte importante en septiembre que continúa hasta alcanzar su punto máximo en noviembre. Sin embargo, en diciembre se presenta una fuerte caída en el volumen de ventas.
En general, se puede concluir que los meses con mejor desempeño en ventas son entre agosto y noviembre, lo que podría estar asociado a patrones estacionales como promociones o la temporada navideña.
Para finalizar se realizara tambien un grafico en el que se pueda hacer una comparacion de las ventas realizadas en el año 2010 y 2011
ventas_anuales <- retail_clean %>%
group_by(Year) %>%
summarise(TotalVentas = sum(TotalSales))
ggplot(ventas_anuales, aes(x = as.factor(Year), y = TotalVentas)) +
geom_col(fill = "coral") +
labs(title = "Ventas por Año", x = "Año", y = "Total de Ventas") +
theme_minimal()
Se puede observar que la empresa ha experimentado un crecimiento sostenible desde el año 2010 hasta el 2011. En 2011, las ventas fueron más del doble que en 2010, lo cual indica un importante aumento en la actividad comercial. Este crecimiento sugiere que, con el paso del tiempo, la empresa ha ido ganando reconocimiento en el mercado, lo que ha contribuido a un incremento significativo en sus ventas.
A partir del análisis de las ventas diarias y mensuales durante los años 2010 y 2011, se identifican patrones estacionales claramente definidos. Las ventas tienden a incrementarse de forma sostenida a partir de agosto, alcanzando su punto máximo en noviembre, seguido por una fuerte caída en diciembre. Este comportamiento sugiere la existencia de ciclos de alta demanda en los últimos meses del año, posiblemente asociados a promociones, campañas de fin de año y compras navideñas.
La comparación interanual de ventas revela un crecimiento significativo en 2011 respecto a 2010, con un incremento que supera el doble del volumen de ventas del año anterior. Este resultado indica una consolidación en la actividad comercial de la empresa, posiblemente impulsada por una mejor presencia en el mercado, expansión de operaciones o incremento en la base de clientes.
Si bien se implementó una regresión lineal múltiple para analizar el efecto del año, mes y día del mes sobre las ventas diarias, el modelo mostró una capacidad explicativa muy limitada (R² ≈ 0.00008). Esto indica que las variables temporales básicas no capturan adecuadamente la variabilidad en las ventas, lo que sugiere la necesidad de incluir factores adicionales (como promociones, días de la semana, eventos especiales o variables exógenas) en futuros modelos predictivos.
El estudio confirma que el análisis detallado del comportamiento temporal de las ventas puede ofrecer información valiosa para la toma de decisiones estratégicas. Al identificar los meses de mayor y menor desempeño, la empresa puede anticipar cambios en la demanda, optimizar su inventario, y alinear mejor sus campañas de marketing con los periodos de mayor actividad comer