Nesse artigo seguiremos com um roteiro para analisar e prever as vendas utilizando o banco de dados Bigmart, uma rede de varejo. Esse artigo é um desafio proposto pelo site https://www.analyticsvidhya.com com dados de 2013. Seguiremos como proposto pelo desafio.
Seguiremos os seguintes passos:
1. Formular uma hipótese - Tentar entender o problema e pensar em possíveis causas que aumentam ou diminuem as vendas
2. Explorar os dados - Veremos os dados como estão dispostos como números ou categorias e tirar insights basedos em nossas hipóteses
3. Limpar os dados - Remover outliers e dados faltantes, decidiremos o que fazer com os dados
4. Modificar os dados - Criar novas variáveis de acordo com o que observamos na exploração de dados e em nossas hipóteses para análise
5. Construir um modelo - fazer modelos preditivos com os dados
“The data scientists at BigMart have collected 2013 sales data for 1559 products across 10 stores in different cities. Also, certain attributes of each product and store have been defined. The aim is to build a predictive model and find out the sales of each product at a particular store.
Using this model, BigMart will try to understand the properties of products and stores which play a key role in increasing sales.”
Em ciência de dados entender o problema e definir como aborda-lo é essencial e o mais importante. Esse passo, faremos antes mesmo de olhar os dados e assim podemos definir como queremos chegar a soluçãoo e como queremos fazer.
A ideia aqui é entender quais características dos produtos e lojas que impactam no aumento das vendas, vamos pensar e surir com algumas hipósteses.
A nível de loja:
Tamanho da Cidade
Tamanho da Loja
Conservação
Tempo de loja
Marketing
Localidade da loja na cidade
Experiencia de compra
A nível de produtos:
Reputação das marcas vendidas
Qualidade dos produtos
Utilidades dos produtos
Disposição dos produtos
Visibilidade dos produtos
Tamanho das prateleiras expostas
Propaganda ou ativações
Produtos em Oferta
Distancia entre produtos relacionados
Nesssa etapa iremos avaliar os dados e possíveis erros e irregularidades apresentadas. Nesse momento iremos comparar as informações dos dados apresentados no banco de dados e os necessários pelas nossas hipóteses. O Banco de dados tem dois arquivos, test e train com 561 e 8523 obs, respectivamente. E fornecido do site temos o dicionário do banco de dados:
| Variable | Description |
|---|---|
| Item_Identifier | Unique product ID |
| Item_Weight | Weight of product |
| Item_Fat_Content | Whether the product is low fat or not |
| Item_Visibility | The % of total display area of all products in a store allocated to the particular product |
| Item_Type | The category to which the product belongs |
| Item_MRP | Maximum Retail Price (list price) of the product |
| Outlet_Identifier | Unique store ID |
| Outlet_Establishment_Year | The year in which store was established |
| Outlet_Size | The size of the store in terms of ground area covered |
| Outlet_Location_Type | The type of city in which the store is located |
| Outlet_Type | Whether the outlet is just a grocery store or some sort of supermarket |
| Item_Outlet_Sales | Sales of the product in the particulat store. This is the outcome variable to be predicted. |
Vamos listar quais hipóteses possuímos são descritas pelas variáveis:
Tamanho da Cidade
Tamanho da Loja
Tempo de loja Qualidade dos produtos*
Utilidades dos produtos
Reputação das marcas vendidas
Visibilidade dos produtos
Hipóteses não descritas pelos nossos dados:
Conservação da Loja Marketing
Localidade da loja na cidade
Experiencia de compra
Disposição dos produtos
Tamanho das prateleiras expostas
Propaganda ou ativações
Produtos em Oferta
Distância entre produtos relacionados
Notamos que possuímos apenas 6 variáveis presentes nos dados que fazem parte da nossa hipótese inicial e uma que poderíamos adaptar, que seriam os produtos low fat como sendo uma qualidade do produto.
Começamos com o carregamento das bibliotecas que iremos utilizar e com a importação dos dados, no meu caso estão na pasta data no diretório do repositório. E usaremos o pacote tydeverse
library(readr)
library(tidyverse)
test <- read_csv("data/Test.csv")
train <- read_csv("data/Train.csv")
Para manusear os dados, unimos os dois data sets e posteriormente separamos novamente, em geral é uma boa idéia pois não geramos problemas ao manusear os dados separadamente.
dados <- dplyr::bind_rows(test, train)
Vamos dar uma olhada nos dados que faltam do nosso banco de dados
colSums(is.na(dados))
## Item_Identifier Item_Weight
## 0 2439
## Item_Fat_Content Item_Visibility
## 0 0
## Item_Type Item_MRP
## 0 0
## Outlet_Identifier Outlet_Establishment_Year
## 0 0
## Outlet_Size Outlet_Location_Type
## 4016 0
## Outlet_Type Item_Outlet_Sales
## 0 5681
Veja que Item_Outlet_Sales é a variavel para predição, logo os dados faltantes são dos dados test.csv.
Vamos analisar cada uma das variáveis:
summary(dados)
## Item_Identifier Item_Weight Item_Fat_Content Item_Visibility
## Length:14204 Min. : 4.555 Length:14204 Min. :0.00000
## Class :character 1st Qu.: 8.710 Class :character 1st Qu.:0.02704
## Mode :character Median :12.600 Mode :character Median :0.05402
## Mean :12.793 Mean :0.06595
## 3rd Qu.:16.750 3rd Qu.:0.09404
## Max. :21.350 Max. :0.32839
## NA's :2439
## Item_Type Item_MRP Outlet_Identifier
## Length:14204 Min. : 31.29 Length:14204
## Class :character 1st Qu.: 94.01 Class :character
## Mode :character Median :142.25 Mode :character
## Mean :141.00
## 3rd Qu.:185.86
## Max. :266.89
##
## Outlet_Establishment_Year Outlet_Size Outlet_Location_Type
## Min. :1985 Length:14204 Length:14204
## 1st Qu.:1987 Class :character Class :character
## Median :1999 Mode :character Mode :character
## Mean :1998
## 3rd Qu.:2004
## Max. :2009
##
## Outlet_Type Item_Outlet_Sales
## Length:14204 Min. : 33.29
## Class :character 1st Qu.: 834.25
## Mode :character Median : 1794.33
## Mean : 2181.29
## 3rd Qu.: 3101.30
## Max. :13086.97
## NA's :5681
Temos algumas considerações: 1. Visibilidade do item como zero. Não faz sentido, pois o produto está a venda e não pode ter um valor como zero. 2. A idade da loja estão em um formato não muito útil para análise, podemos criar uma variável que nos diga os anos e não quando foi inalgurada.
rapply(dados,function(x)length(unique(x)))
## Item_Identifier Item_Weight
## 1559 416
## Item_Fat_Content Item_Visibility
## 5 13006
## Item_Type Item_MRP
## 16 8052
## Outlet_Identifier Outlet_Establishment_Year
## 10 9
## Outlet_Size Outlet_Location_Type
## 4 3
## Outlet_Type Item_Outlet_Sales
## 4 3494
Para aas variáveis que apresentam como character vamos olhar com mais atenção. Vamos ver a frequencia de cada caracter nas colunas Item_Fat_Content, Item_Type, Outlet_Size, Outlet_Location_Type e Outlet_Type.
dados %>%
group_by(Item_Fat_Content) %>%
summarise(n = length(Item_Fat_Content))
## # A tibble: 5 x 2
## Item_Fat_Content n
## <chr> <int>
## 1 LF 522
## 2 low fat 178
## 3 Low Fat 8485
## 4 reg 195
## 5 Regular 4824
dados %>%
group_by(Item_Type) %>%
summarise(n = length(Item_Type))
## # A tibble: 16 x 2
## Item_Type n
## <chr> <int>
## 1 Baking Goods 1086
## 2 Breads 416
## 3 Breakfast 186
## 4 Canned 1084
## 5 Dairy 1136
## 6 Frozen Foods 1426
## 7 Fruits and Vegetables 2013
## 8 Hard Drinks 362
## 9 Health and Hygiene 858
## 10 Household 1548
## 11 Meat 736
## 12 Others 280
## 13 Seafood 89
## 14 Snack Foods 1989
## 15 Soft Drinks 726
## 16 Starchy Foods 269
dados %>%
group_by(Outlet_Size) %>%
summarise(n = length(Outlet_Size))
## # A tibble: 4 x 2
## Outlet_Size n
## <chr> <int>
## 1 High 1553
## 2 Medium 4655
## 3 Small 3980
## 4 <NA> 4016
dados %>%
group_by(Outlet_Location_Type) %>%
summarise(n = length(Outlet_Location_Type))
## # A tibble: 3 x 2
## Outlet_Location_Type n
## <chr> <int>
## 1 Tier 1 3980
## 2 Tier 2 4641
## 3 Tier 3 5583
dados %>%
group_by(Outlet_Type) %>%
summarise(n = length(Outlet_Type))
## # A tibble: 4 x 2
## Outlet_Type n
## <chr> <int>
## 1 Grocery Store 1805
## 2 Supermarket Type1 9294
## 3 Supermarket Type2 1546
## 4 Supermarket Type3 1559
No tratamento dos dados o que faremos é inserir dados que estão em falta ou excluir. Assim como remover outliers ou inconsistências.
Como temos cerca de 4000 dados faltantes na variável Outlet_Size e uma variável muito semelhante, a Outlet_Type, decidi não usar a varíavel Outlet_size. Não sei se é uma boa idéia, porém como são muitos dados faltantes em relação ao número total de observações, veremos como fica o modelo sem essa variável.
-Substituindo Item_Weight
Como um passo para podermos usar em nosso modelo a variável (apesar de não pertencer a nossa hipótese, pode ser útil) faremos a substituição dos valores NA pela média, assim a influência nos parâmetros da distribuição são melhores preservados.
dados$Item_Weight[is.na(dados$Item_Weight)] <- mean(dados$Item_Weight, na.rm=TRUE)
Navegue pelas abas para ver todo conteúdo.
Como vimos a variável possui valor mínimo de 0, o que não faz sentido, uma vez que o item está a venda. Assim faremos a substituição do valor nulo pela média do conjunto.
dados$Item_Visibility[dados$Item_Visibility == 0] <- mean(dados$Item_Visibility)
summary(dados$Item_Visibility)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.003575 0.033143 0.062347 0.070034 0.094037 0.328391
Agora não temos valores zeros para essa variável
dados %>%
group_by(Item_Visibility == 0) %>%
summarise(n = length(Item_Visibility))
## # A tibble: 1 x 2
## `Item_Visibility == 0` n
## <lgl> <int>
## 1 FALSE 14204
Agora vamos criar uma nova variável que explique a nossa hipótese de que um item com maior exposição tem maior chance de vender mais. Faremo a relacão Item_Visibility/mean(Item_visibility). Então, seria a visibilidade do item em relação a média. Acredito que nesse passo poderíamos apenas fazer um pre-processamento de padronização.
dados <- mutate(dados, Item_Visibility_MeanRatio = Item_Visibility/mean(Item_Visibility))
summary(dados$Item_Visibility_MeanRatio)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.05104 0.47325 0.89024 1.00000 1.34273 4.68901
Pronto! nossa nova variável está criada!
Nota: Essa técnica é amplamente usada para análise e pode melhorar seu modelo consideravelmente. Não é a toa que os KPIs são muito utilizados e exigidos dos profissionais hoje. São, inclusive melhores para visualização e tomadas de decisão.
Olhando atentamente a variável Item_Identifier vemos que o nome de cada item tem iniciais FD, NC ou DR. Analisando com a variavel Item_type, podemos chegar a conclusão que refere-se a Comida (FD=Food), Não-consumível (NC=Not-consumable) e Bebibas (DR=Drinks). Assim poderíamos simplesmente usar as iniciais para gerar uma nova coluna de tipo de item.
Nota: Poderíamos fazer a transformação manualmente em relação ao Item_Type para a mesma finalidade.
dados <- mutate(dados, Item_Identifier_Combined = substr(dados$Item_Identifier,1,2))
dados %>%
group_by(Item_Identifier_Combined) %>%
summarise(n = length(Item_Identifier_Combined))
## # A tibble: 3 x 2
## Item_Identifier_Combined n
## <chr> <int>
## 1 DR 1317
## 2 FD 10201
## 3 NC 2686
Agora, iremos, de forma simples, calcular a idade do estabelecimento através da variável Outlet_Establishment_Year.
dados <- mutate(dados, Outlet_Years = 2013 - Outlet_Establishment_Year)
summary(dados$Outlet_Years)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.00 9.00 14.00 15.17 26.00 28.00
Na primeira tabela, notamos que Low fat esta escrito de várias formas: LF low fat e Low Fat, assim como Regular e reg. Vamos somar para apenas Low fat e Regular.
dados$Item_Fat_Content <- gsub("LF", "Low Fat", dados$Item_Fat_Content)
dados$Item_Fat_Content <- gsub("low fat", "Low Fat", dados$Item_Fat_Content)
dados$Item_Fat_Content <- gsub("reg", "Regular", dados$Item_Fat_Content)
dados %>%
group_by(Item_Fat_Content) %>%
summarise(n = length(Item_Fat_Content))
## # A tibble: 2 x 2
## Item_Fat_Content n
## <chr> <int>
## 1 Low Fat 9185
## 2 Regular 5019
Além disso como vimos, alguns itens não são comestíveis, assim precisamos criar uma outra categoria sem relação com ambas.
dados$Item_Fat_Content[dados$Item_Identifier_Combined=="NC"] <- "Non-consumable"
dados %>%
group_by(Item_Fat_Content) %>%
summarise(n = length(Item_Fat_Content))
## # A tibble: 3 x 2
## Item_Fat_Content n
## <chr> <int>
## 1 Low Fat 6499
## 2 Non-consumable 2686
## 3 Regular 5019
O R permite o uso dos levels e factors nos algoritmos. De modo que podemos ou usar desse recurso ou criar novas variáveis "dummy" (representadas apenas por 0 e 1). Inicialmente faremos apenas o uso de factors.
dados$Item_Fat_Content <- as.factor(dados$Item_Fat_Content)
dados$Item_Type <- as.factor(dados$Item_Type)
dados$Outlet_Identifier <- as.factor(dados$Outlet_Identifier)
dados$Outlet_Size <- as.factor(dados$Outlet_Size)
dados$Outlet_Location_Type <- as.factor(dados$Outlet_Location_Type)
dados$Outlet_Type <- as.factor(dados$Outlet_Type)
dados$Item_Identifier_Combined <- as.factor(dados$Item_Identifier_Combined)
O R permite a manipulação dos dados de uma for incrivelmente simples.
De maneira fácil, transfomamos os fatores, ou levels contidos nas variáveis em dummy variables. O que significa transformar em zeros e uns. Assim, criando novas coluna com 1 para contem aquele fator ou descrição e zero caso contrário.
library(dummies)
## dummies-1.5.6 provided by Decision Patterns
dados_asdummy <- c()
dados_asdummy <- dados_asdummy %>%
bind_cols(
data.frame(dummy(dados$Item_Fat_Content)),
data.frame(dummy(dados$Outlet_Identifier)),
data.frame(dummy(dados$Outlet_Location_Type)),
data.frame(dummy(dados$Item_Identifier_Combined))
)
Agora, selecionamos as colunas numéricas que usaremos e unimos com as variáveis criadas como dummies:
dados <- select(dados, c(1,2,5,9,10,12))
dados <- bind_cols(dados, dados_asdummy)
Apartir de agora iremos criar os nossos modelos de predição. Separando e exportando os dados com novo nome de arquivo.
Agora dividiremos os dados em train e test novamente e exportaremos com outro nome para manter os arquivos originais.
train_modified <- dplyr::filter(dados, !is.na(Item_Outlet_Sales))
test_modified <- dplyr::filter(dados, is.na(Item_Outlet_Sales))
Salvando em arquivos:
write.csv(train_modified, "data/train_modified.csv")
write.csv(test_modified, "data/test_modified.csv")
Há várias maneiras de se fazer e decidir quais variáveis poderão ser usadas, a maneira apresentada é bem popular.
Sobre dummy_variables
Normalmente omitimos uma variável criada pelos fatores, pois fica redundante um fator a ser 1 e b ser 0 e outra variável que diga a ser 0 e b com valor 1.
Por questões técnicas (leia-se tempo de processamento), separei em duas partes, que será atualizado quando terminado os nossos modelos de predição. A idéia é criar de 3 a 5 modelos diferentes, não sei ao certo e compara-los.
Escrito por {Vinicius L. 2017}.