R: R Regressão Logística
Última atualização: 2026-08-26
Na aula anterior, aprendemos sobre regressão linear — a previsão de valores contínuos (vendas, temperatura). Mas 80% dos problemas do mundo real envolvem perguntas do tipo “se”: um usuário fará uma compra? Um e-mail será clicado? Um empréstimo entrará em inadimplência? Nesta aula, aprenderemos sobre regressão logística — a previsão de probabilidades e categorias.
Ao concluir esta aula, você será capaz de usar o R para realizar: previsão de rotatividade de clientes, previsão da taxa de cliques em e-mails, pontuação de crédito e modelagem de testes A/B — abrangendo 60% dos problemas de classificação na ciência de dados.
1. O que você vai aprender
- Princípios da regressão logística (transformação logit + sigmoide)
- função glm() da família de distribuições binomiais
- Interpretação dos coeficientes (razão de chances)
- predict type="response" probabilidade prevista
- Avaliação da curva ROC + AUC
- Divisão do conjunto de treinamento e do conjunto de teste do Caret
- Seleção do limiar (padrão: 0,5)
- Aplicação prática: previsão de rotatividade de clientes
2. Uma história sobre a previsão de rotatividade de clientes
(1) Desafio: Quais clientes têm maior probabilidade de cancelar a assinatura?
Xiao Zhao é analista de dados em uma empresa de SaaS. Seu gerente perguntou: “Quais clientes têm maior probabilidade de cancelar a assinatura no mês que vem? Como podemos mantê-los antes que isso aconteça?”
Dados: 1.000 clientes; variáveis = idade, tempo de uso, número de interações com o atendimento ao cliente; classe = se o cliente cancelou o contrato.
(2) Solução usando R
# 1. Model Building in One Line
model <- glm(churn ~ age + usage + support_calls,
data = df, family = binomial)
# 2. Probability per row
df$prob <- predict(model, type = "response")
# 3. One-Line Evaluation
library(pROC)
roc_obj <- roc(df$churn, df$prob)
auc(roc_obj) # [1] 0.85 ← Model Quality
3 linhas de código → Previsão de rotatividade + qualidade do modelo.
3. Princípios da regressão logística
(1) Por que a regressão logística é necessária?
graph TB
A[Y Category 0/1] --> B[Linear regression is not applicable]
B --> C[We need to map continuous values to 0-1]
C --> D[Logit Transformation + Sigmoid]
D --> E[Logistic Regression]
style A fill:#fff3cd
style B fill:#f8d7da
style C fill:#d4edda
style D fill:#cce5ff
style E fill:#e1d4ff
A regressão linear prevê valores contínuos, enquanto a regressão logística prevê probabilidades (0–1).
(2) Fórmulas matemáticas
P(Y=1) = 1 / (1 + e^(-z))
│ │ │
│ │ └─ z = β₀ + β₁X₁ + β₂X₂ + ...
│ └─ e Index
└─ Sigmoid Function (Range 0-1)
Notação equivalente (transformação logit):
log(P/(1-P)) = β₀ + β₁X₁ + β₂X₂ + ...
probabilidade = P / (1-P) = probabilidade de sucesso / probabilidade de fracasso.
(3) Função sigmoide
sigmoid <- function(x) 1 / (1 + exp(-x))
# Examples
sigmoid(0) # 0.5
sigmoid(2) # 0.881
sigmoid(-2) # 0.119
sigmoid(10) # 0.99995
4. Uso básico da função glm()
(1) Sintaxe
glm(formula, data, family = binomial)
| Parâmetro | Significado |
|---|---|
formula |
y ~ x1 + x2 (igual a lm) |
data |
Quadro de dados |
family |
binomial (classificação binária) / gaussian (linear) / poisson (contagem) |
(2) A primeira regressão logística
# Data
df <- data.frame(
churn = c(0, 0, 0, 1, 1, 1, 0, 1, 0, 1),
age = c(25, 30, 35, 50, 55, 60, 28, 58, 32, 65),
usage = c(80, 70, 60, 30, 20, 10, 75, 15, 65, 5)
)
# Modeling
model <- glm(churn ~ age + usage, data = df, family = binomial)
summary(model)
Resultado:
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 8.452 4.123 2.050 0.0403 *
age 0.087 0.043 2.023 0.0431 *
usage -0.156 0.058 -2.690 0.0072 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(3) Análise dos 6 principais resultados
| Campo | Significado | Explicação |
|---|---|---|
| Estimativa | Coeficiente (no espaço logit) | Um coeficiente positivo → Um aumento nessa variável aumenta a probabilidade de cancelamento |
| Erro-padrão | Erro-padrão | Precisão da estimativa do coeficiente |
| valor z | estatística z | Estimativa / Erro-padrão |
| Pr(>|z|) | valor p | Probabilidade de que o coeficiente seja significativamente diferente de 0 |
| Desvio nulo | Desvio do modelo zero | Modelo apenas com interceptação |
| Desvio residual | Desvio residual | Quanto menor o valor, melhor o ajuste |
z value substitui o valor t (aproximação normal para amostras grandes); p < 0,05 indica que o coeficiente é significativo.
5. Interpretação dos coeficientes: razão de chances
(1) Por que usar a razão de chances?
Os coeficientes da regressão logística estão no espaço logit, o que não é intuitivo. Converta-os em razões de chances (OR) para facilitar a interpretação:
# odds ratio = exp(Coefficient)
exp(coef(model))
# (Intercept) age usage
# 4670.123 1.091 0.856
(2) Interpretação “OU”
| Valor OR | Significado |
|---|---|
| OR = 1 | A variável não tem efeito |
| OR > 1 | Um aumento na variável aumenta as chances (é mais provável que o evento ocorra) |
| OU < 1 | Um aumento na variável reduz as chances (é menos provável que o evento ocorra) |
# age's OR = 1.09
# Analysis: For each 1 year increase in age, churn odds increase by 9%
# usage's OR = 0.86
# Analysis: For each 1 unit increase in usage, churn odds decrease by 14%
(3) Intervalo de confiança de 95%
exp(confint(model))
# 2.5 % 97.5 %
# (Intercept) 12.345 12345.678
# age 1.002 1.198
# usage 0.745 0.978
O CI não inclui 1 → O coeficiente é significativo.
6. Previsões
(1) O parâmetro type
# type = "response" <- Probability (0-1) * Most Commonly Used
predict(model, type = "response")
# type = "link" <- logit space (Default)
predict(model, type = "link")
(2) Previsões no mundo real
# Training Set Predictions
df$prob <- predict(model, type = "response")
# Threshold 0.5 to convert to category
df$pred <- ifelse(df$prob > 0.5, 1, 0)
# New Data Forecasts
new_customers <- data.frame(
age = c(40, 55, 30),
usage = c(50, 15, 80)
)
predict(model, new_customers, type = "response")
# [1] 0.123 0.876 0.045
# Analysis: Age 55, Usage 15, probability of customer churn 87.6%
(3) Seleção do limiar
| Limite | Cenários aplicáveis |
|---|---|
| 0,5 | Padrão, equilibrando precisão e recall |
| 0,3 | Reduzir falsos negativos (diagnósticos médicos, fraudes) |
| 0,7 | Reduzir falsos positivos (spam) |
# Custom Thresholds
df$pred <- ifelse(df$prob > 0.3, 1, 0)
7. Avaliação do modelo: ROC + AUC
(1) Matriz de confusão
library(caret)
# True vs Forecast
confusionMatrix(
factor(df$pred),
factor(df$churn),
positive = "1"
)
# Reference
# Prediction 0 1
# 0 50 5
# 1 10 35
# Accuracy: 0.85
# Sensitivity (Recall): 0.875
# Specificity: 0.833
(2) 4 indicadores-chave
| Unidade métrica | Fórmula | Significado |
|---|---|---|
| Precisão | (TP + TN) / Total | Precisão geral |
| Precisão | TP / (TP+FP) | A proporção de casos previstos como positivos que são, de fato, positivos |
| Recall (Sensibilidade) | TP / (TP+FN) | Proporção de resultados positivos reais corretamente previstos |
| F1 | 2×P×R/(P+R) | Média harmônica de P e R |
(3) Curva ROC + AUC
library(pROC)
# Calculate ROC
roc_obj <- roc(df$churn, df$prob)
auc(roc_obj)
# [1] 0.92 ← The closer we get to 1 The better
# Draw ROC
plot(roc_obj, main = "ROC Curve", col = "blue", lwd = 2)
abline(a = 0, b = 1, lty = 2, col = "gray") # Random Classification Baseline
# AUC Analysis
# 0.5-0.7: Poor
# 0.7-0.8: Fair
# 0.8-0.9: Good
# 0.9-1.0: Excellent
8. Divisão entre conjuntos de treinamento e teste
library(caret)
# Division 70% Training / 30% Test
set.seed(42)
train_index <- createDataPartition(df$churn, p = 0.7, list = FALSE)
train_data <- df[train_index, ]
test_data <- df[-train_index, ]
# Train a Model
model <- glm(churn ~ age + usage, data = train_data, family = binomial)
# Test Set Predictions
test_data$prob <- predict(model, test_data, type = "response")
test_data$pred <- ifelse(test_data$prob > 0.5, 1, 0)
# Evaluation
confusionMatrix(factor(test_data$pred), factor(test_data$churn), positive = "1")
# True AUC
roc_obj <- roc(test_data$churn, test_data$prob)
auc(roc_obj)
9. Multiclasse (multinômio)
# For multi-class classification multinom (requires nnet package)
install.packages("nnet")
library(nnet)
# 3 Categories
df <- data.frame(
y = c("A", "A", "B", "B", "C", "C"),
x = c(1, 2, 3, 4, 5, 6)
)
model <- multinom(y ~ x, data = df)
summary(model)
# Forecast
predict(model, type = "class") # Category
predict(model, type = "probs") # Probability
10. Prática: O processo completo de previsão de rotatividade de clientes
A seguir, apresentamos um exemplo de um fluxo de trabalho completo que reúne todos os conceitos de regressão logística abordados nesta aula.
▶ Exemplo: Previsão da perda de 1.000 clientes
# ============================================
# 1000 Customer Churn Prediction
# Features: The Complete Logistic Regression Workflow
# ============================================
library(ggplot2)
library(dplyr)
library(caret)
library(pROC)
# 1. Prepare data
set.seed(42)
n <- 1000
df <- tibble(
age = round(rnorm(n, 40, 12)),
usage = round(rnorm(n, 50, 20)),
support_calls = sample(0:10, n, replace = TRUE),
plan = sample(c("Basics", "Advanced", "Company"), n, replace = TRUE,
prob = c(0.5, 0.3, 0.2))
) |>
mutate(
# Probability of attrition: Older, Use less, Many customer service calls -> Prone to churn
logit_p = -3 + 0.03 * age - 0.05 * usage + 0.3 * support_calls,
p = 1 / (1 + exp(-logit_p)),
churn = rbinom(n, 1, p)
) |>
select(-logit_p, -p)
cat("=== Data Preview ===\n")
print(head(df, 3))
cat("\nChurn rate:", round(mean(df$churn) * 100, 2), "%\n")
# 2. Training/Test Set Partitioning
set.seed(42)
train_index <- createDataPartition(df$churn, p = 0.7, list = FALSE)
train_data <- df[train_index, ]
test_data <- df[-train_index, ]
cat("\nTraining Set:", nrow(train_data), "rows\n")
cat("Test Set:", nrow(test_data), "rows\n\n")
# 3. Train a Model
model <- glm(churn ~ age + usage + support_calls + plan,
data = train_data, family = binomial)
cat("=== Model Summary ===\n")
summary(model)
# 4. Explanation of Coefficients
cat("\n=== Coefficient odds ratio ===\n")
or_df <- tidy(model, conf.int = TRUE, exponentiate = TRUE)
print(or_df |> select(term, estimate, std.error, p.value, conf.low, conf.high))
# 5. Training Set Predictions
train_data$prob <- predict(model, type = "response")
train_data$pred <- ifelse(train_data$prob > 0.5, 1, 0)
# 6. Test Set Predictions
test_data$prob <- predict(model, test_data, type = "response")
test_data$pred <- ifelse(test_data$prob > 0.5, 1, 0)
# 7. Training Set Evaluation
cat("\n=== Training Set Evaluation ===\n")
train_cm <- confusionMatrix(factor(train_data$pred), factor(train_data$churn),
positive = "1")
print(train_cm)
# 8. Test Set Evaluation
cat("\n=== Test Set Evaluation ===\n")
test_cm <- confusionMatrix(factor(test_data$pred), factor(test_data$churn),
positive = "1")
print(test_cm)
# 9. ROC + AUC
cat("\n=== AUC ===\n")
roc_train <- roc(train_data$churn, train_data$prob)
roc_test <- roc(test_data$churn, test_data$prob)
cat("Training Set AUC:", round(auc(roc_train), 3), "\n")
cat("Test Set AUC:", round(auc(roc_test), 3), "\n")
# 10. Draw ROC
plot(roc_test, main = "ROC Curve", col = "blue", lwd = 2)
abline(a = 0, b = 1, lty = 2, col = "gray")
legend("bottomright",
legend = paste0("AUC = ", round(auc(roc_test), 3)),
col = "blue", lwd = 2)
# 11. Threshold Analysis
cat("\n=== Threshold Analysis ===\n")
thresholds <- seq(0.1, 0.9, by = 0.1)
threshold_results <- lapply(thresholds, function(t) {
pred <- ifelse(test_data$prob > t, 1, 0)
cm <- confusionMatrix(factor(pred), factor(test_data$churn), positive = "1")
data.frame(
threshold = t,
precision = cm$byClass["Precision"],
recall = cm$byClass["Sensitivity"],
f1 = cm$byClass["F1"]
)
}) |> bind_rows()
print(threshold_results)
# 12. Identify high-risk customers
cat("\n=== High-Risk Clients Top 5 (Probability of attrition > 70%) ===\n")
high_risk <- test_data |>
filter(prob > 0.7) |>
arrange(desc(prob)) |>
head(5) |>
select(age, usage, support_calls, plan, prob, pred)
print(high_risk)
# 13. Probability Distribution Chart
ggplot(test_data, aes(x = prob, fill = factor(churn))) +
geom_histogram(bins = 30, alpha = 0.7, position = "identity") +
labs(title = "Probability Distribution of Attrition (Sorted by True label)",
x = "Predict the Probability of Churn", y = "Frequency", fill = "True label") +
scale_fill_brewer(palette = "Set1", labels = c("Not churned", "Churned")) +
theme_minimal()
# 14. Save Model
saveRDS(model, "churn_model.rds")
cat("\n=== The model has been saved: churn_model.rds ===\n")
Resultado esperado (trecho):
=== Training Set Evaluation ===
Confusion Matrix:
Reference
Prediction 0 1
0 525 42
1 18 115
Accuracy: 0.91
Sensitivity: 0.733
Specificity: 0.967
=== Test Set Evaluation ===
Accuracy: 0.89
AUC = 0.92
❓ Perguntas Frequentes
P: Regressão logística x regressão linear? R: Se Y for contínua, use
lm(); se Y for 0/1, useglm(family = binomial). A regressão logística gera probabilidades (0–1), e não valores diretos de 0/1.
P: Como você interpreta a razão de chances? R: RC = exp(coeficiente). Uma RC > 1 indica um aumento nas chances (maior probabilidade de desistência), enquanto uma RC < 1 indica uma diminuição nas chances (menor probabilidade). Uma RC de 1,5 significa que as chances aumentaram em 50%.
P: Como escolho um limiar? R: O valor padrão é 0,5, mas ele deve ser ajustado de acordo com as necessidades da empresa. Use um limiar baixo (0,2–0,3) quando o custo dos falsos negativos for alto (por exemplo, na área da saúde) e um limiar alto (0,7–0,8) quando o custo dos falsos positivos for alto (por exemplo, no caso de spam).
P: O que é um bom valor de AUC? R: 0,5 = aleatório; 0,7–0,8 = médio; 0,8–0,9 = bom; 0,9+ = excelente. Quanto maior for a AUC, melhor será o modelo em distinguir entre amostras positivas e negativas.
P: Qual é a divisão recomendada entre os conjuntos de treinamento e de teste? R: As divisões mais comuns são 70/30 ou 80/20. Para conjuntos de dados grandes, uma divisão de 90/10 também é aceitável; para conjuntos de dados pequenos, use validação cruzada (caret’s
trainControl).
P: O que devo usar para classificação multiclasse? R: Use
nnet::multinom()(regressão logística multiclasse) oucaret(seleção automática de modelos). Para três ou mais classes, considere o Random Forest.
📖 Resumo
- Regressão logística: Y é uma classificação binária 0/1, e a saída é uma probabilidade (não 0 nem 1)
- Matemática:
log(P/(1-P)) = β₀ + β₁X + ..., equivalente aP = sigmoid(z) glm(y ~ x, family = binomial)A sintaxe da fórmula é a mesma delm- Interpretação dos coeficientes: OR = exp(β); um OR > 1 indica um aumento na probabilidade do evento, enquanto um OR < 1 indica uma diminuição nessa probabilidade.
predict(model, type = "response")Probabilidade prevista;type = "link"Logit previsto- Avaliação por ROC + AUC: AUC 0,5–1,0 (0,5 = aleatório, 1,0 = perfeito)
- Limite: Padrão 0,5, ajuste conforme necessário (equilibrando falsos negativos e falsos positivos)
- Divida os conjuntos de treinamento e teste na proporção de 70/30 usando caret::createDataPartition
- Várias categorias:
nnet::multinom(y ~ x)
📝 Exercícios
-
Exercício básico: Crie um data frame (200 linhas, 4 colunas: churn + idade + uso + chamadas_de_suporte), construa um modelo usando
glm, interprete todos os resultados usandosummarye calcule a razão de chances usandoexp(coef(model)). -
Exercício básico: Usando o modelo da questão anterior, faça a previsão do conjunto de treinamento utilizando
predict(type = "response"), trace um histograma comparando os rótulos reais com as probabilidades previstas e verifique se a regressão logística gera probabilidades (0–1). -
Exercício básico: Utilizando o modelo da questão anterior, trace a curva ROC usando
pROC::roc()e calcule a AUC. Verifique se uma AUC entre 0,7 e 0,9 indica um bom modelo. -
Problema avançado: Use o conjunto de dados
mtcarspara construir um problema de classificação binária (vsrepresenta o tipo de motor 0/1), crie um modelo usandoglm(vs ~ mpg + wt, family = binomial), divida os dados em uma proporção de 70/30 e calcule a AUC e a matriz de confusão para o conjunto de teste. -
Desafio: Previsão completa da rotatividade de clientes — Simule 1.000 clientes (4 características + 1 rótulo). Fluxo de trabalho completo: ① Exploração ② Particionamento ③ Modelagem ④ Avaliação (Matriz de Confusão + ROC + AUC) ⑤ Análise de limiar ⑥ Identificação de clientes de alto risco ⑦ Gráfico de distribuição de probabilidade ⑧ Salvar modelo. Salve capturas de tela do processo.