Com o crescimento do comércio eletrônico, entender como as pessoas compram e como isso afeta a satisfação do cliente é muito importante para qualquer empresa. Nota-se que os clientes cada vez mais exigentes, onde suas escolhas guiam o fluxo do mercado, fazem as empresas se moldarem para atender às necessidades dos seus consumidores (Rodrigues 2021). Compreender essas tendências pode auxiliar as organizações a aumentar seu lucro e a fidelizar os clientes, através de estratégias cada vez mais ágeis e centradas no cliente.
Por meio da tecnologia, é possível obter um histórico de como os clientes se comportam, quando eles compram, por quanto e como eles avaliam a pre-venda e pós-venda. A Olist, uma das maiores lojas de departamentos dos mercados brasileiros, disponibilizou um conjunto de dados (Olist and Sionek 2018) abrangente sobre pedidos realizados em sua plataforma. Que abrange informações detalhadas sobre pedidos, pagamentos, produtos, vendedores, clientes e avaliações coletadas no ano de 2016 à 2018, oferece uma oportunidade valiosa para investigar diversos aspectos das operações de e-commerce. Através da análise destes dados, podemos identificar padrões, tendências e potenciais áreas de melhoria que podem beneficiar tanto os comerciantes quanto os consumidores. Junto ao conjunto de dados, também utilizaremos a API do IBGE (Instituto Brasileiro de Geografia e Estatástica 2024) e um Conjunto de CEPs do Brasil (Filho and Atilio 2019).
Este relatório tem como objetivo analisar as tendências de compras e o comportamento dos consumidores em diferentes regiões do Brasil. A análise visa proporcionar uma compreensão abrangente de onde estão concentrados os principais clientes, segmentados por categoria de compra. Ao investigar esses padrões de consumo, o relatório pretende oferecer informações estratégicas para que as empresas entendam seus mercados-alvos e otimizem suas operações para atender às demandas variadas dos consumidores em diferentes localidades do país, ajustando suas estratégias de mercado de forma mais precisa e eficaz.
O método foca na coleta e extração de dados de transações comerciais volumosas, seguido pela visualização e pré-processamento simultâneos desses dados, com o objetivo de gerar gráficos e tabelas para análise do conteúdo obtido. A figura abaixo ilustra o passo a passo deste processo.
Conjuntos e subcojuntos de dados que serão usados:
| Nome | Descrição | Fonte |
|---|---|---|
| CEPS do Brasil | Lista de CEPs de todo o Brasil, incluindo faixas de CEP por localidade. | Lista de CEPs do Brasil |
| Localidades do IBGE | Informações detalhadas sobre localidades no Brasil, incluindo dados de municípios, estados, mesorregiões e microrregiões. | API de Localidades do IBGE |
| olist_customers_dataset | Dataset com informações sobre clientes da plataforma Olist. | Olist Brazilian E-Commerce Dataset |
| olist_order_items_dataset | Dataset com detalhes dos itens de pedidos na plataforma Olist. | Olist Brazilian E-Commerce Dataset |
| olist_order_payments_dataset | Dataset com informações de pagamentos de pedidos na plataforma Olist. | Olist Brazilian E-Commerce Dataset |
| olist_order_reviews_dataset | Dataset com avaliações de pedidos na plataforma Olist. | Olist Brazilian E-Commerce Dataset |
| olist_orders_dataset | Dataset com dados gerais de pedidos na plataforma Olist. | Olist Brazilian E-Commerce Dataset |
| olist_products_dataset | Dataset com informações sobre produtos na plataforma Olist. | Olist Brazilian E-Commerce Dataset |
| olist_sellers_dataset | Dataset com informações sobre vendedores na plataforma Olist. | Olist Brazilian E-Commerce Dataset |
Detalhamento de cada conjunto e subconjuntos:
O dataset foi projetado em meados de 2017 a partir do site site de busca de CEPS dos Correios disponibilizado em 2019 por (Filho and Atilio 2019) e está disponível neste link no Kaggle.
| Coluna | Descrição |
|---|---|
| Estado | Sigla do Estado/UF da Localidade |
| Localidade | Nome da Cidade/Município |
| Faixa de CEP | Intervalo de CEPs atribuídos à localidade |
| CEP Inicial | Primeiro CEP do intervalo atribuído à localidade |
| CEP Final | Último CEP do intervalo atribuído à localidade. |
| Situação | Descrição do status de codificação da localidade. |
| Tipo de Faixa | Indicação sobre faixa de CEP |
O dataset tem origem da API de Localidades do IBGE, e contém dados detalhados das localidades, desde regiões até distritos. Para este relatório, serão destacadas apenas as variáveis relevantes:
| Coluna | Descrição |
|---|---|
| municipio-nome | Nome do Município |
| microrregiao-nome | Nome da microrregião |
| mesorregiao-nome | Nome da mesorregião |
| UF-sigla | Sigla da Unidade da Federação |
| UF-nome | Nome da Unidade da Federação |
| regiao-nome | Nome da região |
Todas as colunas dos conjuntos da Olist usados no relátorio unificado.
| Coluna | Descrição |
|---|---|
| customer_id | Identificador do cliente por pedido |
| customer_unique_id | Identificador único do cliente |
| customer_zip_code_prefix | Prefixo do CEP do cliente |
| customer_city | Cidade do cliente |
| customer_state | Estado do cliente |
| order_id | Identificador único do pedido |
| order_item_id | Número sequencial que identifica os itens incluídos no mesmo pedido |
| product_id | Identificador exclusivo do produto |
| seller_id | Identificador do vendedor |
| shipping_limit_date | Data limite para o vendedor enviar o pedido ao parceiro logístico |
| price | Preço do item |
| freight_value | Valor do frete por item |
| payment_sequential | Número sequencial do pagamento realizado pelo cliente |
| payment_type | Forma de pagamento escolhida pelo cliente |
| payment_installments | Número de parcelas escolhidas pelo cliente |
| payment_value | Valor da transação |
| review_id | Identificador único da avaliação |
| review_score | Nota da avaliação em escala Likert |
| review_comment_title | Título do comentário da avaliação |
| review_comment_message | Mensagem de comentário da avaliação |
| review_creation_date | Data em que a pesquisa de satisfação foi enviada ao cliente |
| review_answer_timestamp | Data/hora da resposta da pesquisa de satisfação |
| order_status | Status da encomenda (entregue, expedida, etc.) |
| order_purchase_timestamp | Data/hora da compra |
| order_approved_at | Data/hora de aprovação do pagamento |
| order_delivered_carrier_date | Data/hora de postagem do pedido no operador logístico |
| order_delivered_customer_date | Data real de entrega do pedido ao cliente |
| order_estimated_delivery_date | Data estimada de entrega informada ao cliente no momento da compra |
| product_category_name | Categoria raiz do produto |
| product_name_lenght | Número de caracteres do nome do produto |
| product_description_lenght | Número de caracteres da descrição do produto |
| product_photos_qty | Número de fotos publicadas do produto |
| product_weight_g | Peso do produto em gramas |
| product_length_cm | Comprimento do produto em centímetros |
| product_height_cm | Altura do produto em centímetros |
| product_width_cm | Largura do produto em centímetros |
| seller_zip_code_prefix | Prefixo do CEP do vendedor |
| seller_city | Cidade do vendedor |
| seller_state | Estado do vendedor |
Para realizar a análise das tendências de compras e comportamento dos consumidores em diferentes regiões do Brasil, serão utilizadas os seguintes pacotes:
| Pacote | Descrição |
|---|---|
| rmarkdown | para centralizar as informações em apenas um documento. |
| readxl | para carregar dados de arquivos Excel. |
| dplyr | para manipulação eficiente de dados. |
| httr | para realizar requisições HTTP. |
| jsonlite | para trabalhar com dados em formato JSON. |
| stringi | para manipulação avançada de strings. |
| purrr | para operações funcionais em R. |
| ggplot2 | para criar gráficos estáticos. |
| plotly | para criar visualizações gráficas interativas. |
| DT | para criar tabelas interativas. |
| tidyverse | para manipulação e visualização de dados de forma eficiente. |
Esses pacotes serão empregados para carregar, manipular, unir e visualizar os dados dos conjuntos de dados, bem como para realizar análises estatísticas e gráficas.
Importando todos o pacotes necessários:
library(rmarkdown)
library(readxl)
library(dplyr)
library(httr)
library(jsonlite)
library(stringi)
library(purrr)
library(DT)
library(ggplot2)
library(tidyverse)
library(plotly)
Extração dos conjuntos de dados para o formato de Dataframe:
reviews <- read.csv("olist_order_reviews_dataset.csv")
orders <- read.csv("olist_orders_dataset.csv")
order_payments <- read.csv("olist_order_payments_dataset.csv")
order_customer <- read.csv("olist_customers_dataset.csv")
order_items <- read.csv("olist_order_items_dataset.csv")
products <- read.csv("olist_products_dataset.csv")
sellers <- read.csv("olist_sellers_dataset.csv")
ceps <- read_excel("Lista_de_CEPs.xlsx")
df_municipios <- fromJSON(content(GET("https://servicodados.ibge.gov.br/api/v1/localidades/municipios?view=nivelado"), "text"), flatten = TRUE)
Primeiramente, verificaremos a existência de dados nulos nos conjuntos de dados:
# Verificando a presença de valores nulos nos conjuntos de dados
sum(is.na(reviews))
## [1] 0
sum(is.na(orders))
## [1] 0
sum(is.na(order_payments))
## [1] 0
sum(is.na(order_customer))
## [1] 0
sum(is.na(order_items))
## [1] 0
sum(is.na(products))
## [1] 1838
sum(is.na(sellers))
## [1] 0
sum(is.na(ceps))
## [1] 0
sum(is.na(df_municipios))
## [1] 0
Verifica-se também se há diferenças nos nomes das cidades entre os conjuntos da Olist e os dados do IBGE. Nota-se que em df_municipios, as letras estão misturadas entre maiúsculas e minúsculas, ao contrário dos outros conjuntos que estão todas em minúsculas. Para padronizar a comparação entre os conjuntos, criaremos novas colunas em todos os conjuntos, repetindo o nome da cidade, porém removendo sinais e transformando todas as letras em minúsculas.
#Imprimindo a primeira linha de cada cidade para comparação inicial
print(order_customer$customer_city[1])
## [1] "franca"
print(sellers$seller_city[1])
## [1] "campinas"
print(df_municipios$`municipio-nome`[1])
## [1] "Alta Floresta D'Oeste"
#Criando nova coluna com nomes das cidades formatados.
df_municipios <- df_municipios %>%
mutate(municipio_nome_clean = tolower(stri_trans_general(`municipio-nome`, "Latin-ASCII")))
sellers <- sellers %>%
mutate(seller_city_clean = tolower(stri_trans_general(seller_city, "Latin-ASCII")))
order_customer <- order_customer %>%
mutate(customer_city_clean = tolower(stri_trans_general(customer_city, "Latin-ASCII")))
#Comparando os nomes das cidades
result_seller_city <- sellers %>%
filter(!seller_city_clean %in% df_municipios$municipio_nome_clean)
head(result_seller_city$seller_city)
## [1] "lages - sc" "balenario camboriu" "ferraz de vasconcelos"
## [4] "auriflama/sp" "sao paulo / sao paulo" "vicente de carvalho"
length(unique(result_seller_city$seller_city))
## [1] 70
result_customer_city <- order_customer
result_customer_city <- result_customer_city %>%
filter(!customer_city_clean %in% df_municipios$municipio_nome_clean)
head(result_customer_city$customer_city)
## [1] "parati" "embu" "espigao do oeste" "mogi-guacu"
## [5] "passa tres" "mogi-guacu"
length(unique(result_customer_city$customer_city))
## [1] 253
Podemos observar que há cerca de 70 cidades com nomes incorretos no
conjunto sellers e 253 no conjunto
order_customer. Vamos abordar isso utilizando o conjunto
ceps, tentando corrigir a maior quantidade possível de
cidades incorretas, como nomes de distritos e bairros no lugar do nome
do município (por exemplo, “passa tres” de RJ no DF
customer_city) e misturas de cidade e estado (por exemplo,
“lages - sc” de SC no DF sellers).
Começaremos visualizando o conjunto de dados ceps em e o
conjunto de dados df_municipios:
nrow(ceps) #Contagem de linhas
## [1] 6015
unique(ceps$`Tipo de Faixa`)
## [1] "Total do município" "Exclusiva da sede urbana"
head(ceps) #Visão inicial do df
## # A tibble: 6 × 7
## Estado Localidade `Faixa de CEP` `CEP Inicial` `CEP Final` Situação
## <chr> <chr> <chr> <dbl> <dbl> <chr>
## 1 AC Acrelândia 69945-000 a 69949-9… 69945000 69949999 Não cod…
## 2 AC Assis Brasil 69935-000 a 69939-9… 69935000 69939999 Não cod…
## 3 AC Brasiléia 69932-000 a 69933-9… 69932000 69933999 Não cod…
## 4 AC Bujari 69926-000 a 69926-9… 69926000 69926999 Não cod…
## 5 AC Capixaba 69931-000 a 69931-9… 69931000 69931999 Não cod…
## 6 AC Cruzeiro do Sul 69980-000 a 69981-9… 69980000 69981999 Não cod…
## # ℹ 1 more variable: `Tipo de Faixa` <chr>
nrow(df_municipios) #Contagem de linhas
## [1] 5570
head(df_municipios) #Visão inicial do DF
## municipio-id municipio-nome microrregiao-id microrregiao-nome
## 1 1100015 Alta Floresta D'Oeste 11006 Cacoal
## 2 1100023 Ariquemes 11003 Ariquemes
## 3 1100031 Cabixi 11008 Colorado do Oeste
## 4 1100049 Cacoal 11006 Cacoal
## 5 1100056 Cerejeiras 11008 Colorado do Oeste
## 6 1100064 Colorado do Oeste 11008 Colorado do Oeste
## mesorregiao-id mesorregiao-nome regiao-imediata-id regiao-imediata-nome
## 1 1102 Leste Rondoniense 110005 Cacoal
## 2 1102 Leste Rondoniense 110002 Ariquemes
## 3 1102 Leste Rondoniense 110006 Vilhena
## 4 1102 Leste Rondoniense 110005 Cacoal
## 5 1102 Leste Rondoniense 110006 Vilhena
## 6 1102 Leste Rondoniense 110006 Vilhena
## regiao-intermediaria-id regiao-intermediaria-nome UF-id UF-sigla UF-nome
## 1 1102 Ji-Paraná 11 RO Rondônia
## 2 1101 Porto Velho 11 RO Rondônia
## 3 1102 Ji-Paraná 11 RO Rondônia
## 4 1102 Ji-Paraná 11 RO Rondônia
## 5 1102 Ji-Paraná 11 RO Rondônia
## 6 1102 Ji-Paraná 11 RO Rondônia
## regiao-id regiao-sigla regiao-nome municipio_nome_clean
## 1 1 N Norte alta floresta d'oeste
## 2 1 N Norte ariquemes
## 3 1 N Norte cabixi
## 4 1 N Norte cacoal
## 5 1 N Norte cerejeiras
## 6 1 N Norte colorado do oeste
Agora, vamos tratar as linhas de CEP, focando na faixa de CEP que
engloba toda a área do município. Isso é necessário porque o tipo
“Exclusiva da sede urbana” não inclui a zona rural e alguns distritos.
Observamos que o DF ceps tem 5573 linhas, enquanto o DF
df_municipios tem 5570 linhas, o que ocorre, devido ao fato
de que algumas cidades têm duas faixas de CEP, como mostra abaixo.
ceps <- ceps %>% filter(`Tipo de Faixa` == "Total do município")
ceps <- ceps %>% select(-`Faixa de CEP`, -Situação, -`Tipo de Faixa`) #Eliminando colunas não relevantes.
nrow(ceps) #Contagem de linhas depois da transformação
## [1] 5573
print(ceps %>%
group_by(Localidade, Estado) %>%
filter(n() > 1)) #Linhas não únicas com mesma cidades e estado.
## # A tibble: 6 × 4
## # Groups: Localidade, Estado [3]
## Estado Localidade `CEP Inicial` `CEP Final`
## <chr> <chr> <dbl> <dbl>
## 1 DF Brasília 70000001 72799999
## 2 DF Brasília 73000001 73699999
## 3 RJ Nova Iguaçu 26000001 26099999
## 4 RJ Nova Iguaçu 26200000 26299999
## 5 SP São Paulo 1000001 5999999
## 6 SP São Paulo 8000000 8499999
A seguir, são listadas as cidades que têm nomes diferentes nos conjuntos ceps e df_municipios. Foi feito um filtro que compara ambos, removendo acentos e convertendo as letras para minúsculas.
filter_ceps <- ceps %>%
filter(!(tolower(stri_trans_general(ceps$Localidade, "Latin-ASCII")) %in% tolower(stri_trans_general(df_municipios$`municipio-nome`, "Latin-ASCII"))
& Estado %in% df_municipios$`UF-sigla`))
unique(filter_ceps$Localidade)
## [1] "Muquém de São Francisco" "Pindaré Mirim"
## [3] "Amparo da Serra" "Olhos D'Água"
## [5] "Santa Rita do Ibitipoca" "São Thomé das Letras"
## [7] "Sem Peixe" "Santo Antônio do Leverger"
## [9] "Eldorado dos Carajás" "Santa Isabel do Pará"
## [11] "Iguaraci" "Lagoa do Itaenga"
## [13] "Arez" "Boa Saúde"
## [15] "Olho-D'Água do Borges" "Espigão do Oeste"
## [17] "Santana do Livramento" "Grão Pará"
## [19] "Amparo de São Francisco" "Graccho Cardoso"
## [21] "Biritiba-Mirim" "Couto de Magalhães"
## [23] "Fortaleza do Tabocão" "São Valério da Natividade"
filter_mun <- df_municipios %>%
filter(!(tolower(stri_trans_general(`municipio-nome`, "Latin-ASCII")) %in% tolower(stri_trans_general(ceps$Localidade, "Latin-ASCII"))
& `UF-sigla` %in% ceps$Estado))
unique(filter_mun$`municipio-nome`)
## [1] "Espigão D'Oeste" "Eldorado do Carajás"
## [3] "Santa Izabel do Pará" "Couto Magalhães"
## [5] "Tabocão" "São Valério"
## [7] "Pindaré-Mirim" "Arês"
## [9] "Januário Cicco" "Olho d'Água do Borges"
## [11] "Iguaracy" "Lagoa de Itaenga"
## [13] "Amparo do São Francisco" "Gracho Cardoso"
## [15] "Muquém do São Francisco" "Amparo do Serra"
## [17] "Olhos-d'Água" "Santa Rita de Ibitipoca"
## [19] "São Tomé das Letras" "Sem-Peixe"
## [21] "Biritiba Mirim" "Grão-Pará"
## [23] "Sant'Ana do Livramento" "Santo Antônio de Leverger"
## [25] "Bom Jesus de Goiás"
Observa-se que há 24 cidades com nomes diferentes entre os conjuntos,
além disso, uma cidade chamada “Bom Jesus de Goiás” foi encontrada
apenas no segundo filtro, o que indica que no DF ceps há
uma cidade com o nome incorreto, mas com o estado correto. Ao
filtrarmos, encontramos apenas uma cidade com o nome “Bom Jesus”, das
quais, podemos observar que há 6 cidades com esse nome, e uma em Goiás,
e verificamos que existe apenas isso. Quando comparamos o
df_municipios, podemos ver que essa cidade não existe.
Portanto, o nome correto da cidade no conjunto ceps deveria
ser “Bom Jesus de Goiás” e não apenas “Bom Jesus”.
filter(ceps, Localidade == "Bom Jesus")
## # A tibble: 6 × 4
## Estado Localidade `CEP Inicial` `CEP Final`
## <chr> <chr> <dbl> <dbl>
## 1 GO Bom Jesus 75570000 75579999
## 2 PB Bom Jesus 58930000 58932999
## 3 PI Bom Jesus 64900000 64904999
## 4 RN Bom Jesus 59270000 59274999
## 5 RS Bom Jesus 95290000 95299999
## 6 SC Bom Jesus 89824000 89824999
filter(ceps, Localidade == "Bom Jesus de Goiás")
## # A tibble: 0 × 4
## # ℹ 4 variables: Estado <chr>, Localidade <chr>, CEP Inicial <dbl>,
## # CEP Final <dbl>
filter(df_municipios, `municipio-nome` == "Bom Jesus" & `UF-sigla` == "GO") %>% select( `municipio-nome`, `UF-sigla`)
## [1] municipio-nome UF-sigla
## <0 linhas> (ou row.names de comprimento 0)
filter(df_municipios, `municipio-nome` == "Bom Jesus de Goiás" & `UF-sigla` == "GO") %>% select( `municipio-nome`, `UF-sigla`)
## municipio-nome UF-sigla
## 1 Bom Jesus de Goiás GO
Agora vamos corrigir esses dados de ceps.
corrections_ <- list(
"Muquém de São Francisco" = "Muquém do São Francisco",
"Pindaré Mirim" = "Pindaré-Mirim",
"Amparo da Serra" = "Amparo do Serra",
"Olhos D'Água" = "Olhos-d'Água",
"Santa Rita do Ibitipoca" = "Santa Rita de Ibitipoca",
"São Thomé das Letras" = "São Tomé das Letras",
"Sem Peixe" = "Sem-Peixe",
"Santo Antônio do Leverger" = "Santo Antônio de Leverger",
"Eldorado dos Carajás" = "Eldorado do Carajás",
"Santa Isabel do Pará" = "Santa Izabel do Pará",
"Iguaraci" = "Iguaracy",
"Lagoa do Itaenga" = "Lagoa de Itaenga",
"Arez" = "Arês",
"Boa Saúde" = "Januário Cicco",
"Olho-D'Água do Borges" = "Olho d'Água do Borges",
"Espigão do Oeste" = "Espigão D'Oeste",
"Santana do Livramento" = "Sant'Ana do Livramento",
"Grão Pará" = "Grão-Pará",
"Amparo de São Francisco" = "Amparo do São Francisco",
"Graccho Cardoso" = "Gracho Cardoso",
"Biritiba-Mirim" = "Biritiba Mirim",
"Couto de Magalhães" = "Couto Magalhães",
"Fortaleza do Tabocão" = "Tabocão",
"São Valério da Natividade" = "São Valério"
)
Definimos duas funções para auxiliar no tratamento dos dados:
apply_corrections: essa função verifica se o nome da
cidade está na lista de correções e, se estiver, substitui pelo nome
correto.get_estado_localidade: esta função verifica se o
CEP/zipcode está dentro de uma faixa válida e retorna o estado e a
localidade corretos.apply_corrections <- function(city_name, corrections) {
if (city_name %in% names(corrections)) {
return(corrections[[city_name]])
} else {
return(city_name)
}
}
get_estado_localidade <- function(cep) {
subset <- ceps %>%
filter(cep >= `CEP Inicial` & cep <= `CEP Final`)
if (nrow(subset) == 1) {
return(list(Estado = subset$Estado, Localidade = subset$Localidade))
} else {
return(list(Estado = NA, Localidade = NA))
}
}
Aplicamos as correções nos nomes das cidades da coluna
Localidade de ceps:
#executando função que aplica as correções
ceps <- ceps %>%
mutate(Localidade = sapply(Localidade, apply_corrections, corrections = corrections_))
#visualização do cabeçallho de ceps
head(ceps)
## # A tibble: 6 × 4
## Estado Localidade `CEP Inicial` `CEP Final`
## <chr> <chr> <dbl> <dbl>
## 1 AC Acrelândia 69945000 69949999
## 2 AC Assis Brasil 69935000 69939999
## 3 AC Brasiléia 69932000 69933999
## 4 AC Bujari 69926000 69926999
## 5 AC Capixaba 69931000 69931999
## 6 AC Cruzeiro do Sul 69980000 69981999
Podemos notar que as colunas CEP Incial e CEP Final
de ceps estão com a númeração completa, vamos tratar isso,
removendo os três últimos dígitos de cada coluna para garantir que
representem corretamente a faixa de CEP:
# Verificando o tipo de dados das colunas CEP Inicial e CEP Final
str(ceps$`CEP Inicial`)
## num [1:5573] 69945000 69935000 69932000 69926000 69931000 ...
str(ceps$`CEP Final`)
## num [1:5573] 69949999 69939999 69933999 69926999 69931999 ...
# Convertendo as colunas para inteiro, removendo os 3 últimos dígitos e convertendo de volta para inteiro
ceps <- ceps %>%
mutate(`CEP Inicial` = as.integer(`CEP Inicial`),
`CEP Final` = as.integer(`CEP Final`)) %>%
mutate(`CEP Inicial` = as.character(`CEP Inicial`),
`CEP Final` = as.character(`CEP Final`)) %>%
mutate(`CEP Inicial` = substr(`CEP Inicial`, 1, nchar(`CEP Inicial`) - 3),
`CEP Final` = substr(`CEP Final`, 1, nchar(`CEP Final`) - 3)) %>%
mutate(`CEP Inicial` = as.integer(`CEP Inicial`),
`CEP Final` = as.integer(`CEP Final`))
# Verificando as mudanças nas colunas após o tratamento
head(ceps)
## # A tibble: 6 × 4
## Estado Localidade `CEP Inicial` `CEP Final`
## <chr> <chr> <int> <int>
## 1 AC Acrelândia 69945 69949
## 2 AC Assis Brasil 69935 69939
## 3 AC Brasiléia 69932 69933
## 4 AC Bujari 69926 69926
## 5 AC Capixaba 69931 69931
## 6 AC Cruzeiro do Sul 69980 69981
Atualizamos então os conjuntos de dados order_customer e
sellers utilizando o CEP da coluna
customer_zip_code_prefix e seller_zip_code_prefix e a
função get_estado_localidade:
#Atualizando order_customer e sellers por meio do CEP da coluna zip_code_prefix.
order_customer <- order_customer %>%
mutate(
Estado_Localidade = map(order_customer$customer_zip_code_prefix, get_estado_localidade),
customer_state = sapply(Estado_Localidade, function(x) x$Estado),
customer_city = sapply(Estado_Localidade, function(x) x$Localidade)
) %>%
select(-Estado_Localidade)
sellers <- sellers %>%
mutate(
Estado_Localidade = map(sellers$seller_zip_code_prefix, get_estado_localidade),
seller_state = sapply(Estado_Localidade, function(x) x$Estado),
seller_city = sapply(Estado_Localidade, function(x) x$Localidade)
) %>%
select(-Estado_Localidade)
Após o tratamento, verificamos se há cidades que ficaram nulas nos
conjuntos order_customer e sellers comparando
com o df_municipios. Observamos que no conjunto
sellers não há cidades nulas, mas no conjunto
order_customer há 24 linhas onde as cidades ficaram nulas.
Porém podemos ver que os CEPS não foram anulados.
#Resetar as colunas seller_city_clean e customer_city_clean com as atualizações
sellers <- sellers %>%
mutate(seller_city_clean = tolower(stri_trans_general(seller_city, "Latin-ASCII")))
order_customer <- order_customer %>%
mutate(customer_city_clean = tolower(stri_trans_general(customer_city, "Latin-ASCII")))
result_seller_city <- sellers %>%
filter(!seller_city_clean %in% df_municipios$municipio_nome_clean)
head(result_seller_city)
## [1] seller_id seller_zip_code_prefix seller_city
## [4] seller_state seller_city_clean
## <0 linhas> (ou row.names de comprimento 0)
result_customer_city <- order_customer %>%
filter(!customer_city_clean %in% df_municipios$municipio_nome_clean)
head(result_customer_city)
## customer_id customer_unique_id
## 1 fe196aba95e52d084e7bb60dbd8a23f1 93b4c8bdafa9877757c77b519415d274
## 2 81eaa0c0dfb54f5f9d7d11734f162e65 b0369cc51e0e1618a76c7174132b93cc
## 3 a059473225838f7005cf82e2f6b9a18d 1df28da6a384e9822da017c6d44b0656
## 4 4560c6d8bfdd3e61555dca85d900e1e6 ad054a269e8691d8e2727d1611f3950e
## 5 110d797e5a5055538df046c2cad8f3d4 1a4d4db5393b394803df246ca68872b4
## 6 988126b4ddf725d9724e4318872ea2ae 507dc9becd4fc65635d90682dfa9d3a3
## customer_zip_code_prefix customer_city customer_state customer_city_clean
## 1 89130 <NA> <NA> <NA>
## 2 89130 <NA> <NA> <NA>
## 3 89130 <NA> <NA> <NA>
## 4 89130 <NA> <NA> <NA>
## 5 98900 <NA> <NA> <NA>
## 6 98900 <NA> <NA> <NA>
length(unique(result_customer_city$customer_zip_code_prefix))
## [1] 3
unique(result_customer_city$customer_zip_code_prefix)
## [1] 89130 98900 65935
Vamos utilizar as colunas com dados nulos, utilizando o prefixo do CEP para corrigi-los manualmente. Além disso, aproveitaremos para corrigir a cidade “Bom Jesus de Goiás”, que estava com erro no início do processo, também inclui “Santa Terezinha - BA”, pelo menos motivo.
order_customer <- order_customer %>%
mutate(customer_city_clean = case_when(
customer_zip_code_prefix == 65935 ~ "senador la rocque",
customer_zip_code_prefix == 89130 ~ "indaial",
customer_zip_code_prefix == 98900 ~ "santa rosa",
customer_zip_code_prefix == 75570 ~ "bom jesus de goias",
customer_zip_code_prefix == 44590 ~ "santa terezinha",
TRUE ~ customer_city_clean # Mantém o valor original se nenhuma condição for atendida
)) %>% mutate(customer_state = case_when(
customer_zip_code_prefix == 65935 ~ "MA",
customer_zip_code_prefix == 89130 ~ "SC",
customer_zip_code_prefix == 98900 ~ "RS",
customer_zip_code_prefix == 75570 ~ "GO",
customer_zip_code_prefix == 44590 ~ "BA",
TRUE ~ customer_state # Mantém o valor original se nenhuma condição for atendida
)) %>% mutate(customer_city = case_when(
customer_zip_code_prefix == 65935 ~ "Senador La Rocque",
customer_zip_code_prefix == 89130 ~ "Indaial",
customer_zip_code_prefix == 98900 ~ "Santa Rosa",
customer_zip_code_prefix == 75570 ~ "Bom Jesus de Goiás",
customer_zip_code_prefix == 44590 ~ "Santa Terezinha",
TRUE ~ customer_city # Mantém o valor original se nenhuma condição for atendida
))
Revisamos novamente se há mais inconsistências nos dados após a
correção manual. Verificaremos se há cidades que ainda não correspondem
corretamente aos dados do df_municipios:
# Resetando as colunas customer_city_clean e seller_city_clean com as atualizações
order_customer <- order_customer %>%
mutate(customer_city_clean = tolower(stri_trans_general(customer_city, "Latin-ASCII")))
# Verificando as cidades que estão em order_customer mas não estão em df_municipios
result_customer_city <- order_customer %>%
filter(!customer_city_clean %in% df_municipios$municipio_nome_clean)
head(result_customer_city)
## [1] customer_id customer_unique_id customer_zip_code_prefix
## [4] customer_city customer_state customer_city_clean
## <0 linhas> (ou row.names de comprimento 0)
length(unique(result_customer_city$customer_city))
## [1] 0
# Verificando as cidades que estão em sellers mas não estão em df_municipios
result_seller_city <- sellers %>%
filter(!seller_city_clean %in% df_municipios$municipio_nome_clean)
head(result_seller_city)
## [1] seller_id seller_zip_code_prefix seller_city
## [4] seller_state seller_city_clean
## <0 linhas> (ou row.names de comprimento 0)
length(unique(result_seller_city$seller_city))
## [1] 0
Iniciamos o processo de mesclagem dos conjuntos de dados da Olist para criar o conjunto de dados principal:
df <- inner_join(order_items, order_payments, by= "order_id")
## Warning in inner_join(order_items, order_payments, by = "order_id"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 39 of `x` matches multiple rows in `y`.
## ℹ Row 85983 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
## "many-to-many"` to silence this warning.
df <- inner_join(df, orders, by= "order_id")
df <- inner_join(df, order_customer, by= "customer_id")
df <- inner_join(df, reviews,by= "order_id")
## Warning in inner_join(df, reviews, by = "order_id"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 98 of `x` matches multiple rows in `y`.
## ℹ Row 15256 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
## "many-to-many"` to silence this warning.
df <- inner_join(df, products, by= "product_id")
df <- inner_join(df, sellers, by= "seller_id")
Para enriquecer nosso conjunto de dados com informações adicionais
sobre os municípios, definimos a função get_info_municipio.
Essa função busca no dataframe df_municipios informações
como o nome da microrregião, mesorregião, e a região do município
baseado no nome da cidade e estado.
get_info_municipio <- function(city, state) {
# Procurar pela correspondência no dataframe df_municipios
match_index <- which(df_municipios$municipio_nome_clean == city & df_municipios$`UF-sigla` == state)
# Verificar se encontrou uma correspondência
if (length(match_index) > 0) {
# Se encontrou, retornar um vetor com as informações relevantes
return(c(df_municipios$`UF-nome`[match_index],
df_municipios$`microrregiao-nome`[match_index],
df_municipios$`mesorregiao-nome`[match_index],
df_municipios$`regiao-nome`[match_index],
df_municipios$`municipio-nome`[match_index]
))
} else {
# Se não encontrou correspondência, retornar NA
return(rep(NA, 5))
}
}
Utilizamos essa função para adicionar informações detalhadas sobre os
municípios de vendedores e clientes aos nossos dados principais. Para
isso, aplicamos a função get_info_municipio aos campos de cidade e
estado dos vendedores e clientes, gerando novas colunas com as
informações complementares. Transformamos todas as colunas com datas no
formato POSIXct para faciitar a manipulação de dados com
data e tempo E por fim removemos as colunas não relevantes.
df <- df %>%
mutate(
info_municipio = map2(seller_city_clean, seller_state, get_info_municipio),
seller_UF = sapply(info_municipio, function(x) x[1]),
seller_microrregiao = sapply(info_municipio, function(x) x[2]),
seller_mesorregiao = sapply(info_municipio, function(x) x[3]),
seller_regiao = sapply(info_municipio, function(x) x[4]),
seller_city = sapply(info_municipio, function(x) x[5])
) %>%
select(-info_municipio)
df <- df %>%
mutate(
info_municipio = map2(customer_city_clean, customer_state, get_info_municipio),
customer_UF = sapply(info_municipio, function(x) x[1]),
customer_microrregiao = sapply(info_municipio, function(x) x[2]),
customer_regiao = sapply(info_municipio, function(x) x[4]),
customer_city = sapply(info_municipio, function(x) x[5])
) %>%
select(-info_municipio)
names(df)
## [1] "order_id" "order_item_id"
## [3] "product_id" "seller_id"
## [5] "shipping_limit_date" "price"
## [7] "freight_value" "payment_sequential"
## [9] "payment_type" "payment_installments"
## [11] "payment_value" "customer_id"
## [13] "order_status" "order_purchase_timestamp"
## [15] "order_approved_at" "order_delivered_carrier_date"
## [17] "order_delivered_customer_date" "order_estimated_delivery_date"
## [19] "customer_unique_id" "customer_zip_code_prefix"
## [21] "customer_city" "customer_state"
## [23] "customer_city_clean" "review_id"
## [25] "review_score" "review_comment_title"
## [27] "review_comment_message" "review_creation_date"
## [29] "review_answer_timestamp" "product_category_name"
## [31] "product_name_lenght" "product_description_lenght"
## [33] "product_photos_qty" "product_weight_g"
## [35] "product_length_cm" "product_height_cm"
## [37] "product_width_cm" "seller_zip_code_prefix"
## [39] "seller_city" "seller_state"
## [41] "seller_city_clean" "seller_UF"
## [43] "seller_microrregiao" "seller_mesorregiao"
## [45] "seller_regiao" "customer_UF"
## [47] "customer_microrregiao" "customer_regiao"
str(df$order_purchase_timestamp)
## chr [1:117329] "2017-09-13 08:59:02" "2017-04-26 10:53:06" ...
df$shipping_limit_date <- as.POSIXct(df$shipping_limit_date, format="%Y-%m-%d %H:%M:%S")
df$order_purchase_timestamp <- as.POSIXct(df$order_purchase_timestamp, format="%Y-%m-%d %H:%M:%S")
df$order_approved_at <- as.POSIXct(df$order_approved_at, format="%Y-%m-%d %H:%M:%S")
df$order_delivered_carrier_date <- as.POSIXct(df$order_delivered_carrier_date, format="%Y-%m-%d %H:%M:%S")
df$order_delivered_customer_date <- as.POSIXct(df$order_delivered_customer_date, format="%Y-%m-%d %H:%M:%S")
df$order_estimated_delivery_date <- as.POSIXct(df$order_estimated_delivery_date, format="%Y-%m-%d")
df$review_creation_date <- as.POSIXct(df$review_creation_date, format="%Y-%m-%d %H:%M:%S")
df$review_answer_timestamp <- as.POSIXct(df$review_answer_timestamp, format="%Y-%m-%d %H:%M:%S")
df$order_purchase_year <- as.integer(format(df$order_purchase_timestamp, "%Y"))
df$order_purchase_month <- as.integer(format(df$order_purchase_timestamp, "%m"))
df$order_purchase_day <- as.integer(format(df$order_purchase_timestamp, "%d"))
df <- df %>%
select(, -product_photos_qty, -product_description_lenght, -product_name_lenght, -customer_city_clean, -seller_city_clean)
Esse é o dataframe resultante após os tratamentos dos dados.
datatable(head(df, n=400), options = list(scrollX = TRUE))
O dataframe resultante possui 117329 linhas e 74 categorias únicas de produtos.
nrow(df)
## [1] 117329
length(unique(df$product_category_name))
## [1] 74
Abaixo está o gráfico que mostra as categorias de produtos mais compradas no geral, em todas as regiões, dos anos 2016 à 2018:
O gráfico de barras ilustra as 10 categorias de produtos mais compradas no período analisado. Observa-se que as categorias de “Cama, Mesa e Banho” lideram as compras, seguidas por “Beleza/Saúde” e “Esporte/Lazer”. As demais categorias no ranking são:
df_hist <- df %>%
group_by(product_category_name) %>%
summarise(num_products = n()) %>%
arrange(desc(num_products)) %>%
top_n(10) # Selecionar as 10 maiores categorias
## Selecting by num_products
df_hist <- df_hist %>%
arrange(desc(num_products))
# Histograma de número de produtos por categoria
ggplot(df_hist, aes(x = reorder(product_category_name, num_products), y = num_products)) +
geom_bar(stat = "identity", fill = "steelblue") +
geom_text(aes(label = num_products), vjust = -0.5, size = 3, color = "black") +
labs(x = "Categoria de Produto", y = "Número de Produtos Comprados") +
ggtitle("Top 10 Categorias de Produtos Mais Compradas") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Este gráfico de barras ilustra as cinco categorias de produtos mais comprados em cada região do Brasil. Observa-se que a região Sudeste possui o maior número de compras, seguida pelas regiões Sul e Nordeste. As categorias de produtos mais compradas em todas as regiões incluem:
Analisando cada região, notamos as seguintes tendências:
df_ranking <- df %>%
group_by(customer_regiao, product_category_name) %>%
summarise(total_pedidos = n()) %>%
arrange(customer_regiao, desc(total_pedidos)) %>%
group_by(customer_regiao) %>%
mutate(rank = row_number()) %>%
group_by(customer_regiao) %>%
mutate(proporcao_pedidos = total_pedidos/sum(total_pedidos) * 100) %>%
mutate(proporcao_pedidos = round(proporcao_pedidos, 2)) %>%
filter(rank <= 5)
## `summarise()` has grouped output by 'customer_regiao'. You can override using
## the `.groups` argument.
p <- ggplot(df_ranking, aes(x = reorder(product_category_name, total_pedidos), y = total_pedidos, fill = customer_regiao)) +
geom_bar(stat = "identity", position = "dodge") +
coord_flip() +
labs(x = "Categoria de Produto", y = "Número de Pedidos", fill = "Região") +
ggtitle("Ranking das 5 Categorias de Produtos Mais Comprados por Região") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
p_interactive <- ggplotly(p, dynamicTicks = TRUE) %>%
layout(
title = "Ranking de Categorias de Produtos Mais Comprados por Região",
yaxis = list(autorange = TRUE)
) %>%
config(responsive = TRUE)
p_interactive
Este gráfico de barras, assim como o gráfico acima, ilustra as cinco categorias de produtos mais comprados em cada região do Brasil, mas considerando a proporção de compras de cada categoria dentro de todas as categorias compradas na região. A proporção é calculada como a quantidade de produtos por categoria dividida pela soma de todos os produtos de todas as categorias na região.
Proporção de Compras por Categoria e Região:
Podemos observar que no e-commerce, as categorias mais comercializadas com base no conjunto de dados diferem para cada região. Mas no geral, as categorias “Beleza/Saúde” e “Esporte/Lazer” se destacam. Para contextos específicos como na Centro-Oeste, Sudeste e Sul, as categorias “Móveis e Decoração” e “Cama, Mesa e Banho” são bem requisitadas, sugerindo uma preferência por itens de conforto e utilidade doméstica nessas regiões. No Norte e Nordeste, as categorias “Relógios/Presentes” e “Telefonia” têm uma representação significativa, indicando uma demanda por itens relacionados a presentes e comunicação. Vale destacar que essa análise reflete exclusivamente o e-commerce da Olist.
p2 <- ggplot(df_ranking, aes(x = reorder(product_category_name, proporcao_pedidos), y = proporcao_pedidos, fill = customer_regiao)) +
geom_bar(stat = "identity", position = "dodge") +
coord_flip() +
labs(x = "Categoria de Produto", y = "Proporção", fill = "Região") +
ggtitle("Percentual das 5 Categorias de Produtos Mais Comprados por Região") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
p_interactive <- ggplotly(p2, dynamicTicks = TRUE) %>%
layout(
title = "Ranking de Categorias de Produtos Mais Comprados por Região",
yaxis = list(autorange = TRUE)
) %>%
config(responsive = TRUE)
p_interactive
gerar_grafico_categorias <- function(df, ano_especifico, regiao_especifica) {
df_filtrado <- df %>%
filter(order_purchase_year == ano_especifico, customer_regiao == regiao_especifica)
top_categorias_mes <- df_filtrado %>%
group_by(order_purchase_month, product_category_name) %>%
summarise(total_pedidos = n(), .groups = 'drop') %>%
arrange(desc(total_pedidos)) %>%
group_by(order_purchase_month) %>%
slice_max(total_pedidos, n = 3) %>%
ungroup()
top_categorias_mes$order_purchase_month <- factor(top_categorias_mes$order_purchase_month, levels = 1:12, labels = month.name[1:12])
p <- ggplot(top_categorias_mes, aes(x = order_purchase_month, y = total_pedidos, fill = product_category_name)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Mês", y = "Total de Pedidos", fill = "Categoria", title = paste("Categorias Mais Compradas por Mês na Região", regiao_especifica, "em", ano_especifico)) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
p_interactive <- ggplotly(p, dynamicTicks = TRUE) %>%
layout(
title = list(paste("Categorias Mais Compradas por Mês na Região", regiao_especifica, "em", ano_especifico),
font = list(size = 14)
),
xaxis = list(title = "Mês"),
yaxis = list(title = "Total de Pedidos"),
legend = list(title = list(text = "Categoria"))
) %>%
config(responsive = TRUE)
return(p_interactive)
}
Vamos usar os anos 2017 e 2018 como referência, pois os anos de 2016 estão limitados ao mês de Outubro. Nessa região, podemos verificar uma tendência maior de compras de “Beleza e Saúde” de junho a agosto e de novembro a dezembro, o que se repete em 2018 com a inclusão dos meses de março, abril e maio. “Cama, Mesa e Banho” é popular na maior parte do ano. “Esporte e Lazer” tem destaque em boa parte do ano, exceto em maio e agosto. Para “Informática”, os meses em destaque são fevereiro, maio e novembro. Relógios e Presentes se destacam em março, abril, junho e julho.
gerar_grafico_categorias(df, 2016, "Centro-Oeste")
gerar_grafico_categorias(df, 2017, "Centro-Oeste")
gerar_grafico_categorias(df, 2018, "Centro-Oeste")
Nessa região, “Beleza e Saúde” são constantes ao longo do ano, com uma leve redução apenas em janeiro. Esporte e Lazer é mais constante nos meses de julho a outubro e também em dezembro. Para “informática”, há uma constância no começo do ano, de janeiro a abril, e em novembro. “Relógios e Presentes” têm um pico em maio e julho. Para “Telefonia”, observa-se um foco em outubro, novembro, janeiro e março.
gerar_grafico_categorias(df, 2016, "Nordeste")
gerar_grafico_categorias(df, 2017, "Nordeste")
gerar_grafico_categorias(df, 2018, "Nordeste")
Nessa região, “Beleza e Saúde” são constantes ao longo do ano, com uma leve redução apenas em setembro e outubro. “Esporte e Lazer” possuem um pico em janeiro, abril e setembro. Para “acessórios e Informática”, os pontos altos são outubro, julho e janeiro. “Relógios e Presentes” são populares em julho, novembro e janeiro. E telefonia é popular o ano todo com exceção de abril.
gerar_grafico_categorias(df, 2016, "Norte")
gerar_grafico_categorias(df, 2017, "Norte")
gerar_grafico_categorias(df, 2018, "Norte")
Nessa região, não há muitos dados sobre “Beleza e Saúde”, apesar de possuir o maior índice de vendas em relação às outras regiões. Em 2017, o índice é baixo por mês, exceto por um alto pico em setembro, e é constante em 2018 entre os meses de abril e agosto. “Cama, Mesa e Banho” possui mais vendas entre julho e novembro em 2017, com um pico alto em novembro, e em 2018 possui um pico alto em janeiro, indicando que as vendas são mais populares nos fins e começos de ano. Para “Esporte e Lazer”, não há muitos dados em 2018, mas em 2017 o pico foi entre outubro e novembro. Não há dados suficientes em “Informática” em 2017, só há vendas em maio, e em 2018 apenas entre janeiro e março. O pico de “Móveis e Decoração” é em novembro, e “Utilidades Domésticas” entre maio e agosto, levando em conta todos os anos.
gerar_grafico_categorias(df, 2016, "Sudeste")
gerar_grafico_categorias(df, 2017, "Sudeste")
gerar_grafico_categorias(df, 2018, "Sudeste")
Na região Sul, a categoria “Beleza e Saúde” foi mais frequente nos meses de outubro em 2016, setembro em 2017, e de junho a agosto em 2018, indicando que as vendas provavelmente ocorrem mais nesses períodos. “Cama, Mesa e Banho” é constante o ano todo, com exceção de março, e o pico de vendas ocorre em novembro e janeiro. Para “Esporte e Lazer”, o gráfico de 2017 mostra que de julho a outubro há uma grande quantidade de vendas, voltando a aparecer em dezembro. Para “Informática”, a maior frequência de vendas é em novembro e fevereiro. “Móveis e Decoração” tiveram picos em novembro de 2017 e em março e abril de 2018. “Utilidades Domésticas” registraram frequências maiores de vendas em maio e junho de 2017, e em maio, julho e agosto de 2018, indicando que as vendas ocorrem mais no meio do ano.
gerar_grafico_categorias(df, 2016, "Sul")
gerar_grafico_categorias(df, 2017, "Sul")
gerar_grafico_categorias(df, 2018, "Sul")
A partir dos gráficos, nota-se que a categoria “Cama, Mesa e Banho” é a mais frequente, estando presente entre as categorias mais vendidas nas regiões, dependendo do ano. Logo após, destacam-se “Beleza e Saúde” e “Esporte e Lazer”.
Em cada estado, há peculiaridades diferentes no comportamento de compra dos consumidores. No Sudeste, por exemplo, observa-se uma disparidade significativa entre os clientes que compram as cinco categorias mais populares, indicando que é o maior mercado consumidor do e-commerce da Olist. Além disso, há um aumento nas compras no mês de novembro, provavelmente devido à Black Friday. O início e o meio do ano também são períodos de destaque, possivelmente devido a datas comemorativas como o Dia das Mães (abril e maio), Dia dos Namorados, Dia dos Pais e outras datas festivas.
Esses padrões indicam a importância de adaptar o estoque para as regiões que consomem mais determinados produtos de forma sazonal. Também é essencial otimizar a logística nas áreas onde essas categorias são mais compradas para aumentar a satisfação do cliente. Planejar campanhas de marketing e promoções conforme a demanda de cada região é uma estratégia importante. Além disso, estudar formas de aumentar as vendas de categorias menos populares em determinadas regiões pode trazer benefícios.
É importante lembrar que o conjunto de dados utilizado abrange aproximadamente 100 mil ordens de venda e 117.329 produtos vendidos, limitados aos anos de 2016 a 2018. Além disso, alguns meses de 2016 e 2018 não foram coletados. Portanto, mais dados são necessários para aprofundar a análise e também verificar outros conjuntos de dados de vendas além dos da Olist.