A Regressão Logística é um modelo de Machine Learning usado quando a variável resposta é binária — ou seja, tem apenas dois resultados possíveis, como sim/não, 0/1, sobreviveu/não sobreviveu.
Diferente da regressão linear, que prevê valores contínuos, a regressão logística prevê a probabilidade de um evento ocorrer, sempre entre 0 e 1.
A fórmula central do modelo é a função sigmoide:
\[P(Y=1) = \frac{1}{1 + e^{-(\beta_0 + \beta_1 X_1 + \cdots + \beta_n X_n)}}\]
Quando usar? - Diagnóstico médico (doente ou saudável) - Detecção de spam (spam ou não spam) - Previsão de sobrevivência (como faremos aqui)
Usaremos o famoso dataset Titanic, que contém informações sobre os passageiros do naufrágio de 1912. Nosso objetivo é prever quem sobreviveu com base em características como sexo, idade e classe.
if (!require(tidyverse)) install.packages("tidyverse")
if (!require(caret)) install.packages("caret")
if (!require(pROC)) install.packages("pROC")
if (!require(titanic)) install.packages("titanic")
library(tidyverse)
library(caret)
library(pROC)
library(titanic)## Dimensões: 891 12
## Variáveis: PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
## Rows: 891
## Columns: 12
## $ PassengerId <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,…
## $ Survived <int> 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1…
## $ Pclass <int> 3, 1, 3, 1, 3, 3, 1, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3, 2, 3, 3…
## $ Name <chr> "Braund, Mr. Owen Harris", "Cumings, Mrs. John Bradley (Fl…
## $ Sex <chr> "male", "female", "female", "female", "male", "male", "mal…
## $ Age <dbl> 22, 38, 26, 35, 35, NA, 54, 2, 27, 14, 4, 58, 20, 39, 14, …
## $ SibSp <int> 1, 1, 0, 1, 0, 0, 0, 3, 0, 1, 1, 0, 0, 1, 0, 0, 4, 0, 1, 0…
## $ Parch <int> 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 5, 0, 0, 1, 0, 0, 0…
## $ Ticket <chr> "A/5 21171", "PC 17599", "STON/O2. 3101282", "113803", "37…
## $ Fare <dbl> 7.2500, 71.2833, 7.9250, 53.1000, 8.0500, 8.4583, 51.8625,…
## $ Cabin <chr> "", "C85", "", "C123", "", "", "E46", "", "", "", "G6", "C…
## $ Embarked <chr> "S", "C", "S", "S", "S", "Q", "S", "S", "S", "C", "S", "S"…
Selecionamos as variáveis mais relevantes e removemos valores ausentes.
dados_limpo <- dados %>%
select(Survived, Pclass, Sex, Age, SibSp, Parch, Fare) %>%
mutate(
Survived = factor(Survived, levels = c(0, 1),
labels = c("Nao", "Sim")),
Sex = factor(Sex),
Pclass = factor(Pclass)
) %>%
drop_na()
cat("Linhas após limpeza:", nrow(dados_limpo), "\n")## Linhas após limpeza: 714
##
## Distribuição da variável alvo:
##
## Nao Sim
## 0.5938375 0.4061625
set.seed(42)
indice_treino <- createDataPartition(dados_limpo$Survived,
p = 0.8, list = FALSE)
treino <- dados_limpo[ indice_treino, ]
teste <- dados_limpo[-indice_treino, ]
cat("Treino:", nrow(treino), "linhas\n")## Treino: 572 linhas
## Teste: 142 linhas
##
## Call:
## glm(formula = Survived ~ ., family = binomial(link = "logit"),
## data = treino)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 4.0113173 0.5511054 7.279 3.37e-13 ***
## Pclass2 -1.2290410 0.3550867 -3.461 0.000538 ***
## Pclass3 -2.4036981 0.3740668 -6.426 1.31e-10 ***
## Sexmale -2.4713014 0.2412303 -10.245 < 2e-16 ***
## Age -0.0431636 0.0089913 -4.801 1.58e-06 ***
## SibSp -0.3360601 0.1429036 -2.352 0.018690 *
## Parch -0.0794852 0.1327182 -0.599 0.549238
## Fare 0.0009956 0.0029938 0.333 0.739479
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 772.45 on 571 degrees of freedom
## Residual deviance: 532.71 on 564 degrees of freedom
## AIC: 548.71
##
## Number of Fisher Scoring iterations: 4
O Odds Ratio indica o quanto cada variável aumenta ou reduz a chance de sobrevivência.
## OR 2.5 % 97.5 %
## (Intercept) 55.220 19.213 167.612
## Pclass2 0.293 0.145 0.584
## Pclass3 0.090 0.043 0.187
## Sexmale 0.084 0.052 0.134
## Age 0.958 0.941 0.974
## SibSp 0.715 0.535 0.938
## Parch 0.924 0.705 1.192
## Fare 1.001 0.995 1.007
Como interpretar: - OR > 1 → aumenta a chance de sobreviver - OR < 1 → reduz a chance de sobreviver - OR = 1 → sem efeito
prob_pred <- predict(modelo, newdata = teste, type = "response")
classe_pred <- factor(ifelse(prob_pred >= 0.5, "Sim", "Nao"),
levels = c("Nao", "Sim"))
mat_conf <- confusionMatrix(classe_pred, teste$Survived,
positive = "Sim")
print(mat_conf)## Confusion Matrix and Statistics
##
## Reference
## Prediction Nao Sim
## Nao 76 11
## Sim 8 47
##
## Accuracy : 0.8662
## 95% CI : (0.799, 0.9175)
## No Information Rate : 0.5915
## P-Value [Acc > NIR] : 8.601e-13
##
## Kappa : 0.7209
##
## Mcnemar's Test P-Value : 0.6464
##
## Sensitivity : 0.8103
## Specificity : 0.9048
## Pos Pred Value : 0.8545
## Neg Pred Value : 0.8736
## Prevalence : 0.4085
## Detection Rate : 0.3310
## Detection Prevalence : 0.3873
## Balanced Accuracy : 0.8576
##
## 'Positive' Class : Sim
##
roc_obj <- roc(teste$Survived, prob_pred, levels = c("Nao", "Sim"))
auc_val <- auc(roc_obj)
plot(roc_obj,
main = paste("Curva ROC - AUC =", round(auc_val, 3)),
col = "steelblue",
lwd = 2,
print.auc = TRUE)
abline(a = 0, b = 1, lty = 2, col = "gray50")Descrição do gráfico: A curva ROC mostra a relação entre sensibilidade e especificidade do modelo. A curva azul está bem acima da diagonal cinza tracejada (que representa um modelo aleatório), indicando boa capacidade preditiva. O AUC (Área sob a Curva) próximo de 1 indica excelente desempenho.
dados_limpo %>%
group_by(Sex, Survived) %>%
summarise(n = n(), .groups = "drop") %>%
ggplot(aes(x = Sex, y = n, fill = Survived)) +
geom_col(position = "fill") +
scale_y_continuous(labels = scales::percent) +
scale_fill_manual(values = c("Nao" = "#e74c3c", "Sim" = "#2ecc71")) +
labs(title = "Taxa de Sobrevivência por Sexo",
x = "Sexo", y = "Proporção", fill = "Sobreviveu?") +
theme_minimal()Descrição: Mulheres tiveram uma taxa de sobrevivência muito maior que os homens — cerca de 74% das mulheres sobreviveram, contra apenas 19% dos homens. Isso reflete a política histórica de “mulheres e crianças primeiro” adotada durante o naufrágio.
dados_limpo %>%
group_by(Pclass, Survived) %>%
summarise(n = n(), .groups = "drop") %>%
ggplot(aes(x = Pclass, y = n, fill = Survived)) +
geom_col(position = "fill") +
scale_y_continuous(labels = scales::percent) +
scale_fill_manual(values = c("Nao" = "#e74c3c", "Sim" = "#2ecc71")) +
labs(title = "Taxa de Sobrevivência por Classe",
x = "Classe", y = "Proporção", fill = "Sobreviveu?") +
theme_minimal()Descrição: Passageiros da 1ª classe tiveram a maior taxa de sobrevivência (cerca de 63%), seguidos pela 2ª classe (47%) e 3ª classe (24%). Isso mostra que a posição socioeconômica teve forte impacto nas chances de sobrevivência.
ggplot(dados_limpo, aes(x = Age, fill = Survived)) +
geom_histogram(bins = 30, alpha = 0.7, position = "identity") +
scale_fill_manual(values = c("Nao" = "#e74c3c", "Sim" = "#2ecc71")) +
labs(title = "Distribuição de Idade por Sobrevivência",
x = "Idade", y = "Contagem", fill = "Sobreviveu?") +
theme_minimal()Descrição: Crianças pequenas (até 10 anos) tiveram maior proporção de sobrevivência. A faixa etária de 20 a 40 anos concentra o maior número de passageiros, com mais mortes do que sobrevivências. Idosos acima de 60 anos tiveram baixa taxa de sobrevivência.
teste %>%
mutate(prob = prob_pred) %>%
ggplot(aes(x = Pclass, y = prob, fill = Sex)) +
geom_boxplot(alpha = 0.7) +
scale_fill_manual(values = c("female" = "#9b59b6", "male" = "#3498db")) +
labs(title = "Probabilidade Predita de Sobrevivência por Classe e Sexo",
x = "Classe", y = "Probabilidade", fill = "Sexo") +
theme_minimal()Descrição: O modelo prevê probabilidades muito distintas conforme sexo e classe. Mulheres da 1ª classe têm probabilidade próxima de 95% de sobreviver, enquanto homens da 3ª classe têm probabilidade de apenas 10%. Isso confirma que sexo e classe são os preditores mais fortes do modelo.
Use o modelo treinado para prever a probabilidade de sobrevivência dos passageiros abaixo:
novos <- data.frame(
Pclass = factor(c(1, 3, 2), levels = c(1, 2, 3)),
Sex = factor(c("female", "male", "female")),
Age = c(25, 40, 30),
SibSp = c(0, 1, 0),
Parch = c(0, 0, 1),
Fare = c(100, 10, 50)
)
print(novos)## Pclass Sex Age SibSp Parch Fare
## 1 1 female 25 0 0 100
## 2 3 male 40 1 0 10
## 3 2 female 30 0 1 50
prob_novos <- predict(modelo, newdata = novos, type = "response")
for (i in seq_along(prob_novos)) {
cat(sprintf("Passageiro %d: %.1f%% de chance de sobreviver\n",
i, prob_novos[i] * 100))
}## Passageiro 1: 95.4% de chance de sobreviver
## Passageiro 2: 5.1% de chance de sobreviver
## Passageiro 3: 81.1% de chance de sobreviver
Pergunta: Qual passageiro tem maior chance de sobreviver? Por quê? Discuta com base nos coeficientes do modelo.
A Regressão Logística mostrou-se um modelo eficiente para prever sobrevivência no Titanic. Os principais achados foram:
A Regressão Logística é uma excelente escolha para problemas binários por ser simples, interpretável e eficiente.