ML Atlas

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

Ingénierie des variables

En bref

Le cépage 2 est au milieu de l’axe, aucun seuil ne le découpe. Une colonne x² donne 77,4 % au lieu de 60,4 % ; 200 colonnes de bruit font chuter le kNN.

Échauffement Deux questions de leçons précédentes. Une minute, sans jamais bloquer la leçon.
De la leçon 4.3 : Catégories et mise à l’échelle Pourquoi le kNN sans mise à l’échelle n’obtient-il que 0,695 sur les vins ?

Voir la réponse

Bonne réponse : Parce que la proline est très dispersée et domine toute la distance

La proline a un écart type de 314, la mesure la moins variable 0,124. Sans mise à l’échelle, la distance est presque seulement la différence de proline. Après standardisation, l’exactitude monte à 0,963.

De la leçon 4.2 : Données manquantes 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.

Dans la leçon 4.3, nous avons changé la façon d’écrire les variables : l’échelle des nombres et le code des catégories. Aujourd’hui, nous fabriquons de nouvelles variables à partir de celles qui existent. L’ingénierie des variables consiste à ajouter des colonnes qui montrent plus clairement au modèle ce qu’il cherche : un carré, un rapport, une différence, le nombre de jours depuis un événement. Une bonne variable peut rendre facile un problème difficile. Beaucoup de variables faibles peuvent gâcher un modèle qui marchait.

Prédisez, puis vérifiez Des vins de trois cépages. Un modèle linéaire doit distinguer le cépage 2 des autres par la seule teneur en flavonoïdes. Sur un axe, un modèle linéaire pose un seuil : « cépage 2 » d’un côté, « un autre » de l’autre. Le cépage 2 a en moyenne 2,08, le cépage 1 a 2,98 et le cépage 3 a 0,78. Un seuil séparera-t-il le cépage 2 ?
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 : Non, car le cépage 2 est au milieu et a des vins d’autres cépages des deux côtés

Non. Au milieu de l’axe, un seuil laisse toujours un des deux autres cépages du côté « cépage 2 ». Le meilleur seuil sur les vins d’entraînement atteint 61,6 %, à peine plus que les 60,0 % obtenus en disant « un autre cépage » pour chaque vin, et sur les vins de test exactement autant : 60,4 %. La SVM linéaire du lab ne prédit le cépage 2 nulle part. Seule une nouvelle colonne x² lui permet de découper l’intervalle du milieu.

À vous

  • Commencez avec x seul. Où le modèle prédit-il le cépage 2 ? Quelle est l’exactitude de test, et d’où vient-elle ?
  • Ajoutez la colonne x². À quoi ressemble la frontière dans le plan (x, x²), et sur l’axe des flavonoïdes seul ?
  • Passez au bruit. Descendez le curseur depuis 200 colonnes. Quand le kNN reconnaît-il le mieux les vins mis de côté ?
  • Regardez le contraste des distances. Que devient l’écart entre le vin le plus proche et le plus lointain quand les colonnes s’accumulent ?

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

L’idée en mots simples

Un modèle linéaire sur un axe ne sait faire qu’une chose : poser un seuil. Le cépage 2 est au milieu de l’axe des flavonoïdes, donc un seuil ne peut le découper d’aucun côté : il sépare au plus un des cépages voisins. Le meilleur seuil de ce type sépare le cépage 3 et atteint 61,6 % à l’entraînement, alors que dire « un autre cépage » pour chaque vin donne 60,0 %. Le gain est minime, et au test il disparaît. La SVM linéaire du lab ne prédit le cépage 2 nulle part et obtient 60,4 %, la part des autres cépages parmi les 53 vins de test. Ajoutons la colonne x², le carré des flavonoïdes standardisés. Les vins des deux bouts de l’axe ont un x² grand, ceux du milieu un x² petit. Le même modèle linéaire trace maintenant une droite dans le plan (x, x²). Sur l’axe des flavonoïdes, cela fait deux seuils, un intervalle de 1,11 à 2,82. L’exactitude monte à 77,4 %. Le modèle n’a pas changé ; ce qu’il reçoit, si.

Plus de variables ne veut pas dire mieux, pourtant. Le kNN (k = 5) sur 13 mesures chimiques reconnaît 98,1 % des vins mis de côté. Nous ajoutons des colonnes de bruit pur, des nombres aléatoires à la même échelle. Avec 200 colonnes de ce type, l’exactitude tombe à 77,4 %. Chaque colonne de bruit pèse autant dans la distance qu’une vraie mesure, donc les vins « les plus proches » ne se ressemblent plus. C’est le fléau de la dimension : en grande dimension, tous les points sont presque à la même distance les uns des autres.

