Estatística para Cientistas de Dados 26.1

Author

Anabella Sgarbi Pereira

Published

March 9, 2026

1 Carregando os pacotes

library(tidyverse)
library(readr)
library(gt)
library(summarytools)
library(ggplot2)
library(corrplot)
library(patchwork)

1.1 Descrição dos pacotes

tidyverse para manipulação e transformação de base de dados
readr para carregar as bases de dados
gt para melhorar a visualização de tabelas
summarytools para gerar descrição estatística das variáveis
ggplot2 para gerar gráficos
corrplot para fazer a matriz de correlação entre variáveis
patchwork para combinar gráficos dentro de uma função

2 Carregando os dados

reviews = read_csv("olist_order_reviews_dataset.csv")
pedidos = read_csv("olist_orders_dataset.csv")
pagamentos = read_csv("olist_order_payments_dataset.csv")
itens = read_csv("olist_order_items_dataset.csv")

2.1 Descrição das bases de dados

A base olist_order_reviews_dataset contém as avaliações feitas pelos clientes após a entrega dos pedidos. Cada registro corresponde a uma avaliação associada a um pedido específico. A base inclui informações como a nota atribuída pelo cliente (de 1 a 5), o identificador da avaliação, o identificador do pedido e timestamps relacionados ao envio e à criação da avaliação. Esses dados permitem analisar o nível de satisfação dos clientes e investigar possíveis fatores associados a avaliações negativas.

head(reviews) |> 
  gt()
review_id order_id review_score review_comment_title review_comment_message review_creation_date review_answer_timestamp
7bc2406110b926393aa56f80a40eba40 73fc7af87114b39712e6da79b0a377eb 4 NA NA 2018-01-18 2018-01-18 21:46:59
80e641a11e56f04c1ad469d5645fdfde a548910a1c6147796b98fdf73dbeba33 5 NA NA 2018-03-10 2018-03-11 03:05:13
228ce5500dc1d8e020d8d1322874b6f0 f9e4b658b201a9f2ecdecbb34bed034b 5 NA NA 2018-02-17 2018-02-18 14:36:24
e64fb393e7b32834bb789ff8bb30750e 658677c97b385a9be170737859d3511b 5 NA Recebi bem antes do prazo estipulado. 2017-04-21 2017-04-21 22:02:06
f7c4243c7fe1938f181bec41a392bdeb 8e6bfb81e283fa7e4f11123a3fb894f1 5 NA Parabéns lojas lannister adorei comprar pela Internet seguro e prático Parabéns a todos feliz Páscoa 2018-03-01 2018-03-02 10:26:53
15197aa66ff4d0650b5434f1b46cda19 b18dcdf73be66366873cd26c5724d1dc 1 NA NA 2018-04-13 2018-04-16 00:39:37

A base olist_orders_dataset reúne informações gerais sobre os pedidos realizados na plataforma. Cada registro corresponde a um pedido único e inclui dados como o identificador do pedido, o identificador do cliente e diversas datas associadas ao processo logístico, incluindo aprovação do pedido, envio ao transportador, entrega ao cliente e prazo estimado de entrega. Essa base é fundamental para analisar o desempenho logístico e calcular métricas como tempo de entrega e ocorrência de atrasos.

head(pedidos) |>
  gt()
order_id customer_id order_status order_purchase_timestamp order_approved_at order_delivered_carrier_date order_delivered_customer_date order_estimated_delivery_date
e481f51cbdc54678b7cc49136f2d6af7 9ef432eb6251297304e76186b10a928d delivered 2017-10-02 10:56:33 2017-10-02 11:07:15 2017-10-04 19:55:00 2017-10-10 21:25:13 2017-10-18
53cdb2fc8bc7dce0b6741e2150273451 b0830fb4747a6c6d20dea0b8c802d7ef delivered 2018-07-24 20:41:37 2018-07-26 03:24:27 2018-07-26 14:31:00 2018-08-07 15:27:45 2018-08-13
47770eb9100c2d0c44946d9cf07ec65d 41ce2a54c0b03bf3443c3d931a367089 delivered 2018-08-08 08:38:49 2018-08-08 08:55:23 2018-08-08 13:50:00 2018-08-17 18:06:29 2018-09-04
949d5b44dbf5de918fe9c16f97b45f8a f88197465ea7920adcdbec7375364d82 delivered 2017-11-18 19:28:06 2017-11-18 19:45:59 2017-11-22 13:39:59 2017-12-02 00:28:42 2017-12-15
ad21c59c0840e6cb83a9ceb5573f8159 8ab97904e6daea8866dbdbc4fb7aad2c delivered 2018-02-13 21:18:39 2018-02-13 22:20:29 2018-02-14 19:46:34 2018-02-16 18:17:02 2018-02-26
a4591c265e18cb1dcee52889e2d8acc3 503740e9ca751ccdda7ba28e9ab8f608 delivered 2017-07-09 21:57:05 2017-07-09 22:10:13 2017-07-11 14:58:04 2017-07-26 10:57:55 2017-08-01

