Machine Learning: Regressão Logística
Última atualização: 2026-08-26
A regressão logística não é bem uma "regressão" — é um classificador poderoso que produz probabilidades, não números brutos.
1. O que você vai aprender
- Da linear à logística: a função sigmoide, saídas de probabilidade e fronteiras de decisão
- A função de perda: perda de entropia cruzada e a intuição por trás da estimativa de máxima verossimilhança
- Extensões multiclasse: One-vs-Rest e Softmax (Multinomial)
- Métricas de avaliação: Acurácia/Precisão/Revocação/F1/ROC-AUC e como escolher para o cenário do seu negócio
- Previsão de churn de usuários da Alice: identificando clientes de alto risco em um cenário SaaS
2. A história real de operações SaaS
(1) O problema: churn detectado tarde demais, caro de recuperar
A Alice administra uma plataforma SaaS com 50 mil usuários ativos e uma taxa de churn mensal de 8% — são 4 mil usuários perdidos a cada mês. Com cada usuário valendo cerca de 2 mil USD por ano, a perda mensal é de aproximadamente 670 mil USD. O problema: quando um usuário cancela a assinatura, já é tarde demais — a taxa de sucesso de recuperação é inferior a 5%.
(2) A solução com regressão logística
A regressão logística pode prever a probabilidade de churn assim que o comportamento do usuário mostra sinais de alerta, dando um aviso prévio de 2 a 4 semanas e elevando a taxa de sucesso de recuperação para 30%.
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
model = LogisticRegression(class_weight="balanced")
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred, target_names=["Retido", "Churn"]))
(3) O resultado: cada cliente salvo vale 2k USD
Usando regressão logística, a Alice identifica usuários com alto risco de churn com antecedência e salva 1,2 mil usuários por mês, acrescentando cerca de 2,4 milhões de USD em receita anual. Recuperar um cliente custa cerca de 50 USD — muito menos do que os 500 USD de adquirir um novo.
3. Da linear à logística
(1) A função sigmoide
A regressão logística usa a função sigmoide para comprimir a saída linear no intervalo [0,1] como uma probabilidade: $\sigma(z) = \frac{1}{1+e^{-z}}$
graph LR
INPUT[Features de entrada x] --> LINEAR[Combinação Linear<br/>z = w·x + b]
LINEAR --> SIGMOID[Função Sigmoide<br/>σ = 1/(1+e^(-z))]
SIGMOID --> PROB[P(y=1) = σ]
PROB --> DECISION{P ≥ 0,5?}
DECISION -->|Sim| CLASS1[Classe 1<br/>ex.: Churn]
DECISION -->|Não| CLASS0[Classe 0<br/>ex.: Retido]
▶ Exemplo: Visualizando a função sigmoide
import numpy as np
import matplotlib.pyplot as plt
z = np.linspace(-8, 8, 100)
sigmoid = 1 / (1 + np.exp(-z))
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(z, sigmoid, linewidth=2, color="#2196F3")
ax.axhline(0.5, color="red", linestyle="--", alpha=0.5, label="Fronteira de decisão")
ax.axvline(0, color="gray", linestyle="--", alpha=0.3)
ax.set_xlabel("z (combinação linear)")
ax.set_ylabel("σ(z) = P(y=1)")
ax.set_title("Função Sigmoide")
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("sigmoid.png", dpi=150)
Saída:
# Executado com sucesso
(2) Perda de entropia cruzada
A função de perda da regressão logística é a entropia cruzada (Log Loss):
$L = -\frac{1}{n}\sum[y\log(\hat{y}) + (1-y)\log(1-\hat{y})]$
| Rótulo verdadeiro | Probabilidade prevista | Perda | Intuição |
|---|---|---|---|
| y=1 | ŷ=0,99 | 0,01 | Quase nenhuma penalidade |
| y=1 | ŷ=0,5 | 0,69 | Penalidade moderada |
| y=1 | ŷ=0,01 | 4,60 | Penalidade enorme |
| y=0 | ŷ=0,01 | 0,01 | Quase nenhuma penalidade |
| y=0 | ŷ=0,99 | 4,60 | Penalidade enorme |
4. Regressão logística com Scikit-learn
▶ Exemplo: Classificação binária — Prevendo a intenção de compra do usuário
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
import numpy as np
rng = np.random.default_rng(42)
n = 1000
X = rng.standard_normal((n, 4)) # [tempo_navegacao, paginas_vistas, valor_carrinho, contagem_visitas]
y = (X[:, 0] * 0.5 + X[:, 1] * 1.2 + X[:, 2] * 2.0 + rng.normal(0, 0.5, n) > 1.5).astype(int)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
pipe = Pipeline([
("scaler", StandardScaler()),
("model", LogisticRegression(random_state=42)),
])
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
y_prob = pipe.predict_proba(X_test)[:, 1] # Probabilidade da classe 1
print(f"Acurácia: {accuracy_score(y_test, y_pred):.4f}")
print(f"\nMatriz de Confusão:\n{confusion_matrix(y_test, y_pred)}")
print(f"\nRelatório de Classificação:\n{classification_report(y_test, y_pred)}")
print(f"\nProbabilidades de amostra: {y_prob[:5].round(3)}")
Saída:
# Executado com sucesso
▶ Exemplo: Previsão de churn de usuários SaaS da Alice
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, precision_recall_fscore_support
import pandas as pd
import numpy as np
rng = np.random.default_rng(42)
n = 5000
df = pd.DataFrame({
"tenure_months": rng.integers(1, 60, n),
"monthly_usage_hours": rng.exponential(20, n),
"support_tickets": rng.poisson(2, n),
"payment_delay_days": rng.integers(0, 30, n),
"plan_tier": rng.choice([1, 2, 3], n, p=[0.5, 0.35, 0.15]),
})
# Lógica de churn: pouco tempo de casa + baixo uso + muitos tickets + atrasos
churn_score = (
-0.05 * df["tenure_months"]
- 0.1 * df["monthly_usage_hours"]
+ 0.5 * df["support_tickets"]
+ 0.1 * df["payment_delay_days"]
+ rng.normal(0, 1, n)
)
df["churned"] = (churn_score > 2).astype(int)
print(f"Taxa de churn: {df['churned'].mean():.1%}")
# Treinar com class_weight="balanced" para dados desbalanceados
X = df.drop(columns=["churned"])
y = df["churned"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
model = LogisticRegression(class_weight="balanced", max_iter=500, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]
auc = roc_auc_score(y_test, y_prob)
precision, recall, f1, _ = precision_recall_fscore_support(y_test, y_pred, average="binary")
print(f"AUC-ROC: {auc:.4f}")
print(f"Precisão: {precision:.4f}, Revocação: {recall:.4f}, F1: {f1:.4f}")
Saída:
# Executado com sucesso
5. Extensões multiclasse
(1) One-vs-Rest vs Softmax
▶ Exemplo: Multiclasse — Classificação automática de categoria de produto
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
X, y = load_iris(return_X_y=True)
# One-vs-Rest (padrão)
ovr_model = LogisticRegression(multi_class="ovr", max_iter=200)
ovr_scores = cross_val_score(ovr_model, X, y, cv=5, scoring="accuracy")
# Softmax (Multinomial)
softmax_model = LogisticRegression(multi_class="multinomial", max_iter=200)
softmax_scores = cross_val_score(softmax_model, X, y, cv=5, scoring="accuracy")
print(f"One-vs-Rest: {ovr_scores.mean():.4f} +/- {ovr_scores.std():.4f}")
print(f"Softmax: {softmax_scores.mean():.4f} +/- {softmax_scores.std():.4f}")
Saída:
# Executado com sucesso
| Dimensão | One-vs-Rest | Softmax (Multinomial) |
|---|---|---|
| Princípio | K classificadores binários | 1 classificador multiclasse |
| Calibração de probabilidades | Sem garantia de somar 1 | Soma estritamente 1 |
| Eficiência computacional | Paralelizável | Exige otimização conjunta |
| Melhor para | Muitas classes | Poucas classes, probabilidades necessárias |
6. Métricas de classificação e escolhas de negócio
(1) A matriz de confusão e métricas derivadas
▶ Exemplo: Curva ROC e Curva PR
from sklearn.metrics import roc_curve, auc, precision_recall_curve
import matplotlib.pyplot as plt
import numpy as np
# Assumir y_test e y_prob do exemplo anterior
rng = np.random.default_rng(42)
y_test = rng.choice([0, 1], 500, p=[0.85, 0.15])
y_prob = np.clip(y_test * 0.8 + rng.normal(0, 0.3, 500), 0, 1)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Curva ROC
fpr, tpr, _ = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)
axes[0].plot(fpr, tpr, color="#2196F3", lw=2, label=f"AUC = {roc_auc:.3f}")
axes[0].plot([0, 1], [0, 1], "r--", alpha=0.5)
axes[0].set_xlabel("Taxa de Falsos Positivos")
axes[0].set_ylabel("Taxa de Verdadeiros Positivos")
axes[0].set_title("Curva ROC")
axes[0].legend()
# Curva PR
precision_vals, recall_vals, _ = precision_recall_curve(y_test, y_prob)
axes[1].plot(recall_vals, precision_vals, color="#4CAF50", lw=2)
axes[1].set_xlabel("Revocação")
axes[1].set_ylabel("Precisão")
axes[1].set_title("Curva Precisão-Revocação")
plt.tight_layout()
plt.savefig("roc_pr_curves.png", dpi=150)
Saída:
# Executado com sucesso
(2) Escolhendo métricas para o cenário do seu negócio
| Cenário | Métrica prioritária | Razão | Estratégia de limiar |
|---|---|---|---|
| Previsão de churn de usuários | Revocação | Perder um cliente em churn é caro | Limiar mais baixo (0,3) |
| Filtragem de spam | Precisão | Rotular errado um e-mail legítimo é inaceitável | Aumentar o limiar (0,7) |
| Recomendação de produtos | F1 | Equilíbrio entre precisão e cobertura | Padrão (0,5) |
| Detecção de fraude | Revocação | Perder uma fraude é enormemente caro | Limiar mais baixo (0,2) |
❓ Perguntas Frequentes
P: Por que a regressão logística é chamada de "regressão"? R: Por razões históricas — ela modela com um método de regressão (uma combinação linear), mas a saída passa por uma sigmoide para se tornar uma probabilidade de classe. É fundamentalmente um algoritmo de classificação; o nome é enganoso.
P: O que significa class_weight=balanced? R: Pondera automaticamente cada classe pelo inverso de sua frequência, dando à classe minoritária um peso maior. Com uma taxa de churn de 8%, o peso da classe churn = 1/0,08 = 12,5, e o peso da classe retida = 1/0,92 = 1,09.
P: O limiar de decisão precisa ser 0,5? R: De modo algum. 0,5 é apenas o padrão, mas cenários de negócio geralmente exigem ajuste. Para previsão de churn, você pode baixá-lo para 0,3 (aumentando a Revocação); para spam, pode aumentá-lo para 0,7 (aumentando a Precisão). Deixe os custos de negócio guiarem o limiar.
P: Qual é melhor, ROC-AUC ou PR-AUC? R: Use ROC-AUC quando as classes são balanceadas, e PR-AUC quando elas são fortemente desbalanceadas. Para previsão de churn (8% vs 92%), PR-AUC é recomendado.
P: A regressão logística consegue lidar com relações não lineares? R: Não por padrão. Mas você pode adicionar features polinomiais (
PolynomialFeatures) para que ela aprenda uma fronteira de decisão não linear — essencialmente fazendo classificação linear em um espaço de dimensão mais alta.
P: Para que serve a regularização L1 na regressão logística? R: O mesmo que na regressão linear — L1 produz soluções esparsas e realiza seleção automática de features. Use
LogisticRegression(penalty="l1", solver="saga")para habilitar L1.
📖 Resumo
- A regressão logística usa a sigmoide para transformar a saída linear em probabilidades, com 0,5 como fronteira de decisão padrão
- A perda de entropia cruzada penaliza pesadamente previsões confiantes, mas erradas
- class_weight="balanced" lida com desbalanceamento de classes — essencial para previsão de churn
- Multiclasse: One-vs-Rest (vários classificadores binários) vs Softmax (probabilidades unificadas); este último calibra melhor as probabilidades
- Escolha de métricas de negócio: churn → Revocação, spam → Precisão, recomendação → F1
- Ajustar o limiar de decisão pode otimizar o valor de negócio — não fique preso ao padrão 0,5
📝 Exercícios
- Básico (Dificuldade ⭐): Use regressão logística para classificação multiclasse no conjunto de dados Iris e imprima a acurácia e o classification_report. Dica:
LogisticRegression(max_iter=200)+classification_report. - Intermediário (Dificuldade ⭐⭐): Simule um conjunto de dados desbalanceado (95:5) e compare a Revocação da regressão logística padrão vs class_weight="balanced". Dica: use
make_classification(weights=[0.95, 0.05]). - Desafio (Dificuldade ⭐⭐⭐): Implemente o pipeline completo de previsão de churn da Alice — gere dados simulados de usuários SaaS, treine um modelo de regressão logística, plote as curvas ROC/PR, calcule Revocação/Precisão/F1 em diferentes limiares e encontre o limiar ótimo para o negócio. Dica:
roc_curve+precision_recall_curve+ itere sobre os limiares.
← Anterior: Regressão Linear | Próximo: Árvores de Decisão e Florestas Aleatórias →