Jak to policzono
  • Vins : Wine (Aeberhard et Forina, 1992 ; UCI, licence CC BY 4.0), 178 vins, 13 mesures chimiques, 3 cépages. Découpage stratifié : 125 vins pour apprendre, 53 pour le test.
  • Nouvelle variable : un modèle linéaire (une machine à vecteurs de support linéaire, C = 1) sur les flavonoïdes standardisés, cépage 2 contre les autres. Flavonoïdes moyens calculés sur les 178 vins.
  • Bruit : kNN avec k = 5 sur les 13 mesures standardisées et de 0 à 200 colonnes de nombres tirés d’une loi normale (moyenne 0, écart-type 1), avec une graine fixe.

Pourquoi ça marche

Un modèle linéaire coupe l’espace par une droite (par un plan en plus grande dimension). Sur un axe, une droite est un point : un seuil. La colonne x² ajoute un second axe. Les vins des deux bouts de l’axe des flavonoïdes se retrouvent haut sur la parabole, ceux du milieu en bas. Une droite peut alors couper le cépage 2 par le haut. Sur 20 autres découpages des vins, sans x² la SVM linéaire ne prédit pas une seule fois le cépage 2, et le meilleur seuil unique de l’entraînement ne bat « toujours un autre » au test que dans 1 cas sur 20. Avec x² il découpe toujours un intervalle : de 67,9 à 84,9 % au test.

Avec le bruit, c’est l’inverse. La distance du kNN est une somme de carrés des différences sur toutes les colonnes. Avec 13 mesures, le vin d’entraînement le plus lointain est en moyenne 296,5 % plus loin que le plus proche. Avec 200 colonnes de bruit, seulement 25,7 %. Les différences dans le bruit sont aléatoires, et nombreuses, donc elles noient les 13 vraies différences. Sur 20 tirages du bruit, 200 colonnes donnent de 64,2 à 83,0 %, toujours moins que 98,1 % sans bruit.

Une erreur fréquente

Vrai ou faux : « plus de variables font un meilleur modèle ». Faux. Une variable aide quand elle porte de l’information sous une forme que le modèle sait utiliser, comme x² pour le cépage 2. Les colonnes sans information nuisent : 200 colonnes de bruit font tomber le kNN de 98,1 % à 77,4 %. Dans le code ci-dessous, l’exactitude du kNN tombe de 0,962 sans bruit à 0,689 avec 200 colonnes.

Une bonne variable nouvelle vient en général de la compréhension du problème : ce qui devrait compter, et sous quelle forme. Tout jeter dedans, c’est inviter le bruit.

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. Pourquoi un seul seuil sur les flavonoïdes ne peut-il pas séparer le cépage 2 ?
Voir la réponse

Bonne réponse : Parce que le cépage 2 est au milieu et qu’un seuil ne découpe pas un intervalle central

En moyenne 2,08 contre 2,98 et 0,78 pour les autres. Chaque seuil laisse aussi un autre cépage du côté « cépage 2 ». Le meilleur seuil atteint 61,6 % à l’entraînement contre 60,0 % pour « toujours un autre », et la SVM linéaire ne prédit le cépage 2 nulle part : 60,4 %.

2. Vous ajoutez 200 colonnes de bruit aléatoire aux 13 mesures des vins. Qu’arrive-t-il au kNN ?
Voir la réponse

Bonne réponse : L’exactitude baisse, car le bruit noie les vraies différences dans la distance

L’exactitude tombe de 98,1 % à 77,4 %. Chaque colonne de bruit pèse dans la distance autant qu’une vraie mesure.

3. Vrai ou faux : « plus de variables font un meilleur modèle ».
Voir la réponse

Bonne réponse : Faux, car les variables sans information ajoutent du bruit et peuvent baisser l’exactitude

200 colonnes de bruit font tomber le kNN de 98,1 % à 77,4 %. Ce qui aide, c’est une variable porteuse d’information sous une bonne forme, comme x² pour le cépage 2.

À retenir

  • Une variable de bonne forme rend facile un problème difficile : x² fait monter l’exactitude de 60,4 % à 77,4 %.
  • Un modèle linéaire avec de nouvelles colonnes reste linéaire ; c’est ce qu’il reçoit en entrée qui change.
  • Les colonnes sans information nuisent : 200 colonnes de bruit font tomber le kNN de 98,1 % à 77,4 %.
  • En grande dimension, les distances s’égalisent, donc les modèles fondés sur les distances perdent le plus.

