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.
O arquivo sales.csv contém informações transacionais, onde cada linha representa uma venda. Possui as colunas:
# 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.
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:
# 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.
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:
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.
É 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 treinamentoNotamos 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%
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%
É 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())
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.
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%
É 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
É 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
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:
Acredito que ser importante para o modelo saber quais são os produtos com maior potencial de compras
Acredito que ser importante para o modelo saber quais são os meses que mais possuem compras (Ex: Dia das mãe, pais, etc)
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