A base olist_order_payments_dataset contém informações sobre os pagamentos realizados para cada pedido. Um mesmo pedido pode possuir mais de um registro nesta base, representando diferentes parcelas ou formas de pagamento utilizadas pelo cliente. As variáveis incluem o tipo de pagamento, o número de parcelas e o valor pago. Esses dados permitem analisar padrões financeiros das transações e a relação entre valores pagos e satisfação do cliente.

head(pagamentos) |> 
  gt()
order_id payment_sequential payment_type payment_installments payment_value
b81ef226f3fe1789b1e8b2acac839d17 1 credit_card 8 99.33
a9810da82917af2d9aefd1278f1dcfa0 1 credit_card 1 24.39
25e8ea4e93396b6fa0d3dd708e76c1bd 1 credit_card 1 65.71
ba78997921bbcdc1373bb41e913ab953 1 credit_card 8 107.78
42fdf880ba16b47b59251dd489d4441a 1 credit_card 2 128.45
298fcdf1f73eb413e4d26d01b25bc1cd 1 credit_card 2 96.12

A base olist_order_items_dataset descreve os produtos incluídos em cada pedido. Como um pedido pode conter múltiplos produtos, cada linha representa um item específico dentro de um pedido. A base inclui informações como identificador do produto, vendedor, preço do item e valor do frete associado. Esses dados permitem analisar o valor total dos pedidos e características dos produtos vendidos.

head(itens) |> 
  gt()
order_id order_item_id product_id seller_id shipping_limit_date price freight_value
00010242fe8c5a6d1ba2dd792cb16214 1 4244733e06e7ecb4970a6e2683c13e61 48436dade18ac8b2bce089ec2a041202 2017-09-19 09:45:35 58.90 13.29
00018f77f2f0320c557190d7a144bdd3 1 e5f2d52b802189ee658865ca93d83a8f dd7ddc04e1b6c2c614352b383efe2d36 2017-05-03 11:05:13 239.90 19.93
000229ec398224ef6ca0657da4fc703e 1 c777355d18b72b67abbeef9df44fd0fd 5b51032eddd242adc84c38acab88f23d 2018-01-18 14:48:30 199.00 17.87
00024acbcdf0a6daa1e931b038114c75 1 7634da152a4610f1595efa32f14722fc 9d7a1d34a5052409006425275ba1c2b4 2018-08-15 10:10:18 12.99 12.79
00042b26cf59d7ce69dfabb4e55b4fd9 1 ac6c3623068f30de03045865e4e10089 df560393f3a51e74553ab94004ba5c87 2017-02-13 13:57:51 199.90 18.14
00048cc3ae777c65dbb7d2a0634bc1ea 1 ef92defde845ab8450f9d70c526ef70f 6426d21aca402a131fc0a5d0960a3c90 2017-05-23 03:55:27 21.90 12.69

3 Objetivo da análise

O objetivo da presente análise consiste em identificar o impacto de fatores logísticos e financeiros em avaliações negativas de clientes no e-commerce brasileiro, utilizando dados públicos da plataforma Olist (2016-2018).

Espera-se que fatores logísticos, como atraso na entrega, tenham maior impacto na avaliação negativa do que variáveis financeiras, como valor do pedido e do frete.

A escolha por esta base de dados se deu, principalmente, pelo alinhamento ao meu campo de atuação profissional atual (marketing). Entender o comportamento do consumidor brasileiro no contexto digital é algo de grande interesse para mim.

4 Estudo e limpeza de dados

Descobrindo quantos pedidos foram entregues no total:

pedidos |>
  count(order_status) |>
  gt()
order_status n
approved 2
canceled 625
created 5
delivered 96478
invoiced 314
processing 301
shipped 1107
unavailable 609

Filtrando os pedidos com status “delivered”, de modo a iniciar a limpeza da base de dados que não cabem na análise:

delivered = pedidos |> 
  filter(order_status == "delivered")

Identificando quantos dos pedidos entregues possuem reviews:

reviews |> 
  summarise(total_reviews = n_distinct(order_id)) |> 
  gt()
total_reviews
98673

Observa-se que há mais reviews do que pedidos entregues. Verificando se há mais de uma review por pedido:

reviews |> 
  count(order_id) |> 
  filter(n > 1) |> 
  head(5) |> 
  gt()
order_id n
0035246a40f520710769010f752e7507 2
013056cfe49763c6f66bda03396c5ee3 2
0176a6846bcb3b0d3aa3116a9a768597 2
02355020fd0a40a0d56df9f6ff060413 2
029863af4b968de1e5d6a82782e662f5 2

Observa-se que há mais de uma review por pedido. Verificando se a review é feita por item ou por pedido:

reviews |> 
  count(order_id) |> 
  filter(n > 1) |> 
  slice(1) |> 
  gt()
order_id n
0035246a40f520710769010f752e7507 2
itens |> 
  filter(order_id == "0035246a40f520710769010f752e7507") |> 
  gt()
order_id order_item_id product_id seller_id shipping_limit_date price freight_value
0035246a40f520710769010f752e7507 1 8a6187b2665118d5095f99a25fd7ba7a 4a3ca9315b744ce9f8e9374361493884 2017-08-23 01:25:39 87 12.11
itens_por_pedido = itens |> 
  count(order_id)

