ML Atlas

Le machine learning en partant de zéro · Leçon 4.2 · 21 sur 33 leçons prêtes · 12 min

Données manquantes

En bref

Supprimez les lignes à trous : il reste 333 manchots sur 344. Si l’IMC manque chez les plus lourds, la moyenne dans les trous affaiblit le lien avec la maladie.

Échauffement Deux questions de leçons précédentes. Une minute, sans jamais bloquer la leçon.
De la leçon 4.1 : Exploration : regarder avant de modéliser Vrai ou faux : « les statistiques descriptives suffisent, dessiner les données est une perte de temps ».

Voir la réponse

Bonne réponse : Faux, car les mêmes nombres peuvent cacher un arc, des groupes ou un point lointain

Dans le quartet, les mêmes nombres cachent quatre images différentes, et chez 342 manchots une corrélation a le signe opposé à celui de chaque espèce. Une image le montre tout de suite.

De la leçon 3.6 : Arrêt précoce Sur quoi l’arrêt précoce se base-t-il pour décider quand arrêter l’entraînement ?

Voir la réponse

Bonne réponse : Sur la perte de validation : il s’arrête quand elle ne baisse plus

La perte d’entraînement baisse presque jusqu’au bout, même quand le réseau apprend du bruit. La perte de validation, calculée sur des données hors entraînement, monte quand le modèle commence à surapprendre.

Dans la leçon 4.1, nous avons regardé les données avant de construire un modèle. Aujourd’hui, ce que les données ne contiennent pas. Une donnée manquante est une cellule vide du tableau : quelqu’un n’a pas mesuré, n’a rien noté ou n’a pas voulu répondre. La plupart des modèles n’acceptent pas de cellule vide, il faut donc en faire quelque chose. Il y a deux issues simples : supprimer la ligne, ou écrire une valeur dans le trou, ce qu’on appelle imputer les valeurs manquantes.

Prédisez, puis vérifiez Le tableau des manchots a 344 lignes. Le sexe manque pour 11 manchots, et chacune des quatre mesures (deux du bec, la nageoire, la masse) pour 2. Vous supprimez toute ligne où il manque quelque chose. Combien de manchots restent ?
Quel est votre degré de certitude ?

Labo interactif

Ce labo interactif fonctionne dans un navigateur avec JavaScript activé. Le texte qui l’entoure décrit ce qu’il montre.

Voir la réponse

Bonne réponse : 333, car les 2 manchots sans mesures font partie des 11 auxquels manque le sexe

Il en reste 333. Les cellules vides des mesures sont dans les mêmes 2 lignes, et ces manchots n’ont pas de sexe non plus. Vous supprimez donc 11 lignes, ni 19 ni 13. Avant de compter les pertes, regardez dans quelles lignes sont les trous.

À vous

  • Commencez par les manchots. À combien manque le sexe, à combien les mesures ? Sont-ce les mêmes lignes ?
  • Le modèle doit prédire la masse à partir des trois autres mesures. A-t-il besoin du sexe ? Combien de manchots restent si vous supprimez seulement les lignes sans les colonnes du modèle ?
  • Passez au diabète. Ici, l’IMC manque chez les patients les plus lourds. Mettez la moyenne dans le trou : le lien entre l’IMC et la progression de la maladie s’affaiblit-il ou se renforce-t-il ?
  • Ajoutez la colonne « manquant » et comparez le R² en validation croisée. Passez ensuite à des patients au hasard. Qu’est-ce qui change ?

Une fois vérifié dans le lab, mettons des mots sur ce que vous voyez.

L’idée en mots simples

Supprimer une ligne à trou est simple, mais cela coûte. Chez les manchots, les lignes avec au moins un trou sont 11 sur 344, il en reste donc 333. Un modèle qui prédit la masse à partir des mesures du bec et de la nageoire ne lit jamais le sexe. Si vous supprimez seulement les lignes auxquelles manquent les colonnes du modèle, il en reste 342. Supprimez des lignes à cause des colonnes que vous utilisez vraiment.

