Relatório Desafio Precificação

O problema a seguir trata do desafio de precificação, onde se buscar meios para otimizar a relação demanda e preço. Os dados utilizados são uma pequena amostra de um comércio eletrônico, onde temos basicamente dois arquivos “sales.csv” e “comp_prices.csv com 351.091 e 50.114 linhas, respectivamente.

Arquivo sales.csv

O arquivo sales.csv contém informações transacionais, onde cada linha representa uma venda. Possui as colunas:

  • PROD_ID: ID de produto. Com os dados para nove produtos, P1 a P9
  • DATE_ORDER: Data da venda, no formato YYYY-MM-DD
  • QTY_ORDER: Quantidade vendida
  • PRICE: Preço da venda
# Carregando as bibliotecas necessárias
require(caret)
library(dplyr)
library(ggplot2)
library(h2o)

 
source("~/Projetos/Desafio-Precificacao/Scripts/R/precificacao-lib.R")
 
# Carregando os dados
sales <- read.csv("~/Projetos/Desafio-Precificacao/Scripts/Dados/sales.csv")

Vamos primeiro analisar a quantidade de produtos vendidos.

# Mostra lita de produtos vendidos
venda_produto <- as.data.frame(table(sales$PROD_ID))
 
# % de cada produto
venda_produto$percentual <- (venda_produto$Freq / sum(venda_produto$Freq))*100
 
ggplot(venda_produto, aes(x=reorder(Var1, -percentual), y=percentual, fill = percentual)) +
 geom_bar(stat="identity") +
 labs(y='', x='Produtos', title = "Produtos mais comprado") +
 scale_fill_continuous(name="Compras em %") +
 theme_classic() +
 scale_y_continuous(limits=c(0, 60)) +
 theme(panel.background=element_blank())

É possível notar que o produto P7 foi o produto mais comprado, com 55% das compras. O segundo colocado é o P2, que não chega nem a 20% das compras.

Podemos observar como é a distribuição das compras ao longo do ano.

# Criando novas colunas de datas (dia/mês/ano)
sales <- col_timestamp(sales)
 
# Lista das compras por meses do ano
mes_venda_produto <- as.data.frame(table(sales$mes))
 
ggplot(mes_venda_produto, aes(x=reorder(Var1, -Var1), y=Freq)) +
 geom_bar(stat="identity") +
 labs(y='Compras', x='Meses', title = "Compras por Mês") +
 theme_classic() +
 theme(panel.background=element_blank())

O mês com maior volume de compras é o mês de Setembro (9). Interessante notar que o mês de Maio (5) ficou em segundo lugar, sendo esse o mês do dia das mães.

É interessante investigar também em qual dia da semana que acontece um maior volume de compras.

dia_semana_venda_produto <- as.data.frame(table(sales$dia_da_semana))
 
ggplot(dia_semana_venda_produto, aes(x=reorder(Var1, -Freq), y=Freq)) +
 geom_bar(stat="identity") +
 labs(y='Compras', x='Dias da Semana', title = "Compras por Dia da Semana") +
 theme_classic() +
 theme(panel.background=element_blank())

Para essa amostra de dados, o dia que acontece o maior volume de compras é a quarta-feira.

Podemos verificar também se o volume de compras ao longo dos dias é uniforme ou não.

dia_venda_produto <- as.data.frame(table(sales$dia))
mean_compras_dia <- mean(dia_venda_produto$Freq)
 
ggplot(dia_venda_produto, aes(x=reorder(Var1, -Var1), y=Freq)) +
 geom_bar(stat="identity") +
 labs(y='Compras', x='Dias', title = "Compras por Dia") +
 theme_classic() +
 theme(panel.background=element_blank(), axis.text.x = element_blank()) +
 geom_abline(intercept=mean_compras_dia,slope= 0,colour="blue")

A linha azul representa a média total de compras. Podemos observar que alguns dias superam e muito a média de compras. Os dias 19 e 20 Agosto foram os dias em que se teve o maior volume de compras

Analisamos também a quantidade vendida.

qty_venda_produto <- as.data.frame(table(sales$QTY_ORDER))
qty_venda_produto$porcentagem <- (qty_venda_produto$Freq / sum(qty_venda_produto$Freq))*100
 
ggplot(qty_venda_produto, aes(x=reorder(Var1, -porcentagem), y=porcentagem)) +
 geom_bar(stat="identity") +
 labs(y='Compras %', x='Quantidade Vendida', title = "Quantidade Vendida") +
 theme_classic() +
 theme(panel.background=element_blank())

