Atelier 2 — Régression logistique

Plan

  • Brise-glace — Pourquoi une proba et pas une droite ?
  • Théorie — logit/odds, estimation, interprétation, diagnostics de base
  • 🚀 Mission 1 — Modèle logistique sur Titanic
  • Évaluation — confusion, sens/spec, ROC/AUC, calibration, seuils & coûts
  • 🚀 Mission 2 — ROC, AUC & choix de seuil
  • Compléments — interactions, non-linéarités, séparation, régularisation (aperçu)
  • Débrief & pièges fréquents

Brise-glace (Survie sur le titanic)

ggplot(df, aes(sex, fill=survived)) + geom_bar(position="fill") + labs(y="Proportion", title="Survie par sexe")

ggplot(df, aes(fare, y=survived)) + geom_point() + labs(y="Survie", title="Survie selon le prix")

  • Discussion : Pourquoi une probabilité bornée entre 0 et 1 ? Pourquoi pas une droite comme en régression linéaire ?

Logistique : de la probabilité aux log-odds

  • Probabilité \(p \in (0,1)\)
  • Odds \(= \dfrac{p}{1-p}\) (rapport de chances)
  • Logit \(= \log\dfrac{p}{1-p}\) (fonction croissante)

\[ {\log\frac{p}{1-p}}= \beta_0 + \beta_1 x_1 + \cdots + \beta_p x_p \]

  • Interprétation : \(\exp(\beta_j)\) = odds ratio (OR) pour \(x_j\) (+1 unité ou changement de niveau).

Estimation & sortie R

  • Fonction : glm(y ~ x, family=binomial, data=...)
  • summary() fournit les coefficients (log-odds)
  • broom::tidy(..., exponentiate=TRUE) donne les OR et IC
m <- glm(survived ~ sex + pclass + age + fare, data=df %>% tidyr::drop_na(), family=binomial())
summary(m)

Call:
glm(formula = survived ~ sex + pclass + age + fare, family = binomial(), 
    data = df %>% tidyr::drop_na())

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept)  3.7225052  0.4645113   8.014 1.11e-15 ***
sexmale     -2.5185052  0.2082017 -12.096  < 2e-16 ***
pclass2     -1.2765903  0.3126370  -4.083 4.44e-05 ***
pclass3     -2.5415762  0.3277677  -7.754 8.89e-15 ***
age         -0.0367302  0.0077325  -4.750 2.03e-06 ***
fare         0.0005226  0.0022579   0.231    0.817    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 964.52  on 713  degrees of freedom
Residual deviance: 647.23  on 708  degrees of freedom
AIC: 659.23

Number of Fisher Scoring iterations: 5
broom::tidy(m, exponentiate=TRUE, conf.int=TRUE) %>%
  dplyr::mutate(across(c(estimate, conf.low, conf.high), round, 3))
# A tibble: 6 × 7
  term        estimate std.error statistic  p.value conf.low conf.high
  <chr>          <dbl>     <dbl>     <dbl>    <dbl>    <dbl>     <dbl>
1 (Intercept)   41.4     0.465       8.01  1.11e-15   16.9     105.   
2 sexmale        0.081   0.208     -12.1   1.10e-33    0.053     0.12 
3 pclass2        0.279   0.313      -4.08  4.44e- 5    0.15      0.512
4 pclass3        0.079   0.328      -7.75  8.89e-15    0.041     0.148
5 age            0.964   0.00773    -4.75  2.03e- 6    0.949     0.978
6 fare           1.00    0.00226     0.231 8.17e- 1    0.996     1.00 

Note

Réflexion : - Que signifie un OR supérieur à 1 ? inférieur à 1 ? - Pourquoi présenter des OR plutôt que des coefficients bruts ?

🔍 Diagnostics du modèle logistique

  • Résidus déviance : repérer des motifs → un motif = variable manquante ou non-linéarité.
  • QQ-plot : points très écartés → observations atypiques (influence forte).
  • Résidus vs ajustés : structure (U, pente) → lien mal capté avec les log-odds.
  • Leverage : cas qui influencent beaucoup la prédiction.
  • Distance de Cook : barres hautes → observations qui tirent les coefficients.
par(mfrow=c(2,2)); plot(m); par(mfrow=c(1,1))

🚀 Transition — Mission 1

Objectifs pédagogiques :
- Construire un premier modèle logistique sur Titanic
- Lire et interpréter des odds ratios
- Tester un seuil simple (0.5) et discuter ses limites

👉 Ouvrir missions/M1_titanic.qmd

De la probabilité à la décision : seuil

  • Prédire \(\hat p\) ne suffit pas ⇒ il faut un seuil pour décider (Yes/No)
  • Seuil 0.5 : simple mais rarement optimal
df_fit <- df %>% tidyr::drop_na()

prob <- predict(m, newdata = df_fit, type = "response")
pred <- factor(ifelse(prob >= 0.5, "Yes", "No"), levels = c("No","Yes"))

table(Truth = df_fit$survived, Pred = pred)
     Pred
Truth  No Yes
  No  357  67
  Yes  81 209

Note

Réflexion :
- Que se passe-t-il si l’on prend un seuil très bas (0.1) ? Très haut (0.9) ?
- Quels types d’erreurs (FP/FN) cela favorise-t-il ?

📊 Mesures de performance

  • Accuracy (exactitude)
    = proportion de prédictions correctes ((TP + TN) / Total)
    → Globalement utile, mais trompeuse si les classes sont déséquilibrées.

  • Sensibilité (Recall / TPR)
    = proportion de positifs bien détectés (TP / (TP + FN))
    → “Parmi les passagers qui ont survécu, combien le modèle a-t-il bien prédits ?”

  • Spécificité (TNR)
    = proportion de négatifs bien détectés (TN / (TN + FP))
    → “Parmi ceux qui n’ont pas survécu, combien le modèle a-t-il bien classés ?”

  • Précision (PPV) (utile si classes déséquilibrées)
    = proportion de prédictions positives correctes (TP / (TP + FP))
    → “Quand le modèle dit Yes, quelle est la confiance ?”

  • Courbe ROC
    = trace la sensibilité (TPR) vs 1-spécificité (FPR) pour tous les seuils possibles.

  • AUC (Area Under the Curve)
    = probabilité qu’un positif ait une proba prédite plus élevée qu’un négatif.
    → 0.5 = hasard complet, 1 = discrimination parfaite.

🚀 Transition — Mission 2

Objectifs pédagogiques :
- Tracer une courbe ROC et calculer l’AUC
- Choisir un seuil adapté au contexte (coûts FP/FN)
- Explorer la calibration du modèle

👉 Ouvrir missions/M2_roc_seuils.qmd

ROC & AUC — rappels utiles

  • ROC : TPR (sensibilité) vs FPR (1-spécificité)
  • AUC : probabilité qu’un positif ait un score > qu’un négatif choisi au hasard
  • AUC ne dépend pas d’un seuil particulier

Choix de seuil contextuel

  • Le choix du seuil dépend :
    • Prévalence (taux de positifs)
    • Coûts FP/FN
  • Exemples :
    • Diagnostic médical : FN coûteux ⇒ seuil bas (maximiser sensibilité)
    • Détection fraude : FP coûteux ⇒ seuil haut (maximiser spécificité)

Compléments (aperçu)

  • Interactions et non-linéarités (splines, polynômes)
  • Déséquilibre des classes

Débrief & pièges fréquents

  • Confondre odds et probabilité
  • Utiliser par défaut un seuil de 0.5
  • Juger un modèle uniquement par l’accuracy
  • Oublier d’intégrer le contexte (coûts, domaine)
Retour au site