Pour aller plus loin : formule, code, pratique

Les maths

La nouvelle variable : z = (x − x̄) / s, et le modèle linéaire reçoit (z, z²). La frontière w₁ · z + w₂ · z² + b = 0 est une équation du second degré en z, elle a donc jusqu’à deux racines : deux seuils sur l’axe x et un intervalle entre eux.

La distance du kNN : d(a, b)² = Σⱼ (aⱼ − bⱼ)² sur toutes les colonnes. Pour m colonnes de bruit tirées de N(0, 1), chacune ajoute en moyenne 2 à d² (la variance de la différence de deux nombres indépendants), quel que soit le cépage. Avec un grand m, la somme du bruit noie les 13 vrais termes, et le contraste (d_max − d_min) / d_min diminue.

En code (Python)

La même expérience dans scikit-learn : un modèle linéaire sur les flavonoïdes sans x² et avec x² en validation croisée 10 × 5, puis le kNN sur les 13 mesures et un nombre croissant de colonnes de bruit.

import numpy as np
from sklearn.datasets import load_wine
from sklearn.model_selection import cross_val_score, RepeatedStratifiedKFold
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier

wine = load_wine(as_frame=True)
x, is2 = wine.data[["flavanoids"]], (wine.target == 1).astype(int)
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=10, random_state=0)
line = make_pipeline(StandardScaler(), SVC(kernel="linear", C=1))
squared = make_pipeline(StandardScaler(), PolynomialFeatures(2, include_bias=False), StandardScaler(), SVC(kernel="linear", C=1))  # la nouvelle colonne x²
a, b = cross_val_score(line, x, is2, cv=cv), cross_val_score(squared, x, is2, cv=cv)
print(f"cultivar 2 vs the rest from flavanoids, 10 x 5 CV: x only {a.mean():.3f}, x and x^2 {b.mean():.3f}; always 'other' {1 - is2.mean():.3f}")
print(f"x only predicts cultivar 2 for {line.fit(x, is2).predict(x).sum()} of {len(x)} wines; x and x^2 wins in {(b > a).sum()} of 50 folds")
X, y = wine.data.to_numpy(), wine.target.to_numpy()
noise = np.random.default_rng(0).normal(size=(len(X), 200))  # colonnes de bruit pur
for m in [0, 10, 50, 200]:
    acc = cross_val_score(make_pipeline(StandardScaler(), KNeighborsClassifier(5)), np.hstack([X, noise[:, :m]]), y, cv=cv)
    print(f"kNN on 13 measurements + {m} noise columns: {acc.mean():.3f}")

Sortie

cultivar 2 vs the rest from flavanoids, 10 x 5 CV: x only 0.601, x and x^2 0.755; always 'other' 0.601
x only predicts cultivar 2 for 0 of 178 wines; x and x^2 wins in 49 of 50 folds
kNN on 13 measurements + 0 noise columns: 0.962
kNN on 13 measurements + 10 noise columns: 0.940
kNN on 13 measurements + 50 noise columns: 0.842
kNN on 13 measurements + 200 noise columns: 0.689

Les découpages et le bruit diffèrent de ceux du lab, donc les nombres diffèrent un peu aussi. L’image est la même : sans x², le modèle ne prédit pas une seule fois le cépage 2 (0,601, autant que « toujours un autre »), avec x² il obtient 0,755 et gagne dans 49 parties de validation sur 50. Le bruit fait tomber le kNN de 0,962 à 0,689.

Pour les praticiens
  • Dans scikit-learn : PolynomialFeatures(2) ajoute les carrés et les produits de paires de variables, SplineTransformer des courbes lisses, FunctionTransformer(np.log1p) un logarithme pour les variables à longue traîne. Mettez-les dans make_pipeline, pour que la validation croisée voie tout le chemin.
  • Les meilleures variables viennent de la connaissance du problème : un rapport (prix au mètre carré), une différence (jours depuis le dernier achat), une partie de la date (jour de la semaine). Le modèle ne les inventera pas s’il ne reçoit pas les ingrédients bruts sous une bonne forme.
  • Quand les variables sont nombreuses, choisissez-les dans chaque découpage (SelectKBest dans le pipeline) ou prenez un modèle régularisé (leçon 3.4). Choisir les variables sur toutes les données avant la validation est une fuite (leçon 4.5).
  • Les méthodes à noyau que vous verrez avec les machines à vecteurs de support calculent le résultat comme si elles avaient ajouté de telles colonnes, mais sans les construire explicitement.

Aller plus loin dans l’Atlas

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