Em 95% das compras apenas 1 produto foi comprado.

qty_venda_produto <- filter(qty_venda_produto, porcentagem < 90)
 
ggplot(qty_venda_produto, aes(x=reorder(Var1, -porcentagem), y=porcentagem)) +
 geom_bar(stat="identity") +
 labs(y='Compras %', x='Quantidade Vendida', title = "Quantidade Vendida (sem o 1)") +
 theme_classic() +
 theme(panel.background=element_blank())

2 produtos foram comprados em menos de 4% das compras. Mostrando que o padrão de compra desse comércio eletrônico é majoritariamente de 1 produto.

Podemos também analisar a média de preços por produto.

# Média de compras por semana
produto_sales <- group_by(sales, PROD_ID) %>%
 summarise(media = mean(PRICE))
 
ggplot(produto_sales, aes(x = reorder(PROD_ID, -media), y = media)) +
 geom_bar(stat="identity") +
 labs(y='Média de Preço', x='Produto', title = "Média de Preço por Produto") +
 theme_classic() +
 theme(panel.background=element_blank())

É possível observar que o produto P6 possui maior média de preço.


Arquivo comp_prices.csv

O arquivo comp_prices.csv contém dados de monitoramento dos preços dos concorrentes. É possível encontrar os dados de seis concorrentes, C1 a C6, que são monitorados duas vezes ao dia.

Possui as colunas:

  • PROD_ID: ID de produto
  • DATE_EXTRACTION: Data e hora da extração dos preços dos concorrentes, no formato YYYY-MM-DD HH:MM:SS
  • COMPETITOR: ID do concorrente (C1 a C6)
  • COMPETITOR_PRICE: Preço do concorrente, por produto
  • PAY_TYPE: Tipo de pagamento
# Carregando os dados
comp_prices <- read.csv("~/Projetos/Desafio-Precificacao/Scripts/Dados/comp_prices.csv")

Vamos analisar a distribuição do valor dos preços por produto.

comp_prices$PROD_ID <- as.character(comp_prices$PROD_ID)
 
ggplot(comp_prices, aes(factor(PROD_ID), COMPETITOR_PRICE)) +
 geom_boxplot(stat = "boxplot") +
 labs(y='Preço', x='Produto', title = "BoxPlot do Preço dos Produtos") +
 theme_classic() +
 theme(panel.background=element_blank())

É possível perceber que todos os produtos possuem outlier. Isso pode às vezes significar erro de digitação, erro na hora de coletar os dados.

ggplot(comp_prices, aes(factor(PROD_ID), COMPETITOR_PRICE)) +
 geom_boxplot( stat = "boxplot")  +
 scale_y_continuous(breaks = round(seq(200, 3000, by = 300),), limits = c(0, 3000)) +
 labs(y='Preço', x='Produto', title = "BoxPlot do Preço dos Produtos (Zoom)") +
 theme_classic() +
 theme(panel.background=element_blank())

Podemos perceber que o P6 é o produto que possui a média mais alta. Já o produto P8 possui a média mais baixa.

Interessante notar qual o competidor que possui o maior e menor preço para cada produto.

toPlot_preco_competidor(comp_prices, "P1")

toPlot_preco_competidor(comp_prices, "P2")

toPlot_preco_competidor(comp_prices, "P3")

toPlot_preco_competidor(comp_prices, "P4")

toPlot_preco_competidor(comp_prices, "P5")

toPlot_preco_competidor(comp_prices, "P6")

toPlot_preco_competidor(comp_prices, "P7")

toPlot_preco_competidor(comp_prices, "P8")

toPlot_preco_competidor(comp_prices, "P9")

É importante notar que para o P5 todos os 3 concorrentes possuem o mesmo valor mínimo. A coluna em azul significa que aquele concorrente possui valor mínimo, já a coluna em vermelho significa que aquele concorrente possui valor máximo em comparação com os outros concorrentes.

Qual é então o concorrente mais importante?

ggplot(data=toPlot_preco_competidor_df(comp_prices),
      aes(x=reorder(Var1, Var1), y=Freq, fill=Preco)) +
 geom_bar(stat="identity") +
 scale_fill_manual(values = c("Melhor" = "blue", "Pior" = "red")) +
 labs(y='', x='Competidor', title = "Número de vezes que um competidor foi melhor/pior") +
 theme_classic() +
 theme(axis.ticks = element_blank())