reviews_por_pedido = reviews |> 
  count(order_id)

comparacao = itens_por_pedido |> 
  left_join(reviews_por_pedido, by = "order_id") |> 
  filter(n.x == 1 & n.y > 1) 

head(comparacao) |> 
  gt()
order_id n.x n.y
0035246a40f520710769010f752e7507 1 2
013056cfe49763c6f66bda03396c5ee3 1 2
0176a6846bcb3b0d3aa3116a9a768597 1 2
02355020fd0a40a0d56df9f6ff060413 1 2
029863af4b968de1e5d6a82782e662f5 1 2
02e0b68852217f5715fb9cc885829454 1 2

Observa-se que o review é feito a nível do pedido e que há mais de uma review por pedido, mesmo para aqueles com 1 único item. Identificando quantos pedidos possuem mais de uma review:

reviews |> 
  count(order_id) |> 
  filter(n > 1) |> 
  summarise(qtd_pedidos = n()) |> 
  gt()
qtd_pedidos
547
total_pedidos_com_review = reviews |> 
  distinct(order_id) |> 
  nrow()

pedidos_com_mais_de_uma_review = reviews |> 
  count(order_id) |> 
  filter(n > 1) |> 
  nrow()

percentual = (pedidos_com_mais_de_uma_review / total_pedidos_com_review) * 100

percentual
[1] 0.5543563

Observa-se que os pedidos com mais de uma review representam menos de 1% da base. Verificando se as reviews de um mesmo pedido possuem notas diferentes:

reviews_multiplas = reviews |> 
  group_by(order_id) |> 
  filter(n() > 1)
comparacao_notas = reviews_multiplas |> 
  group_by(order_id) |> 
  summarise(n_notas_distintas = n_distinct(review_score))
comparacao_notas  |> 
  count(n_notas_distintas) |> 
  gt()
n_notas_distintas n
1 345
2 202

Observa-se que 202 pedidos tiveram alteração de nota. Filtrando pela última review feita pelo cliente para cada pedido, de modo a evitar duplicação de observações (e aproveitando para remover reviews sem notas):

reviews_unicas = reviews |>
  filter(!is.na(.data$review_score)) |>
  arrange(order_id, review_answer_timestamp) |>
  group_by(order_id) |>
  slice_tail(n = 1) |>
  ungroup()

Como todas as reviews são feitas a nível do pedido, os dados referentes a fatores logísticos e financeiros também precisam estar alinhados a isso. Ajustando a base de itens para o nível do pedido:

itens_agg = itens |> 
  group_by(order_id) |> 
  summarise(
    total_produtos = n(),
    valor_produtos = sum(price),
    valor_frete = sum(freight_value),
    valor_total = sum(price + freight_value)
  )

4.1 Resumo da limpeza

  • Bases originais
# reviews
# pedidos
# pagamentos
# itens
  • Bases tratadas:
head(reviews_unicas) |> 
  gt()
review_id order_id review_score review_comment_title review_comment_message review_creation_date review_answer_timestamp
97ca439bc427b48bc1cd7177abe71365 00010242fe8c5a6d1ba2dd792cb16214 5 NA Perfeito, produto entregue antes do combinado. 2017-09-21 2017-09-22 10:57:03
7b07bacd811c4117b742569b04ce3580 00018f77f2f0320c557190d7a144bdd3 4 NA NA 2017-05-13 2017-05-15 11:34:13
0c5b33dea94867d1ac402749e5438e8b 000229ec398224ef6ca0657da4fc703e 5 NA Chegou antes do prazo previsto e o produto surpreendeu pela qualidade. Muito satisfatório. 2018-01-23 2018-01-23 16:06:31
f4028d019cb58564807486a6aaf33817 00024acbcdf0a6daa1e931b038114c75 4 NA NA 2018-08-15 2018-08-15 16:39:01
940144190dcba6351888cafa43f3a3a5 00042b26cf59d7ce69dfabb4e55b4fd9 5 NA Gostei pois veio no prazo determinado . 2017-03-02 2017-03-03 10:54:59
5e4e50af3b7960b7a10d86ec869509e8 00048cc3ae777c65dbb7d2a0634bc1ea 4 NA NA 2017-05-23 2017-05-24 19:00:09
head(itens_agg) |> 
  gt()
order_id total_produtos valor_produtos valor_frete valor_total
00010242fe8c5a6d1ba2dd792cb16214 1 58.90 13.29 72.19
00018f77f2f0320c557190d7a144bdd3 1 239.90 19.93 259.83
000229ec398224ef6ca0657da4fc703e 1 199.00 17.87 216.87
00024acbcdf0a6daa1e931b038114c75 1 12.99 12.79 25.78
00042b26cf59d7ce69dfabb4e55b4fd9 1 199.90 18.14 218.04
00048cc3ae777c65dbb7d2a0634bc1ea 1 21.90 12.69 34.59
head(delivered) |> 
  gt()