La question la plus importante est : chez qui les données manquent-elles ? Dans le jeu de données du diabète, chacun des 442 patients a un IMC, donc le lab le cache exprès pour 110 d’entre eux. Une fois au hasard, une fois pour les 110 plus lourds, c’est-à-dire tous ceux dont l’IMC vaut au moins 29,4. Un tel trou n’est pas aléatoire. Les patients sans IMC ont une progression moyenne de la maladie de 209, les autres de 133. Le simple fait que l’IMC manque dit quelque chose du patient.

Quand vous écrivez dans le trou la moyenne des autres patients (24,3), les 110 personnes à la plus forte progression se retrouvent à un IMC moyen. La corrélation de l’IMC avec la progression de la maladie tombe de 0,586 à 0,352 : le lien s’affaiblit. La droite du modèle ne devient pas plus plate, car ce sont les patients avec un IMC qui la fixent ; c’est l’ajustement qui se dégrade, car les 110 points remplis sont loin de la droite. Le R² d’une régression linéaire en validation croisée tombe de 0,328 à 0,106. Une colonne 0/1 supplémentaire « l’IMC manquait » aide. Le modèle donne alors au trou lui-même un poids de 76 points de progression, et le R² remonte à 0,284. Avec des trous aléatoires, cette colonne n’apporte rien : 0,264 contre 0,267 avec la moyenne seule.

Jak to policzono
  • Manchots : Palmer Penguins (Gorman, Williams et Fraser, 2014 ; paquet palmerpenguins : Horst, Hill et Gorman, 2020), licence CC0. 344 lignes, trous réels : le sexe pour 11 (Adelie 6, Gentoo 5), les quatre mesures pour les 2 mêmes manchots.
  • Diabète : Diabetes (Efron, Hastie, Johnstone et Tibshirani, 2004), distribué avec scikit-learn sous licence BSD-3-Clause. 442 patients, progression de la maladie après un an. L’IMC figure dans les données pour tous ; les trous de 110 patients sont les nôtres : au hasard ou pour les 110 à l’IMC le plus élevé.
  • Modèle : régression linéaire de la progression de la maladie sur l’IMC (avec la colonne de trou, sur l’IMC et cette colonne), validation croisée en 5 parties répétée 10 fois. La moyenne à mettre est calculée sur les patients qui ont un IMC ; en validation croisée, dans chaque découpage, sur la partie d’entraînement seulement, comme SimpleImputer dans un pipeline.

Pourquoi ça marche

La moyenne mise dans les trous est au milieu de l’axe de l’IMC, mais elle appartient à des patients de son extrémité droite. Leur progression est forte, donc le remplissage crée une pile verticale de points hauts au-dessus d’un IMC moyen. Une telle pile n’ajoute rien à la variation commune de l’IMC et de la progression. Par rapport aux seuls patients qui ont un IMC (corrélation 0,459), elle n’ajoute que de la variation à la progression, donc la corrélation tombe à 0,352. Par rapport aux données complètes (0,586), ces 110 patients perdent leur part de la variation commune : ils avaient un IMC élevé et une forte progression, et ils se retrouvent au milieu de l’axe. L’écart-type de l’IMC passe de 4,4 à 2,3, car 110 valeurs sont au même point.

Supprimer ces patients ne sauve pas la mise non plus. Il reste un nuage sans son extrémité droite, et la corrélation sur les 332 restants vaut 0,459 au lieu de 0,586. En plus, le modèle ne donne aucune réponse pour 110 patients. La colonne de trou marche parce qu’elle donne au modèle un poids à part pour le groupe dont on ne connaît pas l’IMC. Ce groupe diffère par la progression de la maladie, donc le poids reporte cette différence dans les prédictions. Quand le trou est aléatoire, le groupe sans IMC ne diffère pas du reste (156 contre 151), et le poids n’a rien à reporter.

Une erreur fréquente

Vrai ou faux : « remplissez les trous avec la moyenne et c’est réglé ». Faux. La moyenne réduit la dispersion de la colonne et fait comme si le trou n’avait jamais existé. Quand le trou dépend de la valeur elle-même, comme ici chez les plus lourds, la moyenne déforme la relation : la corrélation tombe de 0,586 à 0,352 et le R² de 0,328 à 0,106. La colonne « manquant » ramène le R² à 0,284. Dans le code ci-dessous, elle bat la moyenne seule dans 48 parties de validation sur 50.