Se a gente considerar que um concorrente é importante quando aplica os melhores preços, então podemos concluir que o concorrente C1 é o melhor concorrente e o concorrente C6 é o pior corrente.


Pré-processamento

Foram feitos vários pre-processamentos com o objetivo de criar um data frame ideal para a solução do problema. Para mais detalhe de implementação olhar o código em pre-processamento.Rmd. Como resultado foi criado um data frame com as seguintes colunas:

  • “PROD_ID”
  • “dia”
  • “qty”
  • “preco”
  • “date”
  • “hora”
  • “mes”
  • “semana”
  • “dia_da_semana_num”
  • “C1”
  • “C2”
  • “C3”
  • “C4”
  • “C5”
  • “C6”

O modelo

Para a criação do modelo utilizei a biblioteca h2o, por se tratar de um open-source software para big-data analysis. O h2o é bastante rápido e flexível, podendo assim ser possível carregar uma grande quantidade de dados. Faz parte de uma comunidade que vem crescendo cada dia mais.

conn <- h2o.init(nthreads = -1)
## 
## H2O is not running yet, starting it now...
## 
## Note:  In case of errors look at the following log files:
##     /tmp/Rtmpj6MGBD/h2o_rodolfo_started_from_r.out
##     /tmp/Rtmpj6MGBD/h2o_rodolfo_started_from_r.err
## 
## 
## ..........Successfully connected to http://127.0.0.1:54321/ 
## 
## R is connected to the H2O cluster: 
##     H2O cluster uptime:         16 seconds 626 milliseconds 
##     H2O cluster version:        3.0.1.7 
##     H2O cluster name:           H2O_started_from_R_rodolfo_pvl383 
##     H2O cluster total nodes:    1 
##     H2O cluster total memory:   0.85 GB 
##     H2O cluster total cores:    4 
##     H2O cluster allowed cores:  4 
##     H2O cluster healthy:        TRUE

Inicialmente vamos dividir o dataset entre o dataset de treino e validação. Essa divisão é importante por evita o overfitting, que ocorre quando um modelo estatístico super se adapta ao conjunto treinado, dessa forma quando o modelo recebe um valor pelo o qual ele não foi treinado, ele vai gerar uma predição muito ruim. É importante essa divisão entre treino e validação para verificar em qual ponto o modelo começa a sofrer overfitting.

# Importando arquivo no h2o
path_input <- "/home/rodolfo/Projetos/Desafio-Precificacao/Scripts/Dados/prod_qty_treino.csv"
data <- h2o.importFile(path = path_input, destination_frame = "train.hex")
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=================================================================| 100%
# Divide o data frame em dois. Treino 80 %/ validação  20%
data.split <- h2o.splitFrame(data = data , ratios = 0.80)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=================================================================| 100%
# Treino
data.train <- data.split[[1]]
 
# Validação
data.validacao <- data.split[[2]]

A minha estratégia é primeiro achar o melhor modelo que encontre a quantidade diária que será vendida para cada produto, e só depois encontrar o melhor modelo que encontre o preço diário desse produto.

Vamos inicialmente trabalhar com os modelos GBM, random florest e GLM. O ideal seria inicialmente rodar todos os modelos com um grande número de árvores, grande profundidade e uma taxa de aprendizado pequena por interação, porém isso leva um tempo grande na minha máquina atual (com apenas 4GB)

# Coluna que se deseja prever
myY <- "qty"
 
# Coluna que deve ser ignorada pelo modelo
ignored_columns <- "preco"
 
myX <- setdiff(setdiff(names(data.train), myY), ignored_columns)
 
# GBM
gbm <- h2o.gbm(x = myX, build_tree_one_node = T,
            y = myY,
            training_frame    = data.train,
            validation_frame  = data.validacao,
            ntrees            = 50,
            max_depth         = 6,
            learn_rate        = 0.1)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=                                                                |   2%
  |                                                                       
  |=====                                                            |   8%
  |                                                                       
  |=========                                                        |  14%
  |                                                                       
  |=============                                                    |  20%
  |                                                                       
  |==================                                               |  28%
  |                                                                       
  |=======================                                          |  36%
  |                                                                       
  |==============================                                   |  46%
  |                                                                       
  |=======================================                          |  60%
  |                                                                       
  |===============================================                  |  72%
  |                                                                       
  |=======================================================          |  84%
  |                                                                       
  |==============================================================   |  96%
  |                                                                       
  |=================================================================| 100%