order_id customer_id order_status order_purchase_timestamp order_approved_at order_delivered_carrier_date order_delivered_customer_date order_estimated_delivery_date
e481f51cbdc54678b7cc49136f2d6af7 9ef432eb6251297304e76186b10a928d delivered 2017-10-02 10:56:33 2017-10-02 11:07:15 2017-10-04 19:55:00 2017-10-10 21:25:13 2017-10-18
53cdb2fc8bc7dce0b6741e2150273451 b0830fb4747a6c6d20dea0b8c802d7ef delivered 2018-07-24 20:41:37 2018-07-26 03:24:27 2018-07-26 14:31:00 2018-08-07 15:27:45 2018-08-13
47770eb9100c2d0c44946d9cf07ec65d 41ce2a54c0b03bf3443c3d931a367089 delivered 2018-08-08 08:38:49 2018-08-08 08:55:23 2018-08-08 13:50:00 2018-08-17 18:06:29 2018-09-04
949d5b44dbf5de918fe9c16f97b45f8a f88197465ea7920adcdbec7375364d82 delivered 2017-11-18 19:28:06 2017-11-18 19:45:59 2017-11-22 13:39:59 2017-12-02 00:28:42 2017-12-15
ad21c59c0840e6cb83a9ceb5573f8159 8ab97904e6daea8866dbdbc4fb7aad2c delivered 2018-02-13 21:18:39 2018-02-13 22:20:29 2018-02-14 19:46:34 2018-02-16 18:17:02 2018-02-26
a4591c265e18cb1dcee52889e2d8acc3 503740e9ca751ccdda7ba28e9ab8f608 delivered 2017-07-09 21:57:05 2017-07-09 22:10:13 2017-07-11 14:58:04 2017-07-26 10:57:55 2017-08-01
  • Base final analítica:
df = delivered |>
  left_join(reviews_unicas, by = "order_id") |>
  left_join(itens_agg, by = "order_id")

head(df) |> 
  gt()
order_id customer_id order_status order_purchase_timestamp order_approved_at order_delivered_carrier_date order_delivered_customer_date order_estimated_delivery_date review_id review_score review_comment_title review_comment_message review_creation_date review_answer_timestamp total_produtos valor_produtos valor_frete valor_total
e481f51cbdc54678b7cc49136f2d6af7 9ef432eb6251297304e76186b10a928d delivered 2017-10-02 10:56:33 2017-10-02 11:07:15 2017-10-04 19:55:00 2017-10-10 21:25:13 2017-10-18 a54f0611adc9ed256b57ede6b6eb5114 4 NA Não testei o produto ainda, mas ele veio correto e em boas condições. Apenas a caixa que veio bem amassada e danificada, o que ficará chato, pois se trata de um presente. 2017-10-11 2017-10-12 03:43:48 1 29.99 8.72 38.71
53cdb2fc8bc7dce0b6741e2150273451 b0830fb4747a6c6d20dea0b8c802d7ef delivered 2018-07-24 20:41:37 2018-07-26 03:24:27 2018-07-26 14:31:00 2018-08-07 15:27:45 2018-08-13 8d5266042046a06655c8db133d120ba5 4 Muito boa a loja Muito bom o produto. 2018-08-08 2018-08-08 18:37:50 1 118.70 22.76 141.46
47770eb9100c2d0c44946d9cf07ec65d 41ce2a54c0b03bf3443c3d931a367089 delivered 2018-08-08 08:38:49 2018-08-08 08:55:23 2018-08-08 13:50:00 2018-08-17 18:06:29 2018-09-04 e73b67b67587f7644d5bd1a52deb1b01 5 NA NA 2018-08-18 2018-08-22 19:07:58 1 159.90 19.22 179.12
949d5b44dbf5de918fe9c16f97b45f8a f88197465ea7920adcdbec7375364d82 delivered 2017-11-18 19:28:06 2017-11-18 19:45:59 2017-11-22 13:39:59 2017-12-02 00:28:42 2017-12-15 359d03e676b3c069f62cadba8dd3f6e8 5 NA O produto foi exatamente o que eu esperava e estava descrito no site e chegou bem antes da data prevista. 2017-12-03 2017-12-05 19:21:58 1 45.00 27.20 72.20
ad21c59c0840e6cb83a9ceb5573f8159 8ab97904e6daea8866dbdbc4fb7aad2c delivered 2018-02-13 21:18:39 2018-02-13 22:20:29 2018-02-14 19:46:34 2018-02-16 18:17:02 2018-02-26 e50934924e227544ba8246aeb3770dd4 5 NA NA 2018-02-17 2018-02-18 13:02:51 1 19.90 8.72 28.62
a4591c265e18cb1dcee52889e2d8acc3 503740e9ca751ccdda7ba28e9ab8f608 delivered 2017-07-09 21:57:05 2017-07-09 22:10:13 2017-07-11 14:58:04 2017-07-26 10:57:55 2017-08-01 89b738e70a1ce346db29a20fb2910161 4 NA NA 2017-07-27 2017-07-27 22:48:30 1 147.90 27.36 175.26