La moyenne et la suppression de lignes conviennent quand les trous sont rares et aléatoires. Mais vérifiez d’abord si les lignes à trou diffèrent du reste.

Quiz

Trois questions pour vérifier vos acquis. Choisissez une réponse ou dépliez la solution sous chaque question. Au clavier : les flèches choisissent, Entrée ou Espace valide.

1. Dans le tableau des manchots, le sexe manque pour 11, et les mesures pour 2 de ces mêmes manchots. Combien en reste-t-il après suppression de toute ligne à trou ?
Voir la réponse

Bonne réponse : 333, car les 2 manchots sans mesures font partie des 11 manchots sans sexe

Les mesures manquantes sont dans 2 lignes où manque aussi le sexe. Vous supprimez 11 lignes, et sur 344 il en reste 333.

2. L’IMC manque chez les 110 patients les plus lourds. Que fait le remplissage par la moyenne des autres ?
Voir la réponse

Bonne réponse : Il affaiblit le lien IMC–maladie, car les plus malades se retrouvent à un IMC moyen

La corrélation tombe de 0,586 à 0,352. 110 patients à forte progression sont au même point : à la moyenne de 24,3.

3. Vrai ou faux : « remplissez les trous avec la moyenne et c’est réglé ».
Voir la réponse

Bonne réponse : Faux, car la moyenne réduit la dispersion et cache un trou qui peut vouloir dire quelque chose

Chez les plus lourds, le R² tombe de 0,328 à 0,106. La colonne « manquant » ramène 0,284, car le trou lui-même dit quelque chose du patient.

À retenir

  • Supprimez des lignes à cause des colonnes que vous utilisez : il reste 342 manchots au lieu de 333.
  • Avant de traiter les trous, vérifiez si les lignes à trou diffèrent du reste.
  • La moyenne dans les trous réduit la dispersion et, avec des trous non aléatoires, affaiblit la relation : une corrélation de 0,586 tombe à 0,352.
  • Une colonne 0/1 « manquant » laisse le modèle utiliser l’information que porte le trou lui-même : R² 0,284 au lieu de 0,106.

Pour aller plus loin : formule, code, pratique

Les maths

Remplissage par la moyenne : x̃ᵢ = x̄_obs pour les patients à trou, x̃ᵢ = xᵢ pour les autres. Les points remplis ont x̃ᵢ − x̄ = 0, ils n’ajoutent donc rien à la covariance Σ (x̃ᵢ − x̄)(yᵢ − ȳ) ni à la variance Σ (x̃ᵢ − x̄)², mais ajoutent (yᵢ − ȳ)² à la variance de y. Par rapport aux seuls patients qui ont un IMC, la somme Σ (x̃ᵢ − x̄)(yᵢ − ȳ) ne change pas tandis que la variance de y augmente, donc la corrélation r = cov(x̃, y) / (s_x̃ · s_y) baisse (0,459 → 0,352). Par rapport aux données complètes, la variance de y est la même ; c’est la covariance qui baisse, car les points remplis n’apportent plus leurs grands termes positifs (0,586 → 0,352).

La colonne de trou : ŷ = a + b · x̃ + c · m, où m = 1 quand l’IMC manquait et m = 0 sinon. Pour un patient à trou, le modèle prédit a + b · x̄_obs + c, donc c décale tout le groupe sans IMC. Ici, c = 76 avec les trous chez les plus lourds.

En code (Python)

La même expérience en pandas et scikit-learn : les trous du tableau des manchots, puis l’IMC caché pour 110 patients au hasard et pour les 110 plus lourds, la moyenne dans les trous et la moyenne avec une colonne de trou en validation croisée 10 × 5.

import numpy as np
import pandas as pd
from sklearn.datasets import load_diabetes
from sklearn.model_selection import cross_val_score, RepeatedKFold
from sklearn.linear_model import LinearRegression
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline

df = pd.read_csv("data/raw/penguins.csv")
gaps = df.isna().sum()
print(f"{len(df)} penguins; missing: " + ", ".join(f"{c} {n}" for c, n in gaps[gaps > 0].items()))
measured = df.dropna(subset=["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"])  # supprimer seulement les lignes sans les colonnes du modèle
print(f"dropna() leaves {len(df.dropna())}; dropping only rows without measurements leaves {len(measured)}")
X, y = load_diabetes(return_X_y=True, as_frame=True, scaled=False)
bmi, y = X.bmi.to_numpy(), y.to_numpy()
heavy = bmi >= np.sort(bmi)[-110]  # les 110 plus lourds : IMC d’au moins 29,4
rnd = np.zeros(len(bmi), bool)
rnd[np.random.default_rng(0).choice(len(bmi), 110, replace=False)] = True  # 110 au hasard
cv = RepeatedKFold(n_splits=5, n_repeats=10, random_state=0)
r2 = lambda model, Z: cross_val_score(model, Z, y, cv=cv, scoring="r2")
print(f"{len(bmi)} patients, BMI vs progression: r {np.corrcoef(bmi, y)[0, 1]:.3f}, CV R2 {r2(LinearRegression(), bmi[:, None]).mean():.3f}")
for name, miss in [("random", rnd), ("heaviest", heavy)]:
    hidden = np.where(miss, np.nan, bmi)[:, None]
    filled = np.where(miss, bmi[~miss].mean(), bmi)  # la moyenne des seuls patients avec un IMC
    mean_r2 = r2(make_pipeline(SimpleImputer(), LinearRegression()), hidden)  # la moyenne est apprise dans chaque découpage, sur sa partie d’entraînement seulement
    flag_r2 = r2(make_pipeline(SimpleImputer(add_indicator=True), LinearRegression()), hidden)  # deuxième colonne : 1 = l’IMC manquait
    print(f"BMI hidden for 110 {name}: progression {y[miss].mean():.0f} vs {y[~miss].mean():.0f}; mean fill: r {np.corrcoef(filled, y)[0, 1]:.3f}, CV R2 {mean_r2.mean():.3f}; mean + flag: CV R2 {flag_r2.mean():.3f}")
print(f"heaviest: mean + flag beats the mean alone in {(flag_r2 > mean_r2).sum()} of 50 folds")

Sortie

344 penguins; missing: bill_length_mm 2, bill_depth_mm 2, flipper_length_mm 2, body_mass_g 2, sex 11
dropna() leaves 333; dropping only rows without measurements leaves 342
442 patients, BMI vs progression: r 0.586, CV R2 0.332
BMI hidden for 110 random: progression 159 vs 150; mean fill: r 0.503, CV R2 0.241; mean + flag: CV R2 0.239
BMI hidden for 110 heaviest: progression 209 vs 133; mean fill: r 0.352, CV R2 0.112; mean + flag: CV R2 0.289
heaviest: mean + flag beats the mean alone in 48 of 50 folds

Les patients tirés au hasard et les découpages diffèrent de ceux du lab, donc les nombres diffèrent un peu aussi. L’image est la même : il reste 333 ou 342 manchots, la moyenne chez les plus lourds fait tomber la corrélation à 0,352, et la colonne de trou fait monter le R² de 0,112 à 0,289. Avec des trous aléatoires, la colonne n’aide pas : 0,239 contre 0,241.

Pour les praticiens
  • Dans scikit-learn : SimpleImputer(strategy="mean") ou "median", et avec add_indicator=True vous obtenez directement la colonne de trou. Mettez-le dans make_pipeline, pour que la moyenne soit calculée seulement sur la partie d’entraînement de chaque découpage.
  • df.isna().sum() et df[df.x.isna()].describe() montrent combien il y a de trous et si les lignes à trou diffèrent du reste. C’est la première chose à vérifier avant de choisir une méthode.
  • IterativeImputer et KNNImputer prédisent la valeur manquante à partir d’autres colonnes. Ils aident quand les trous dépendent d’autres colonnes, mais ne retrouvent pas un trou qui dépend de la valeur cachée elle-même ; la colonne de trou compte alors davantage.
  • Les arbres de HistGradientBoostingClassifier gèrent eux-mêmes les trous : à chaque coupure, ils apprennent de quel côté envoyer les lignes à trou.

Aller plus loin dans l’Atlas

Articles de l’encyclopédie sur les notions de cette leçon :