# DRF
drf <- h2o.randomForest(x = myX,
                     y = myY,
                     training_frame    = data.train,
                     validation_frame  = data.validacao,
                     ntrees            = 50,
                     max_depth         = 30)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=                                                                |   2%
  |                                                                       
  |===                                                              |   4%
  |                                                                       
  |====                                                             |   6%
  |                                                                       
  |=====                                                            |   8%
  |                                                                       
  |======                                                           |  10%
  |                                                                       
  |========                                                         |  12%
  |                                                                       
  |=========                                                        |  14%
  |                                                                       
  |==========                                                       |  16%
  |                                                                       
  |============                                                     |  18%
  |                                                                       
  |=============                                                    |  20%
  |                                                                       
  |==============                                                   |  22%
  |                                                                       
  |=================                                                |  26%
  |                                                                       
  |====================                                             |  30%
  |                                                                       
  |======================                                           |  34%
  |                                                                       
  |=========================                                        |  38%
  |                                                                       
  |===========================                                      |  42%
  |                                                                       
  |==============================                                   |  46%
  |                                                                       
  |================================                                 |  50%
  |                                                                       
  |===================================                              |  54%
  |                                                                       
  |======================================                           |  58%
  |                                                                       
  |========================================                         |  62%
  |                                                                       
  |===========================================                      |  66%
  |                                                                       
  |============================================                     |  68%
  |                                                                       
  |==============================================                   |  70%
  |                                                                       
  |=================================================                |  76%
  |                                                                       
  |====================================================             |  80%
  |                                                                       
  |=======================================================          |  84%
  |                                                                       
  |=========================================================        |  88%
  |                                                                       
  |==========================================================       |  90%
  |                                                                       
  |=============================================================    |  94%
  |                                                                       
  |=================================================================| 100%
# GLM
glm <- h2o.glm(x = myX,
            y = myY,
            training_frame    = data.train,
            validation_frame  = data.validacao,
            lambda            = 1e-5,
            family            = "poisson")
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |==========                                                       |  16%
  |                                                                       
  |=================================================================| 100%
# Score de cada modelo
train_r2_gbm <- h2o.r2(gbm)
test_r2_gbm  <- h2o.r2(gbm, valid = TRUE)
 
train_r2_drf <- h2o.r2(drf)
test_r2_drf  <- h2o.r2(drf, valid = TRUE)
 
train_r2_glm <- h2o.r2(glm)
test_r2_glm  <- h2o.r2(glm, valid = TRUE)
 
df <- data.frame(Rsquared = c(train_r2_gbm, test_r2_gbm, train_r2_drf, test_r2_drf, train_r2_glm, test_r2_glm),
                        tipo = c("treino", "validacao", "treino", "validacao", "treino", "validacao"),
                        modelo = c("GBM","GBM","RF", "RF","GLM", "GLM"))

Para verificar qual dos 3 modelos é o melhor, utilizamos a métrica Rsquared, onde o valor do Rsquared (entre 0 e 1) é o percentual de variância explicada pelo o modelo. Quanto maior foi o Rsquared melhor é o modelo.

ggplot(data=df, aes(x = modelo, y = Rsquared, fill = tipo)) +
 geom_bar(stat="identity", position=position_dodge()) +
 theme_classic() +
 labs(title = "Comparando os modelos") +
 theme(axis.ticks = element_blank())

É possível notar que o Random Florest teve um melhor resultado do que os outros modelos, obtendo assim um Rsquared maior, então optamos por escolher o Random Florest para o caso da predição da quantidade de vendas de produtos.

Como o Random Florest foi o escolhido, é interessante observar como se deu o treinamento ao longo das criações das árvores. Para evitar o overfitting dividimos os dados de treino em treino e validação. Dessa forma podemos observar o exato momento em que o modelo passa a sofrer o overfitting.

treinamento

É possível notar que depois da árvore 17, o modelo passa a sofrer overfitting. Por esse motivo criamos um novo modelo, dessa vez parando o treinamento na árvore 17. A linha azul significa a evolução do treino e a linha laranja significa validação.

