Análise exploratória de dados (EDA) é a etapa em que você conhece o dataset antes de modelar ou reportar. Estatísticas descritivas, distribuições, correlações, outliers e padrões temporais — sem essa fase, qualquer análise subsequente parte de premissas não verificadas. Este artigo cobre um fluxo de EDA completo e reutilizável.
Carregando e inspecionando o dataset
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv("vendas_2026.csv", sep=";", decimal=",",
parse_dates=["data_pedido"], dayfirst=True)
# Visão geral:
print(df.shape) # (linhas, colunas)
print(df.dtypes) # tipos de cada coluna
print(df.head()) # primeiras 5 linhas
print(df.tail()) # últimas 5 linhas
print(df.sample(5)) # 5 linhas aleatórias — melhor que head() para amostras reais
Qualidade dos dados
# Nulos por coluna (quantidade e percentual):
nulos = pd.DataFrame({
"qtd": df.isnull().sum(),
"pct": (df.isnull().mean() * 100).round(2)
}).query("qtd > 0").sort_values("pct", ascending=False)
print(nulos)
# Duplicatas:
print(f"Linhas duplicadas: {df.duplicated().sum()}")
# Cardinalidade de colunas categóricas:
for col in df.select_dtypes("object").columns:
print(f"{col}: {df[col].nunique()} valores únicos")
print(df[col].value_counts().head(5))
print()
Estatísticas descritivas
# Resumo numérico completo:
desc = df.describe().T
desc["cv"] = desc["std"] / desc["mean"] # coeficiente de variação
print(desc)
# Percentis customizados:
print(df["valor"].quantile([0.01, 0.25, 0.5, 0.75, 0.90, 0.99]))
Análise de distribuição
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Histograma com KDE:
sns.histplot(df["valor"], kde=True, ax=axes[0], color="#4a148c")
axes[0].set_title("Distribuição do Valor do Pedido")
# Boxplot para detectar outliers:
sns.boxplot(y=df["valor"], ax=axes[1], color="#b39ddb")
axes[1].set_title("Outliers no Valor do Pedido")
plt.tight_layout()
plt.show()
Análise de correlação
numericas = df.select_dtypes(include="number")
correlacao = numericas.corr()
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(correlacao, annot=True, fmt=".2f",
cmap="RdYlGn", center=0, ax=ax)
ax.set_title("Correlação entre Variáveis Numéricas")
plt.tight_layout()
plt.show()
Séries temporais: tendência e sazonalidade
# Vendas mensais:
mensal = df.set_index("data_pedido")["valor"].resample("ME").sum()
mensal.plot(figsize=(12, 4), title="Receita Mensal", color="#4a148c")
plt.tight_layout()
plt.show()
# Crescimento mês a mês (%):
mensal_pct = mensal.pct_change() * 100
print(mensal_pct.round(1))
Análise por categoria
por_regiao = df.groupby("regiao")["valor"].agg(
total="sum",
media="mean",
contagem="count"
).sort_values("total", ascending=False)
print(por_regiao)
# Boxplot por categoria:
fig, ax = plt.subplots(figsize=(10, 5))
df.boxplot(column="valor", by="regiao", ax=ax)
ax.set_title("Distribuição do Valor por Região")
plt.suptitle("") # remove título automático do boxplot
plt.tight_layout()
plt.show()
Detecção de outliers com IQR
Q1 = df["valor"].quantile(0.25)
Q3 = df["valor"].quantile(0.75)
IQR = Q3 - Q1
limite_inf = Q1 - 1.5 * IQR
limite_sup = Q3 + 1.5 * IQR
outliers = df[(df["valor"] < limite_inf) | (df["valor"] > limite_sup)]
print(f"Outliers detectados: {len(outliers)} ({len(outliers)/len(df)*100:.1f}%)")
Perguntas frequentes
Devo remover outliers sempre?
Não automaticamente. Investigue primeiro: o outlier é um erro de digitação, um evento legítimo incomum, ou uma fraude? A decisão depende do contexto de negócio, não de uma regra estatística automática.
Qual biblioteca usar para EDA automatizada?
ydata-profiling (antigo pandas-profiling) gera um relatório HTML completo com uma linha: ProfileReport(df).to_file("eda.html"). Útil para uma visão rápida inicial, mas não substitui a análise guiada pelo entendimento do negócio.