Projetos
Pandas · Logística · Desenvolvimento

Logística & Entrega — Como foi feito (explicado fácil)

Pensa numa pizza prometida em 30min. Chega em 25 → você dá 5 estrelas. Chega em 1h → uma estrela e um xingo. Aqui medi quanto a nota do cliente cai por dia de atraso em 96 mil pedidos reais de e-commerce. O resultado é brutal: cai de 4,3 → 1,7.

Nível Iniciante a intermediário Stack Python · Pandas Tipo Projeto analítico
Visão geral

O que é isso, em uma frase?

É uma análise sobre 96 mil pedidos do e-commerce Olist (Kaggle) que responde: "a nota do cliente cai quando a entrega atrasa? quanto?". A resposta, mensurada:

  • Entrega no prazo → nota média ~4,3
  • Atraso curto (1-7 dias) → nota média ~3,0
  • Atraso muito longo (30+ dias) → nota média ~1,7

Por que importa? Porque em e-commerce com reputação por avaliação, isso é equivalente a perder cliente. Saber o número dá poder de decisão: vale pagar transportadora mais cara pra reduzir atraso? quanto custa cada dia de atraso em reputação?

Passo a passo

Da data ao impacto

1 · Trazer as 2 datas-chave + a nota. Junto orders (que tem a data estimada e a data real de entrega) com reviews (que tem a nota de 1 a 5).

orders = pd.read_csv("olist_orders_dataset.csv",
                     usecols=["order_id", "order_status",
                              "order_estimated_delivery_date",
                              "order_delivered_customer_date"],
                     parse_dates=["order_estimated_delivery_date",
                                  "order_delivered_customer_date"])
reviews = pd.read_csv("olist_order_reviews_dataset.csv",
                      usecols=["order_id", "review_score"])
df = orders.merge(reviews, on="order_id", how="inner")

2 · Filtrar com cuidado. Só pedidos delivered e com as duas datas preenchidas. Pedidos cancelados ou em rota não fazem parte da análise — métrica suja, conclusão suja.

df = df[df["order_status"] == "delivered"].dropna(
    subset=["order_delivered_customer_date",
            "order_estimated_delivery_date"]
)

3 · Calcular o atraso (em dias). Simples: data real menos data prometida. Negativo = adiantada, zero = no prazo, positivo = atraso. O .dt.days arranca só os dias inteiros.

df["dias_atraso"] = (
    df["order_delivered_customer_date"]
    - df["order_estimated_delivery_date"]
).dt.days

4 · Quebrar em faixas legíveis. "Dias contínuos" são bons pra cálculo, ruins pra leitura. Quebro em 5 faixas que falam a língua do negócio.

def faixa(d):
    if d < -3:  return "adiantada (3+ dias)"
    if d <= 0:  return "no prazo (-3 a 0)"
    if d <= 7:  return "atraso curto (1-7 dias)"
    if d <= 30: return "atraso longo (8-30 dias)"
    return            "atraso muito longo (30+ dias)"

df["faixa"] = df["dias_atraso"].apply(faixa)

5 · Nota média por faixa. O cerne da análise — 3 linhas resolvem.

res = (df.groupby("faixa")["review_score"]
         .agg(["mean", "count"])
         .round(2))
print(res)
faixanota média
Adiantada (3+ dias)4,3
No prazo4,3
Atraso curto (1-7d)~3,0
Atraso longo (8-30d)~2,1
Atraso muito longo (30+d)1,7

6 · Conclusão acionável. Atraso aceitável (até 7 dias) já tira mais de 1 estrela da média. Atraso longo cria detratores. Decisões que saem disso: revisar transportadora pra rotas críticas, comunicar proativamente quando o sistema previr atraso, considerar política de reembolso parcial pra recuperar nota.

Resultado

Nota média × faixa de atraso

O que dá pra levar daqui

Em uma linha: o que esse projeto ensina

Que operação afeta marca. Logística não é problema só de logística — é problema de CX, marketing, retenção. Medir esse custo em número (não em "intuição de que afeta") é a base pra justificar investimento em transportadora melhor.

Coisas técnicas que apareceram aqui: Pandas (merge, dropna com subset, aritmética de datetime, .dt.days), classificação em faixas com apply, agregação por categoria com groupby, leitura crítica de filtros (status, datas válidas).