# DRF
drf <- h2o.randomForest(x = myX,
                     y = myY,
                     training_frame    = data.train,
                     validation_frame  = data.validacao,
                     ntrees            = 17,
                     max_depth         = 30)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |========                                                         |  12%
  |                                                                       
  |===============                                                  |  24%
  |                                                                       
  |===================                                              |  29%
  |                                                                       
  |===========================                                      |  41%
  |                                                                       
  |==================================                               |  53%
  |                                                                       
  |==============================================                   |  71%
  |                                                                       
  |======================================================           |  82%
  |                                                                       
  |=============================================================    |  94%
  |                                                                       
  |=================================================================| 100%
novo_train_r2_drf <- h2o.r2(drf)
novo_test_r2_drf  <- h2o.r2(drf, valid = TRUE)
 
df <- data.frame(Rsquared = c(train_r2_drf, test_r2_drf, novo_train_r2_drf, novo_test_r2_drf),
                        tipo = c("treino", "validacao", "treino", "validacao"),
                        modelo = c("Antigo", "Antigo", "Novo", "Novo"))
 
ggplot(data=df, aes(x = modelo, y = Rsquared, fill = tipo)) +
 geom_bar(stat = "identity", position = position_dodge()) +
 labs(title = "Comparando RF") +
 theme_classic() +
 theme(axis.ticks = element_blank())

É possível notar que o valor de Rsquared do treino sofreu uma ligeira queda, porém o valor do Rsquared da validação sofreu um aumento. Dessa forma a gente evita o overfitting

Evolução do treinamento
treinamento
É interessante notar também a importância das variáveis para a criação dos modelos.
treinamento

Notamos que a variável PROD_ID, dia e semana foram as variáveis com maior importância para a criação do modelo. Por esse motivo é interessante criar novas variáveis que podem agregar valor a essas variáveis para melhorar o modelo.

Uma boa alternativa é criar uma variável que mostre a quantidade de compras que o item teve no dia anterior. Outra boa alternativa é criar uma variável que mostre a média de preço e a quantidade de compras do item na última semana.

Foi feito então um novo pré-processamento, onde foram adicionadas as três novas colunas qty_semana, media_preco_semana, qty_anterior.

# Importando arquivo no h2o
path_input <- "/home/rodolfo/Projetos/Desafio-Precificacao/Scripts/Dados/prod_qty_treino_novas_variaveis.csv"
data <- h2o.importFile(path = path_input, destination_frame = "train.hex")
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=================================================================| 100%
# Divide o data frame em dois. treino 80 / validação  20
data.split <- h2o.splitFrame(data = data , ratios = 0.80)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=================================================================| 100%
# Treino
data.train <- data.split[[1]]
 
# Validação
data.validacao <- data.split[[2]]

Um novo modelo será criado, seguindo os mesmo passos anteriores: * Rodar RF com 50 árvores e 30 de profundidade * Encontrar o ponto onde o modelo começa a ficar especialista (overfitthing) * Rodar RF com o número de árvores otimizado

myY <- "qty"
ignored_columns <- "preco"
myX <- setdiff(setdiff(names(data.train), myY), ignored_columns)
 
# DRF
drf <- h2o.randomForest(x = myX,
                     y = myY,
                     training_frame    = data.train,
                     validation_frame  = data.validacao,
                     ntrees            = 50,
                     max_depth         = 30)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=                                                                |   2%
  |                                                                       
  |====                                                             |   6%
  |                                                                       
  |======                                                           |  10%
  |                                                                       
  |=========                                                        |  14%
  |                                                                       
  |============                                                     |  18%
  |                                                                       
  |==============                                                   |  22%
  |                                                                       
  |=================                                                |  26%
  |                                                                       
  |====================                                             |  30%
  |                                                                       
  |======================                                           |  34%
  |                                                                       
  |=========================                                        |  38%
  |                                                                       
  |=============================                                    |  44%
  |                                                                       
  |===============================                                  |  48%
  |                                                                       
  |==================================                               |  52%
  |                                                                       
  |====================================                             |  56%
  |                                                                       
  |========================================                         |  62%
  |                                                                       
  |==========================================                       |  64%
  |                                                                       
  |===========================================                      |  66%
  |                                                                       
  |==============================================                   |  70%
  |                                                                       
  |===============================================                  |  72%
  |                                                                       
  |=================================================                |  76%
  |                                                                       
  |====================================================             |  80%
  |                                                                       
  |=====================================================            |  82%
  |                                                                       
  |=========================================================        |  88%
  |                                                                       
  |============================================================     |  92%
  |                                                                       
  |==============================================================   |  96%
  |                                                                       
  |================================================================ |  98%
  |                                                                       
  |=================================================================| 100%
treinamento