5 Análise descritiva

5.1 Panorama geral das reviews (sentimento)

Esta parte da análise é dedicada a contextualizar o comportamento geral da variável numérica discreta “notas” e os sentimentos representados por ela.

Considerando:

  • Reviews negativas = nota igual ou abaixo de 2

  • Reviews neutras = nota 3

  • Reviews positivas = nota igual ou acima de 4

Gráfico de barras para observação da distribuição dos sentimentos das reviews:

# Criando as variáveis categóricas
df = df |> 
  mutate(
    categoria_nota = factor(
      case_when(
        review_score <= 2 ~ "Negativa",
        review_score == 3 ~ "Neutra",
        review_score >= 4 ~ "Positiva"
      ),
      levels = c("Negativa", "Neutra", "Positiva")
    ))
# Criando o gráfico
df |>
  filter(!is.na(categoria_nota)) |>
  ggplot(aes(x = categoria_nota, fill = categoria_nota)) +
  geom_bar() +
  scale_fill_manual(values = c(
    "Negativa" = "#d73027",
    "Neutra" = "#fee08b",
    "Positiva" = "#1a9850"
  )) +
  theme_minimal() +
  labs (
    x = "Sentimento da review",
    y = "Frequência",
    title = "Distribuição do sentimento das avaliações",
    subtitle = "Base de dados: df"
  ) +
  theme(legend.position = "none")

Pode-se calcular a proporção das notas negativas:

df |> 
  summarise(
    prop_negativas = round((sum(review_score <= 2, na.rm = TRUE) / n()) * 100)
  ) |> 
  gt()
prop_negativas
13

Observa-se que as reviews negativas representam cerca de 13% do total de reviews com notas.

5.1.1 Diagnóstico geral do sentimento das reviews

  • Majoritariamente positivo

  • Com minoria negativa, mas suficiente para análise de impacto

5.2 Impacto de fatores logísticos

Esta parte da análise dedica-se a compreender se fatores logísticos influenciam a probabilidade de uma avaliação negativa dentre os pedidos entregues.

Variáveis logísticas consideradas para essa análise:

  • Atraso na entrega: variável binária que responde se houve atraso na entrega ou não
df = df |> 
  mutate(
    order_delivered_customer_date = as.Date(order_delivered_customer_date),
    order_estimated_delivery_date = as.Date(order_estimated_delivery_date),
    atraso_dias = as.numeric(order_delivered_customer_date - order_estimated_delivery_date),
    entrega_atrasada = atraso_dias > 0
  )
  • Tempo de entrega: variável que contabiliza os dias desde a confirmação da compra até a entrega
df = df |> 
  mutate(
    order_approved_at = as.Date(order_approved_at),
    tempo_entrega = as.numeric(order_delivered_customer_date - order_approved_at)
  )

Descrição estatística para contextualizar o comportamento geral destas variáveis:

df |> 
  dplyr::select(atraso_dias, tempo_entrega) |> 
  summarytools::descr()
Descriptive Statistics  
df  
N: 96478  

                    atraso_dias   tempo_entrega
----------------- ------------- ---------------
             Mean        -11.88           11.98
          Std.Dev         10.18            9.53
              Min       -147.00           -7.00
               Q1        -17.00            6.00
           Median        -12.00           10.00
               Q3         -7.00           15.00
              Max        188.00          208.00
              MAD          7.41            5.93
              IQR         10.00            9.00
               CV         -0.86            0.79
         Skewness          2.02            3.86
      SE.Skewness          0.01            0.01
         Kurtosis         28.07           39.79
          N.Valid      96470.00        96456.00
                N      96478.00        96478.00
        Pct.Valid         99.99           99.98
# Criando função para calcular normalidade
plot_normalidade = function(dados, var, bins = 30, xlim = NULL){
  
  var_enquo = rlang::enquo(var)
  
  vetor = dados |> dplyr::pull(!!var_enquo)
  
  media = mean(vetor, na.rm = TRUE)
  mediana = median(vetor, na.rm = TRUE)
  
  p1 = dados |> 
    ggplot(aes(x = !!var_enquo)) +
    geom_histogram(
      aes(y = after_stat(density)),
      bins = bins,
      fill = "lightblue",
      color = "black"
    ) +
    geom_density(color = "darkblue", linewidth = 0.8, alpha = 0.3) +
    theme_minimal() +
    labs(
      title = paste0("Distribuição - ", rlang::as_name(var_enquo)),
      x = rlang::as_name(var_enquo),
      y = "Densidade"
    )
  
  # aplicar limite do eixo x se for especificado
  if(!is.null(xlim)){
    p1 = p1 + coord_cartesian(xlim = xlim)
  }
  
  p2 = dados |> 
    ggplot(aes(sample = !!var_enquo)) +
    stat_qq(size = 2, alpha = 0.6) +
    stat_qq_line(color = "red", linewidth = 1) +
    theme_minimal() +
    labs(
      title = paste0("QQ plot - ", rlang::as_name(var_enquo)),
      x = "Quantis teóricos",
      y = "Quantis amostrais"
    )
  
  p1 + p2
}
df |> 
plot_normalidade(atraso_dias, bins = 75, xlim = c(-60, 60))

