Objetivo: Ayudar al Supermercado a predecir sus ventas
library(rsconnect)
library(janitor)
library(dplyr)
library(wordspace)
library(tidyverse)
train<-read.csv("C:\\Users\\javaw\\OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey\\7mo Semestre\\Modulo 3\\train.csv")
test<-read.csv("C:\\Users\\javaw\\OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey\\7mo Semestre\\Modulo 3\\test.csv")
stores<-read.csv("C:\\Users\\javaw\\OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey\\7mo Semestre\\Modulo 3\\stores.csv")
features<-read.csv("C:\\Users\\javaw\\OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey\\7mo Semestre\\Modulo 3\\features.csv")
Train
train<-clean_names(train)
summary(train)
## i_store dept date weekly_sales
## Min. : 1.0 Min. : 1.00 Length:421570 Min. : -4989
## 1st Qu.:11.0 1st Qu.:18.00 Class :character 1st Qu.: 2080
## Median :22.0 Median :37.00 Mode :character Median : 7612
## Mean :22.2 Mean :44.26 Mean : 15981
## 3rd Qu.:33.0 3rd Qu.:74.00 3rd Qu.: 20206
## Max. :45.0 Max. :99.00 Max. :693099
## is_holiday
## Mode :logical
## FALSE:391909
## TRUE :29661
##
##
##
Observaciones
1. Hay 45 tiendas.
2. La columna de dept va desde 1 hasta 99.
3. La fecha está como character en lugar de estar como formato de fecha.
Las fechas van de 2010-02-05 a 2012-11-01.
4. Las ventas semanales tienen valores negativos.
Stores
stores<-clean_names(stores)
summary(stores)
## i_store type size
## Min. : 1 Length:45 Min. : 34875
## 1st Qu.:12 Class :character 1st Qu.: 70713
## Median :23 Mode :character Median :126512
## Mean :23 Mean :130288
## 3rd Qu.:34 3rd Qu.:202307
## Max. :45 Max. :219622
count(stores, type, sort = TRUE)
## type n
## 1 A 22
## 2 B 17
## 3 C 6
Observaciones
1. Hay 45 tiendas.
2. La columna de type describe el tipo de tienda, hay 3 tipos, A, B,
C.
3. La columna de size describe el tamaño de la tienda.
Test
test<-clean_names(test)
summary(test)
## i_store dept date is_holiday
## Min. : 1.00 Min. : 1.00 Length:115064 Mode :logical
## 1st Qu.:11.00 1st Qu.:18.00 Class :character FALSE:106136
## Median :22.00 Median :37.00 Mode :character TRUE :8928
## Mean :22.24 Mean :44.34
## 3rd Qu.:33.00 3rd Qu.:74.00
## Max. :45.00 Max. :99.00
Observaciones
1. Hay 45 tiendas.
2. La columna de dept va desde 1 hasta 99.
3. La fecha está como character en lugar de estar como formato de fecha.
Y son distintas a las fechas que hay en train.
4. Los días festivos también difieren a los que hay en train.
Features
features<-clean_names(features)
summary(features)
## i_store date temperature fuel_price
## Min. : 1 Length:8190 Min. : -7.29 Min. :2.472
## 1st Qu.:12 Class :character 1st Qu.: 45.90 1st Qu.:3.041
## Median :23 Mode :character Median : 60.71 Median :3.513
## Mean :23 Mean : 59.36 Mean :3.406
## 3rd Qu.:34 3rd Qu.: 73.88 3rd Qu.:3.743
## Max. :45 Max. :101.95 Max. :4.468
##
## mark_down1 mark_down2 mark_down3 mark_down4
## Min. : -2781 Min. : -265.76 Min. : -179.26 Min. : 0.22
## 1st Qu.: 1578 1st Qu.: 68.88 1st Qu.: 6.60 1st Qu.: 304.69
## Median : 4744 Median : 364.57 Median : 36.26 Median : 1176.42
## Mean : 7032 Mean : 3384.18 Mean : 1760.10 Mean : 3292.94
## 3rd Qu.: 8923 3rd Qu.: 2153.35 3rd Qu.: 163.15 3rd Qu.: 3310.01
## Max. :103185 Max. :104519.54 Max. :149483.31 Max. :67474.85
## NA's :4158 NA's :5269 NA's :4577 NA's :4726
## mark_down5 cpi unemployment is_holiday
## Min. : -185.2 Min. :126.1 Min. : 3.684 Mode :logical
## 1st Qu.: 1440.8 1st Qu.:132.4 1st Qu.: 6.634 FALSE:7605
## Median : 2727.1 Median :182.8 Median : 7.806 TRUE :585
## Mean : 4132.2 Mean :172.5 Mean : 7.827
## 3rd Qu.: 4832.6 3rd Qu.:213.9 3rd Qu.: 8.567
## Max. :771448.1 Max. :229.0 Max. :14.313
## NA's :4140 NA's :585 NA's :585
Observaciones
1. Hay 45 tiendas.
2. Hay información de markdowns que se hicieron y solo estan disponibles
a partir de nov 2011. La fecha está en caracter también.
3. Está presente el indice de precios al consumidor.
4. También está presente el desempleo.
5. De igual manera, esta marcado si fue en festividad o no.
6. Hay NA’s en más de la mitad de lso registros de MarkDown (1 al
5).
7. Hay 585 Na’s en CPI y desempleo, hay 585 registros de festividades,
sin embargo no hay relación entre estas al revisar la base de datos.
El departamento de mercadotecnia de EUA (con muestra de 45 tiendas) en el indicador de Ventas Semanales.
Elaborar un modelo predictivo de ventas semanales.
Elaborar una base de datos con la variable dependiente(ventas semanales) y las variables independientes a definir.
Mecadotecnia elaborará plan para desplegar el modelo predictivo en
fases.
Fase 1. Piloto en San Antonio, TX.
Fase 2. Texas
Fase 3. EUA
Sistemas asegurará la captura del markdown en las bases de datos.
Podemos optar por unir las bases de datos de train, stores, y features, ya que todas juntas contienen información relevante que debe de ser analizada para predecir las ventas en la base de datos de test. Primero podemos unir train y stores.
df<-merge(train,stores, by="i_store")
Posteriormente hay que unir features pero hay que dejar solo las variables que nos interesan: temperatura, precio de combustible, CPI y desempleo.
features2<-select(features,-(mark_down1:mark_down5))
#De igual manera puede realizarse con subset
featuresprueba<-subset(features,select=-c(mark_down1:mark_down5))
df2<-merge(df,features2)
colSums(is.na(df2))
## i_store date is_holiday dept weekly_sales type
## 0 0 0 0 0 0
## size temperature fuel_price cpi unemployment
## 0 0 0 0 0
No hay NA’s ya que se eliminaron las columnas de los markdowns, ademas que los NA,s de CPI y unemployment eran en fechas posteriores del 2012.
df2$date<-as.Date(df2$date, format = "%d/%m/%Y")
str(df2)
## 'data.frame': 421570 obs. of 11 variables:
## $ i_store : int 1 1 1 1 1 1 1 1 1 1 ...
## $ date : Date, format: "2011-04-01" "2011-04-01" ...
## $ is_holiday : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
## $ dept : int 49 26 81 34 59 30 7 85 8 28 ...
## $ weekly_sales: num 13168 5947 28545 9950 317 ...
## $ type : chr "A" "A" "A" "A" ...
## $ size : int 151315 151315 151315 151315 151315 151315 151315 151315 151315 151315 ...
## $ temperature : num 59.2 59.2 59.2 59.2 59.2 ...
## $ fuel_price : num 3.52 3.52 3.52 3.52 3.52 ...
## $ cpi : num 215 215 215 215 215 ...
## $ unemployment: num 7.68 7.68 7.68 7.68 7.68 ...
Al evaluar la base de datos, se puede observar que todos los valores negativos provienen del departamento 47. Esto podría significar que ese departamento es de devoluciones.
signcount(df2$weekly_sales)
## pos zero neg
## 420212 73 1285
Sin embargo, no se cuenta con elementos necesarios para corroborar esta información, y los registros son pocos por lo que se opta eliminar los registros con ventas negativas.
df3<-filter(df2, weekly_sales > 0)
summary(df3$weekly_sales)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0 2120 7662 16033 20271 693099
Si bien ya tenemos la fecha como tal, el numero de la semana puede ser un factor que afecte en las ventas.
df4<-df3
df4$week_number<-strftime(df4$date, format="%V") %>% as.integer(df4$Date)
str(df4)
## 'data.frame': 420212 obs. of 12 variables:
## $ i_store : int 1 1 1 1 1 1 1 1 1 1 ...
## $ date : Date, format: "2011-04-01" "2011-04-01" ...
## $ is_holiday : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
## $ dept : int 49 26 81 34 59 30 7 85 8 28 ...
## $ weekly_sales: num 13168 5947 28545 9950 317 ...
## $ type : chr "A" "A" "A" "A" ...
## $ size : int 151315 151315 151315 151315 151315 151315 151315 151315 151315 151315 ...
## $ temperature : num 59.2 59.2 59.2 59.2 59.2 ...
## $ fuel_price : num 3.52 3.52 3.52 3.52 3.52 ...
## $ cpi : num 215 215 215 215 215 ...
## $ unemployment: num 7.68 7.68 7.68 7.68 7.68 ...
## $ week_number : int 13 13 13 13 13 13 13 13 13 13 ...
df5<-df4
df5<-df5 %>%
mutate(year=lubridate::year(date),
month=lubridate::month(date),
day=lubridate::day(date))
str(df5)
## 'data.frame': 420212 obs. of 15 variables:
## $ i_store : int 1 1 1 1 1 1 1 1 1 1 ...
## $ date : Date, format: "2011-04-01" "2011-04-01" ...
## $ is_holiday : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
## $ dept : int 49 26 81 34 59 30 7 85 8 28 ...
## $ weekly_sales: num 13168 5947 28545 9950 317 ...
## $ type : chr "A" "A" "A" "A" ...
## $ size : int 151315 151315 151315 151315 151315 151315 151315 151315 151315 151315 ...
## $ temperature : num 59.2 59.2 59.2 59.2 59.2 ...
## $ fuel_price : num 3.52 3.52 3.52 3.52 3.52 ...
## $ cpi : num 215 215 215 215 215 ...
## $ unemployment: num 7.68 7.68 7.68 7.68 7.68 ...
## $ week_number : int 13 13 13 13 13 13 13 13 13 13 ...
## $ year : num 2011 2011 2011 2011 2011 ...
## $ month : num 4 4 4 4 4 4 4 4 4 4 ...
## $ day : int 1 1 1 1 1 1 1 1 1 1 ...
colnames(df3)
## [1] "i_store" "date" "is_holiday" "dept" "weekly_sales"
## [6] "type" "size" "temperature" "fuel_price" "cpi"
## [11] "unemployment"
regresion <- lm(weekly_sales~i_store+is_holiday+dept+type+size+temperature+fuel_price+cpi+unemployment+week_number+year+month+day, data=df5)
summary(regresion)
##
## Call:
## lm(formula = weekly_sales ~ i_store + is_holiday + dept + type +
## size + temperature + fuel_price + cpi + unemployment + week_number +
## year + month + day, data = df5)
##
## Residuals:
## Min 1Q Median 3Q Max
## -34331 -12895 -5852 5626 671540
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.110e+06 2.999e+05 3.701 0.000214 ***
## i_store -1.426e+02 3.087e+00 -46.198 < 2e-16 ***
## is_holidayTRUE 8.511e+02 1.391e+02 6.119 9.45e-10 ***
## dept 1.108e+02 1.097e+00 101.013 < 2e-16 ***
## typeB -3.133e+02 1.078e+02 -2.908 0.003642 **
## typeC 5.836e+03 1.840e+02 31.709 < 2e-16 ***
## size 9.920e-02 9.584e-04 103.511 < 2e-16 ***
## temperature 3.701e+00 2.133e+00 1.735 0.082688 .
## fuel_price 4.791e+02 1.480e+02 3.237 0.001207 **
## cpi -2.340e+01 9.996e-01 -23.409 < 2e-16 ***
## unemployment -2.538e+02 2.062e+01 -12.308 < 2e-16 ***
## week_number 7.678e+02 4.566e+02 1.682 0.092648 .
## year -5.485e+02 1.485e+02 -3.695 0.000220 ***
## month -3.167e+03 1.988e+03 -1.594 0.111036
## day -1.281e+02 6.539e+01 -1.959 0.050115 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 21690 on 420197 degrees of freedom
## Multiple R-squared: 0.08982, Adjusted R-squared: 0.08979
## F-statistic: 2962 on 14 and 420197 DF, p-value: < 2.2e-16
datos_nuevos <- data.frame(i_store=1, is_holiday= TRUE, dept=1, type="A", size= 151315, week_number =1, temperature = 59.17, fuel_price = 3.524, cpi= 214.8372, unemployment = 7.682, year =2012, month = 1, day=1)
predict(regresion,datos_nuevos)
## 1
## 14667.94
Para realizar el gráfico dinámico se consideraron las opciones de graficar las ventas promedio de acuerdo al mes, día, o número de semana del año 2012.
df6<-filter(df5,year==2012)
df7<-group_by(df6,week_number) %>% summarise(total_wsales = mean(weekly_sales))
df8<-group_by(df6,month) %>% summarise(total_wsales = mean(weekly_sales))
df9<-group_by(df6,day) %>% summarise(total_wsales = mean(weekly_sales))
Adicional, se optó por realiza run histograma dinámico donde se puede ajustar los breaks y la densidad.
También se optó por realizar un gráfico general.
#selectInput("variables",label="x",choices = names(df6),selected = "month")
#renderPlot(plot(df6$weekly_sales,df6[,input$variables])
#)
El modelo de regresión tiene un valor de r cuadrada ajustada de 0.08970, lo cual es bajo, por lo que no podemos afirmar que sea un modelo predictivo acertado. Esto se debe a la temporalidad, por ejemplo, hay picos en ventas cada vez que es Thanksgiving o cuando es el Super Bowl. Para predecir las ventas en un modelo que tiene este tipo de temporalidad hay que recurrir a otros modelos.
Adicionalmente, al realizar los pasos finales de los gráficos dinámicos, las imagenes previamente insertadas dejaron de visualizarse. Se optó por eliminar las imagenes cuando se corre el codigo en shiny.
Considero, que el modelo de predicción no posee la confiabilidad necesaria para poder implementar acciones a partir de este. Mi propuesta radica en la creación de un nuevo modelo predictivo que considere la temporalidad de las festividades para poder predecir con mayor certeza las ventas. Hasta el momento, considero que cualquier predicción tiene una alta probabilidad de ser incorrecta.