Para esse novo modelo não foi possível notar o ponto onde o modelo começa a ficar especialista. Por esse motivo foi criado um novo modelo, dessa vez utilizando 100 árvores e 30 de profundidade.

myY <- "qty"
ignored_columns <- "preco"
myX <- setdiff(setdiff(names(data.train), myY), ignored_columns)
 
# DRF
drf <- h2o.randomForest(x = myX,
                     y = myY,
                     training_frame    = data.train,
                     validation_frame  = data.validacao,
                     ntrees            = 100,
                     max_depth         = 30)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=                                                                |   1%
  |                                                                       
  |=                                                                |   2%
  |                                                                       
  |===                                                              |   4%
  |                                                                       
  |===                                                              |   5%
  |                                                                       
  |=====                                                            |   7%
  |                                                                       
  |======                                                           |   9%
  |                                                                       
  |======                                                           |  10%
  |                                                                       
  |========                                                         |  12%
  |                                                                       
  |=========                                                        |  14%
  |                                                                       
  |==========                                                       |  16%
  |                                                                       
  |============                                                     |  18%
  |                                                                       
  |=============                                                    |  20%
  |                                                                       
  |==============                                                   |  22%
  |                                                                       
  |================                                                 |  24%
  |                                                                       
  |=================                                                |  26%
  |                                                                       
  |==================                                               |  28%
  |                                                                       
  |====================                                             |  30%
  |                                                                       
  |=====================                                            |  32%
  |                                                                       
  |======================                                           |  34%
  |                                                                       
  |=======================                                          |  35%
  |                                                                       
  |=======================                                          |  36%
  |                                                                       
  |=========================                                        |  39%
  |                                                                       
  |===========================                                      |  41%
  |                                                                       
  |=============================                                    |  44%
  |                                                                       
  |=============================                                    |  45%
  |                                                                       
  |===============================                                  |  47%
  |                                                                       
  |================================                                 |  49%
  |                                                                       
  |=================================                                |  51%
  |                                                                       
  |==================================                               |  53%
  |                                                                       
  |===================================                              |  54%
  |                                                                       
  |====================================                             |  56%
  |                                                                       
  |======================================                           |  58%
  |                                                                       
  |=======================================                          |  60%
  |                                                                       
  |========================================                         |  62%
  |                                                                       
  |==========================================                       |  64%
  |                                                                       
  |==========================================                       |  65%
  |                                                                       
  |============================================                     |  67%
  |                                                                       
  |=============================================                    |  69%
  |                                                                       
  |==============================================                   |  71%
  |                                                                       
  |===============================================                  |  73%
  |                                                                       
  |=================================================                |  75%
  |                                                                       
  |==================================================               |  77%
  |                                                                       
  |===================================================              |  79%
  |                                                                       
  |=====================================================            |  82%
  |                                                                       
  |=======================================================          |  84%
  |                                                                       
  |========================================================         |  86%
  |                                                                       
  |=========================================================        |  88%
  |                                                                       
  |==========================================================       |  90%
  |                                                                       
  |============================================================     |  92%
  |                                                                       
  |==============================================================   |  95%
  |                                                                       
  |===============================================================  |  97%
  |                                                                       
  |================================================================ |  99%
  |                                                                       
  |=================================================================| 100%
treinamento

É possível notar que depois da árvore 60, tanto o treinamento quando a validação se estabilizam. Por esse motivo, o número de árvores ideal para esse conjunto de dados é 60 (com mais árvores só estaríamos “desperdiçando” processamento para ter pouca melhora no modelo).

myY <- "qty"
ignored_columns <- "preco"
myX <- setdiff(setdiff(names(data.train), myY), ignored_columns)
 