df |> 
plot_normalidade(tempo_entrega, bins = 60, xlim = c(-10, 60))

OBS: A quantidade de bins escolhida para ambos os histogramas foi o valor encontrado que melhor permite a visualização da distribuição das observações.

df |>
  filter(!is.na(entrega_atrasada)) |>
  ggplot(aes(x = entrega_atrasada, fill = entrega_atrasada)) +
  geom_bar() +
  scale_fill_manual(values = c(
    "FALSE" = "#d73027",
    "TRUE" = "#1a9850"
  )) +
  theme_minimal() +
  labs (
    x = "Entrega atrasada?",
    y = "Frequência",
    title = "Frequência de entregas atrasadas",
    subtitle = "Base de dados: df"
  ) +
  theme(legend.position = "none")

O histograma e o QQ plot indicam que atraso_dias não segue distribuição normal, com forte concentração de valores próximos de zero e presença de alguns valores extremos. A mediana de -12 dias indica que a maioria dos pedidos apresenta atraso baixo ou inexistente. O IQR foi de cerca de 10 dias, representando a dispersão dos 50% centrais dos atrasos observados.

O gráfico de barras confirma o resultado da mediana, indicando que entregas atrasadas representam menos de 10% das observações.

Já a variável tempo_entrega apresenta assimetria à direita, com maior concentração de valores baixos e cauda longa à direita. A mediana foi de 10 dias, indicando o prazo típico de entrega. O IQR foi de cerca de 9 dias, descrevendo a variabilidade dos tempos de entrega mais comuns sem grande influência de valores extremos.

  • Comparando a proporção de reviews negativas vs atraso: quando há atraso, aumenta a chance de avaliação negativa?
df |>
  mutate(faixa_atraso = floor(atraso_dias/5)*5) |>
  group_by(faixa_atraso) |>
  summarise(media_review = mean(review_score, na.rm = TRUE)) |>
  ggplot(aes(x = faixa_atraso, y = media_review)) +
  geom_line(linewidth = 1.2, color = "red") +
  theme_minimal() +
  labs(
    title = "Nota média da review por tempo de atraso",
    x = "Tempo de atraso (dias)",
    y = "Nota média"
  )

df |> 
  filter(
    !is.na(entrega_atrasada),
    !is.na(categoria_nota)
  ) |> 
  group_by(entrega_atrasada) |> 
  summarise(
  prop_negativas = mean(categoria_nota == "Negativa"),
  total = n()
  ) |> 
  gt()
entrega_atrasada prop_negativas total
FALSE 0.09267355 89443
TRUE 0.62419683 6381
ggplot(df |> 
         filter(!is.na(entrega_atrasada), !is.na(categoria_nota)) |> 
         group_by(entrega_atrasada) |> 
         summarise(prop_negativas = mean(categoria_nota == "Negativa")),
       aes(x = entrega_atrasada, y = prop_negativas, fill = entrega_atrasada)) +
  geom_col() +
  scale_fill_manual(values = c("FALSE" = "red", "TRUE" = "green")) +
  labs(
    title = "Proporção de avaliações negativas por atraso",
    subtitle = "Base de dados: df",
    x = "Entrega atrasada?",
    y = "Proporção de avaliações negativas",
    fill = "Entrega atrasada?"
  ) +
  theme(legend.position = "none")

Observa-se que, quando não há atraso na entrega, a proporção de avaliações negativas é de aproximadamente 9%. No entanto, quando ocorre atraso, essa proporção sobe para cerca de 62%, indicando um aumento expressivo na probabilidade de insatisfação. Esse resultado sugere possível associação entre atrasos logísticos e avaliações negativas dos clientes.

  • Comparando tempo de entrega vs reviews: entregas mais demoradas, mesmo dentro do prazo, geram mais avaliações negativas?
df |>
  mutate(faixa_entrega = floor(tempo_entrega/5)*5) |>
  group_by(faixa_entrega) |>
  summarise(media_review = mean(review_score, na.rm = TRUE)) |>
  ggplot(aes(x = faixa_entrega, y = media_review)) +
  geom_line(linewidth = 1.2, color = "red") +
  theme_minimal() +
  labs(
    title = "Nota média da review por tempo de entrega",
    x = "Tempo de entrega (dias)",
    y = "Nota média"
  )

df |> 
  filter(!is.na(categoria_nota)) |>
  group_by(categoria_nota) |>
  summarise(
    media_tempo = mean(tempo_entrega, na.rm = TRUE),
    mediana_tempo = median(tempo_entrega, na.rm = TRUE)
  ) |> 
  gt()
categoria_nota media_tempo mediana_tempo
Negativa 19.61177 15
Neutra 13.65774 11
Positiva 10.51855 9
ggplot(df |> 
         group_by(categoria_nota) |>
         filter(!is.na(categoria_nota)) |>
         summarise(media_tempo = mean(tempo_entrega, na.rm = TRUE)),
       aes(x = categoria_nota, y = media_tempo, fill = categoria_nota)) +
  geom_col() +
  scale_fill_manual(values = c(
    "Negativa" = "red",
    "Neutra" = "yellow",
    "Positiva" = "green"
  )) +
  theme_minimal() +
  labs(
    title = "Tempo médio de entrega por categoria de avaliação",
    subtitle = "Base de dados: df",
    x = "Categoria da avaliação",
    y = "Tempo médio de entrega (dias)"
  ) +
  theme(legend.position = "none")

Observa-se um aumento consistente no tempo médio de entrega conforme a avaliação se torna mais negativa. Pedidos avaliados negativamente apresentaram tempo médio de 19,6 dias, enquanto pedidos com avaliação positiva apresentaram média de 10,5 dias. Esse padrão sugere que entregas mais demoradas estão associadas a maior insatisfação do cliente, mesmo quando não configuram necessariamente atraso formal.

5.2.1 Diagnóstico do impacto de fatores logísticos

A análise evidencia que pedidos entregues com atraso apresentam maior incidência de avaliações negativas, indicando que o desempenho logístico pode influenciar diretamente a satisfação do cliente. Mesmo entre as entregas que ocorrem dentro do prazo, quanto maior o tempo de entrega, maior a incidência de avaliações negativas.

5.3 Impacto de fatores financeiros

Esta parte da análise dedica-se a compreender se fatores financeiros influenciam a probabilidade de uma avaliação negativa dentre os pedidos entregues.


Variáveis financeiras consideradas para essa análise:

  • Preço do frete: variável numérica que corresponde ao valor pago pelo consumidor para o frete do pedido
dfSummary(df |> select(valor_frete))
Data Frame Summary  
df  
Dimensions: 96478 x 1  
Duplicates: 88609  

------------------------------------------------------------------------------------------------
No   Variable      Stats / Values            Freqs (% of Valid)     Graph   Valid      Missing  
---- ------------- ------------------------- ---------------------- ------- ---------- ---------
1    valor_frete   Mean (sd) : 22.8 (21.6)   7476 distinct values   :       96478      0        
     [numeric]     min < med < max:                                 :       (100.0%)   (0.0%)   
                   0 < 17.2 < 1795                                  :                           
                   IQR (CV) : 10.2 (0.9)                            :                           
                                                                    :                           
------------------------------------------------------------------------------------------------
  • Preço do(s) produto(s): variável numérica que corresponde ao valor pago pelo consumidor pelo(s) produto(s)
dfSummary(df |> select(valor_produtos))
Data Frame Summary  
df  
Dimensions: 96478 x 1  
Duplicates: 88844  

-------------------------------------------------------------------------------------------------
No   Variable         Stats / Values          Freqs (% of Valid)     Graph   Valid      Missing  
---- ---------------- ----------------------- ---------------------- ------- ---------- ---------
1    valor_produtos   Mean (sd) : 137 (209)   7435 distinct values   :       96478      0        
     [numeric]        min < med < max:                               :       (100.0%)   (0.0%)   
                      0.8 < 86.6 < 13440                             :                           
                      IQR (CV) : 104 (1.5)                           :                           
                                                                     :                           
-------------------------------------------------------------------------------------------------

Essas variáveis refletem custos diretos da compra e podem influenciar a percepção de valor da transação e, consequentemente, a avaliação atribuída pelos clientes.


Descrição estatística para contextualizar o comportamento geral destas variáveis:

df |>
  plot_normalidade(valor_frete, bins = 240, xlim = c(-10, 100))

df |>
  plot_normalidade(valor_produtos, bins = 250, xlim = c(-10, 1000))

OBS: A quantidade de bins escolhida para ambos os histogramas foi o valor encontrado que melhor permite a visualização da distribuição das observações.

O histograma e o QQ plot indicam que valor_produto não segue distribuição normal, apresentando assimetria à direita, com maior concentração de valores mais baixos e uma cauda longa à direita. A mediana de aproximadamente 86,6 reais indica que metade dos pedidos possui valor de produto até esse montante. O IQR de cerca de 104 reais mostra uma dispersão relativamente ampla entre os 50% centrais dos valores, sugerindo grande variabilidade no preço dos produtos vendidos.

Já a variável valor_frete também apresenta assimetria à direita, com concentração em valores menores e presença de alguns valores mais altos. A mediana foi de aproximadamente 17,2 reais, indicando que metade dos pedidos não ultrapassam este montante no valor do frete. O IQR de cerca de 10,2 reais descreve a variabilidade dos valores de frete mais comuns, mostrando que a maioria das entregas apresenta custos relativamente próximos desse intervalo central.

  • Comparando a proporção de reviews negativas vs valor do produto: pedidos mais caros recebem mais avaliações negativa?
df |>
  group_by(categoria_nota) |>
  filter(!is.na(categoria_nota)) |>
  summarise(
    media_valor_produtos = round(mean(valor_produtos, na.rm = TRUE), 2),
    mediana_valor_produtos = median(valor_produtos, na.rm = TRUE),
    n = n()
  ) |> 
  gt()