# DRF
drf <- h2o.randomForest(x = myX,
                     y = myY,
                     training_frame    = data.train,
                     validation_frame  = data.validacao,
                     ntrees            = 60,
                     max_depth         = 30)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |==                                                               |   3%
  |                                                                       
  |====                                                             |   7%
  |                                                                       
  |======                                                           |  10%
  |                                                                       
  |=========                                                        |  13%
  |                                                                       
  |===========                                                      |  17%
  |                                                                       
  |==============                                                   |  22%
  |                                                                       
  |================                                                 |  25%
  |                                                                       
  |==================                                               |  28%
  |                                                                       
  |=====================                                            |  32%
  |                                                                       
  |========================                                         |  37%
  |                                                                       
  |==========================                                       |  40%
  |                                                                       
  |============================                                     |  43%
  |                                                                       
  |==============================                                   |  47%
  |                                                                       
  |================================                                 |  50%
  |                                                                       
  |====================================                             |  55%
  |                                                                       
  |=====================================                            |  57%
  |                                                                       
  |========================================                         |  62%
  |                                                                       
  |==========================================                       |  65%
  |                                                                       
  |============================================                     |  68%
  |                                                                       
  |===============================================                  |  72%
  |                                                                       
  |=================================================                |  75%
  |                                                                       
  |====================================================             |  80%
  |                                                                       
  |======================================================           |  83%
  |                                                                       
  |========================================================         |  87%
  |                                                                       
  |=========================================================        |  88%
  |                                                                       
  |=============================================================    |  93%
  |                                                                       
  |===============================================================  |  97%
  |                                                                       
  |=================================================================| 100%
novas_variaveis_train_r2_drf <- h2o.r2(drf)
novas_variaveis_test_r2_drf  <- h2o.r2(drf, valid = TRUE)

Podemos agora compara e verificar se existiu algum ganho entre o melhor modelo com as novas variáveis

df <- data.frame(Rsquared = c(novo_train_r2_drf, novo_test_r2_drf,
                       novas_variaveis_train_r2_drf, novas_variaveis_test_r2_drf),
                        tipo = c("treino", "validacao", "treino", "validacao"),
                        modelo = c("Antigo", "Antigo", "Novo", "Novo"))
 
ggplot(data = df, aes(x = modelo, y = Rsquared, fill = tipo)) +
 geom_bar(stat = "identity", position = position_dodge()) +
 labs(title = "Comparando RF com Novas Variáveis") +
 theme_classic() +
 theme(axis.ticks = element_blank())

É possível notar que o valor do Rsquared subiu em relação ao modelo anterior. Devemos agora investigar quais foram as variáveis que mais contribuíram para essa mudança.
treinamento

Notamos que as três novas variáveis adicionadas se encontram no Top 5 das variáveis que mais contribuíram para a criação do modelo. Podemos afirmar então, que as novas variáveis influenciaram positivamente o modelo.


Modelo para prever o preço de um certo produto por dia

Vamos agora repetir os passos para criar um novo modelo, para prever o preço de um certo produto por dia.

myY <- "preco"
ignored_columns <- "qty"
myX <- setdiff(setdiff(names(data.train), myY), ignored_columns)
 
# DRF
drf_preco <- h2o.randomForest(x = myX,
                     y = myY,
                     training_frame    = data.train,
                     validation_frame  = data.validacao,
                     ntrees            = 50,
                     max_depth         = 30)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=                                                                |   2%
  |                                                                       
  |=====                                                            |   8%
  |                                                                       
  |========                                                         |  12%
  |                                                                       
  |==========                                                       |  16%
  |                                                                       
  |=============                                                    |  20%
  |                                                                       
  |=================                                                |  26%
  |                                                                       
  |====================                                             |  30%
  |                                                                       
  |=======================                                          |  36%
  |                                                                       
  |===========================                                      |  42%
  |                                                                       
  |==============================                                   |  46%
  |                                                                       
  |================================                                 |  50%
  |                                                                       
  |===================================                              |  54%
  |                                                                       
  |=======================================                          |  60%
  |                                                                       
  |===========================================                      |  66%
  |                                                                       
  |==============================================                   |  70%
  |                                                                       
  |=================================================                |  76%
  |                                                                       
  |====================================================             |  80%
  |                                                                       
  |========================================================         |  86%
  |                                                                       
  |==========================================================       |  90%
  |                                                                       
  |=============================================================    |  94%
  |                                                                       
  |================================================================ |  98%
  |                                                                       
  |=================================================================| 100%
treinamento

É possível notar que o após 17 árvores o modelo se torna especialista. Por esse motivo foi criado um novo modelo com apenas 17 árvores.

myY <- "preco"
ignored_columns <- "qty"
myX <- setdiff(setdiff(names(data.train), myY), ignored_columns)
 
# DRF
drf_preco <- h2o.randomForest(x = myX,
                     y = myY,
                     training_frame    = data.train,
                     validation_frame  = data.validacao,
                     ntrees            = 17,
                     max_depth         = 30)
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |========                                                         |  12%
  |                                                                       
  |===================                                              |  29%
  |                                                                       
  |===========================                                      |  41%
  |                                                                       
  |==================================                               |  53%
  |                                                                       
  |==============================================                   |  71%
  |                                                                       
  |=========================================================        |  88%
  |                                                                       
  |=================================================================| 100%