categoria_nota media_valor_produtos mediana_valor_produtos n
Negativa 159.89 98.00 12273
Neutra 127.48 82.99 7916
Positiva 134.03 84.94 75643

Observa-se que pedidos com avaliações negativas apresentam valor médio de produtos ligeiramente superior aos pedidos com avaliações neutras ou positivas. A média dos pedidos avaliados negativamente foi de aproximadamente 159,89 reais, enquanto pedidos com avaliações positivas apresentaram média de 134,03 reais.

Apesar dessa diferença, os valores medianos são relativamente próximos, indicando que o valor dos produtos pode apresentar alguma associação com avaliações negativas, mas não configura um fator fortemente determinante para a insatisfação dos clientes.

  • Comparando a proporção de reviews negativas vs valor do frete: fretes mais caros aumentam a chance de avaliação negativa?
df |>
  group_by(categoria_nota) |>
  filter(!is.na(categoria_nota)) |>
  summarise(
    media_valor_frete = round(mean(valor_frete, na.rm = TRUE), 2),
    mediana_valor_frete = median(valor_frete, na.rm = TRUE),
    n = n()
  ) |> 
  gt()
categoria_nota media_valor_frete mediana_valor_frete n
Negativa 27.71 18.49 12273
Neutra 23.56 17.63 7916
Positiva 21.88 16.87 75643

Padrão semelhante ao de valor do produto é observado para o valor do frete. Tanto a média quanto a mediana são levemente mais altas em avaliações negativas, porém as diferenças são pequenas, sugerindo que fatores financeiros não exercem influência relevante sobre o sentimento das reviews.

5.3.1 Diagnóstico do impacto de fatores financeiros

A análise evidencia que pedidos com reviews negativas apresentam, em média, valores de produto e de frete ligeiramente mais altos em comparação às demais avaliações. No entanto, como a diferença observada é pequena, não há evidências suficientes para afirmar que fatores financeiros impactam de forma relevante o sentimento das reviews.

6 Conclusão

A análise realizada sugere que fatores logísticos, como tempo de entrega e atrasos, podem estar associados à ocorrência de reviews negativas. Por outro lado, fatores financeiros, como valor do frete e valor total da compra, não apresentaram evidências claras de influência sobre as avaliações dos consumidores.

  • Análise de correlação para confirmar os resultados:
num_var = df |>
  select(where(is.numeric))
matriz_cor_pedidos = cor(num_var, use = "complete.obs")
corrplot(
  matriz_cor_pedidos,
  method = "color",
  type = "upper",
  addCoef.col = "gray",
  tl.col = "black",
  tl.srt = 45
)

Através da matriz de correlação acima, observa-se que os valores mais positivos são aqueles mais obviamente correlacionados, como o tempo de entrega e o tempo de atraso, o valor do frete e o valor total do pedido, o valor total dos produtos e o valor do frete, bem como a quantidade de produtos de um pedido e o valor do frete.

Os três pares de variáveis mais correlacionados são:

  1. tempo_entrega e atraso_dias (r = 0.60)

  2. valor_total e valor_frete (r = 0.49)

  3. total_produtos e valor_frete (r = 0.41)

Já os valores mais negativos correspondem à correlação entre o tempo de entrega e a nota da review, bem como entre o tempo de atraso e a nota da review. A matriz indica que fatores logísticos, como maior tempo de entrega e maiores atrasos, estão associados a notas de avaliação mais baixas. Trata-se de uma correlação fraca (magnitude entre 0,20 e 0,39), mas ainda superior à observada para fatores financeiros, como valor do frete e valor total dos produtos.

df |> 
  ggplot(aes(x = tempo_entrega, y = review_score)) +
  geom_jitter(alpha = 0.1, height = 0.1) +
  geom_smooth(method = "lm", color = "red") +
  theme_minimal() +
  labs(
    title = "Relação entre tempo de entrega e nota da review",
    subtitle = "Base de dados: df",
    x = "Tempo de entrega (dias)",
    y = "Nota da review"
  )

df |> 
  ggplot(aes(x = atraso_dias, y = review_score)) +
  geom_jitter(alpha = 0.1, height = 0.1) +
  geom_smooth(method = "lm", color = "red") +
  theme_minimal() +
  labs(
    title = "Relação entre tempo de atraso e nota da review",
    subtitle = "Base de dados: df",
    x = "Tempo de atraso (dias)",
    y = "Nota da review"
  )

Os scatterplots acima, entre tempo de entrega/tempo de atraso e nota da avaliação, mostram uma tendência negativa, evidenciada pela linha de regressão. Embora a dispersão dos pontos seja alta, observa-se que pedidos com maior tempo de entrega e tempo de atraso tendem a receber avaliações menores. A visualização apresenta faixas horizontais devido ao fato de a variável de nota ser discreta (valores de 1 a 5), o que limita a visualização direta da correlação.

Os resultados indicam que fatores logísticos, como tempo de entrega e atrasos, estão associados a avaliações mais baixas dos consumidores. Assim, melhorias na eficiência do frete podem contribuir para reduzir reviews negativas e melhorar a experiência do cliente no e-commerce.