Agora o modelo não sofre mais overfitting
treinamento
É importante observar quais foram as variáveis quem mais contribuíram para a criação do modelo.
treinamento

É interessante notar que o concorrente C1 se encontra no Top 3 das variáveis que mais contribuíram para a criação do modelo. Esse mesmo concorrente foi destacado como sendo o concorrente que possui os melhores preços antes mesmo da criação de qualquer modelo

Com isso temos dois modelos finais: * Um modelo para prever a quantidade diária que será vendida de cada produto * Um modelo para prever o preço diário de cada produto


Prevendo o preço e a quantidade

Podemos agora utilizar os dados de teste (que foi separado antes do modelo, e que é totalmente disjunto dos dados de treino) para prever qual seria o resultado em um mundo real.

# Importanto arquivo de teste no H2O
path_test <- "/home/rodolfo/Projetos/Desafio-Precificacao/Scripts/Dados/prod_qty_test_novas_variaveis.csv"
data_train <- h2o.importFile(path = path_test, destination_frame = "test.hex")
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=================================================================| 100%
drf.qty = h2o.predict(object = drf, newdata = data_train)
h2o.exportFile(drf.qty, path = "/home/rodolfo/Projetos/Desafio-Precificacao/Scripts/Dados/predicao_qty.csv")
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=================================================================| 100%
drf.preco = h2o.predict(object = drf_preco, newdata = data_train)
h2o.exportFile(drf.preco, path = "/home/rodolfo/Projetos/Desafio-Precificacao/Scripts/Dados/predicao_preco.csv")
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |=================================================================| 100%

Podemos agora simular qual seria o real valor Rsquared no mundo real. Para o modelo que prever a quantidade de compras, temos um Rsquared de:

prod_qty_test_novas_variaveis <- read.csv("~/Projetos/Desafio-Precificacao/Scripts/Dados/prod_qty_test_novas_variaveis.csv")
 
predicao_qty <- read.table("~/Projetos/Desafio-Precificacao/Scripts/Dados/predicao_qty.csv", header=TRUE, quote="\"")
 
avaliacao_qty <- data.frame(obs = prod_qty_test_novas_variaveis$qty, pred = predicao_qty$predict)
 
defaultSummary(avaliacao_qty)[[2]]
## [1] 0.9813621

Para o modelo que prever a quantidade o preço, temos um Rsquared de:

predicao_preco <- read.table("~/Projetos/Desafio-Precificacao/Scripts/Dados/predicao_preco.csv", header=TRUE, quote="\"")
 
avaliacao_preco <- data.frame(obs = prod_qty_test_novas_variaveis$preco, pred = predicao_preco$predict)
 
defaultSummary(avaliacao_preco)[[2]]
## [1] 0.9961352

É possível notar que o Rsquared ficou acima de 0.97 para os dois casos. Esse valor no mundo real é considerado bastante alto. Cheguei nesse valor tão alto por se tratar de um conjunto de dados no qual não condiz com o de um mundo real (ter apenas 9 produtos, 6 concorrentes, etc). Todos esses fatores influenciaram para se ter um modelo com uma precisão tão alta.

Mesmo com um valor alto, ainda é possível melhorar sem causar overfitting. Se eu tivesse mais tempo, iria criar um novo modelo retirando alguns outlier, pois acredito que eles influênciam negativamente o modelo. Também iria retirar as variáveis que pouco contribuem para o modelo, deixando ele assim mais rápido.

Além disso, iria investigar e criar novas variáveis para melhorar o modelo. Algumas variáveis que tem potencial para melhorar o modelo:

  • Vendabilidade - Proporção que o produto foi comprado em relação aos outros produtos

Acredito que ser importante para o modelo saber quais são os produtos com maior potencial de compras

  • Top_meses - Proporção de vendas de um mês em relação aos outros meses.

Acredito que ser importante para o modelo saber quais são os meses que mais possuem compras (Ex: Dia das mãe, pais, etc)

  • Dia_Mes - Mostra se o dia se encontra no começo, meio ou fim do mês

Acredito que algumas pessoas preferem comprar no começo do mês (quando recebem o salário) outras devem preferir comprar no fim do mês

Também acho importante utilizar outra biblioteca além do h2o, como por exemplo, o caret, que eu já usei aqui