Feature engineering pour le Machine Learning
Travaux préliminaires sur les données
Nous allons cheminer à travers diverses techniques de représentations et d’analyse de la donnée structurée (tableaux de classes et de chiffres) en complément à ce que nous avons déjà abordé. À partir d’une revue systématique de ses données, le data scientist s’apprête à identifier sur quelles features et comment il pourrait élaborer sa modélisation du réel.
L’agencement des techniques suivantes ne doit pas être interprété comme un "protocole" ou une méthode d’analyse de la donnée. Nous avons fait un choix didactique qui introduit pas à pas divers outils, ou qui présente la même chose sous divers angles, afin que le lecteur dispose d’éléments complémentaires à ce qu’il sait déjà, pour qu’il se sente en confiance et imagine son propre mode exploratoire en fonction des circonstances.
Appréhension directe et rapide d’un dataset
Afin d’éviter des redondances inutiles, nous allons nous doter d’un dataset conventionnel issu de la littérature scientifique. Le package mlbench permet d’accéder à certaines données classiques et également de fabriquer des datasets adaptés à un type de problème donné.
library(tidyverse)
library(mlbench) # package pour créer ou accéder à des données de test
On peut facilement lister l’ensemble des datasets de démonstration proposés dans les packages qui sont installés sur une machine.
data(package = .packages(all.available = TRUE)) # liste des datasets disponibles
Voici un (très) court extrait de ce qui est disponible sur notre machine :
...
Data sets in package ‘mlbench':
BostonHousing Boston Housing Data
BreastCancer Wisconsin Breast Cancer Database
DNA Primate splice-junction gene sequences (DNA)
Glass Glass Identification Database
HouseVotes84 United States Congressional Voting Records 1984
Ionosphere Johns Hopkins University Ionosphere database
LetterRecognition Letter Image Recognition Data
Ozone Los Angeles ozone pollution data, 1976
PimaIndiansDiabetes Pima Indians Diabetes Database
...
Nous allons invoquer les données suivantes :
data(PimaIndiansDiabetes) # accès...
Analyse de la conformation des distributions par rapport à la loi normale
On peut valider certaines de nos intuitions par rapport à la normalité des données en confrontant ces densités à la loi normale en utilisant un diagramme Quantile-Quantile.
# ajustements loi normale(mu,e)
plot_qq(df) # diagrammes Quantile-Quantile

Diagrammes Quantile-Quantile
Même sans savoir interpréter finement un tel diagramme, cela attire notre attention sur certaines caractéristiques des données :
-
Il faudra analyser les valeurs nulles (nulles ou inconnues ?) au sein de glucose, insulin, mass, pregnant, pressure, triceps, ce qui nous permettra de décider notre stratégie (remplacement par NA, par une moyenne, suppression de lignes de mauvaise qualité, traitement particulier d’outliers…).
-
Le fait que glucose, mass et pressure ressemblent à des droites proches de la diagonale (hors valeurs nulles à qualifier) peut nous laisser penser que, conformément à leur aspect général dans la figure Densités, par variable, elles sont plus ou moins facile à approximer par une loi normale.
-
La forme régulière de pedigree pourrait nous inciter à la rapprocher d’une autre loi (à tester), typiquement une loi de Poisson ou Log-normal.
On peut comparer cet ajustement en distinguant...
Dépendance linéaire entre variables
En complément, il est d’usage de vérifier si certaines des variables explicatives ne sont pas en forte corrélation, ce qui pourrait inciter à essayer des modèles de prédiction qui ne garderaient que l’une ou l’autre de ces variables (pour bien faire, on compare l’efficacité avec l’une et avec l’autre, et quand elle est similaire, on conserve la variable la plus facile à interpréter ou à collecter dans le monde réel).
plot_correlation(df) # un tableau de corrélations

Corrélations deux à deux
Notre problème n’est pas linéairement trivial, le diabète n’est manifestement pas corrélé simplement à une variable. Excepté pour la variable age, il semble totalement exclu qu’il y ait une part de relation plus ou moins linéaire et simple entre le nombre de grossesses et les autres variables explicatives. On peut se représenter cela, peut-être à tort, en imaginant qu’il serait intéressant de réfléchir à imaginer deux grandes familles de prédicteurs : prédicteurs "sociaux" (âge, nombre de grossesses) et prédicteurs techniques (les autres). Tout cela étant posé, remarquez que cette piste ne porte que sur des relations linéaires...
Mise en évidence de différences sur les distributions
Nous allons maintenant tâcher de mettre en évidence (ou non) d’éventuelles différences de distributions pour certaines variables d’aspect gaussien (pour cet exemple, nous avons choisi glucose) entre la distribution avec diabète ou non.
Notre préoccupation principale sera la significativité de l’éventuelle différence de moyenne. L’outil nous donne également des informations sur la différence d’écart-type, qui ne nécessite pas d’interprétation forte, sinon que le fait qu’elle soit significative peut nous conforter dans l’idée qu’un algorithme judicieux saura en extraire des améliorations de prédictibilité du diabète.
library(lessR)
d <- df # par défaut lessR utilise d comme dataset
tt(glucose ~ diabetes) # graphique et stats

Distributions du glucose en fonction du diabète
La différence de moyenne est significative !
Vous pourriez aussi vouloir une représentation en "moustache/violon", en utilisant la syntaxe suivante :
library(ggstatsplot)
set.seed(666)
ggbetweenstats( ...
Points étrangers
La représentation suivante va permettre d’extraire des observations candidates à ce que vous les qualifiiez comme points étrangers (outliers). C’est à vous de choisir par essais successifs de différents paramètres le pouvoir plus ou moins discriminant du contour que vous allez tracer. Il vous reste à étudier individuellement les points à l’extérieur, dont l’identifiant est stipulé, pour commencer à envisager votre stratégie de traitement de ce type de point.
Le fait de conserver des points techniquement aberrants (anomalies ou pas) peut être valide ou non, suivant le traitement que vous appliquez sur ces valeurs. Le fait de conserver ou pas des points correspondant à des observations exceptionnelles peut vous aider à diminuer l’overfitting ou, à l’inverse, diminuer la prédictibilité de vos modèles. Toute décision de ce type doit être soigneusement consignée comme hypothèse structurante dans la documentation de vos modèles. Vous serez souvent amené à challenger ces hypothèses et à faire évoluer vos positions quant à celles-ci pour améliorer votre travail. Ne prenez pas pour argent comptant les assertions que vous pouvez trouver ici ou là vous donnant une méthode automatique pour gérer...
Tris et agrégats
1. Tris automatisés
Nous allons maintenant aborder différents tris (dont le tri à plat) de nos données au travers de différentes fonctions spécialisées.
Pour nous aider dans la présentation de nos résultats, nous avons rédigé une fonction naïve de présentation de ceux-ci, qui nous servira à plusieurs reprises dans cette section :
# une petite fonction pour imprimer head + tail d'un objet data
h_t <- function(x, titre = "", sous_titre ="", n = 3)
{
cat(titre, "\n")
cat(sous_titre, "\n")
print(rbind(head(x,n),tail(x,n)))
}
Nous nous proposons de visualiser les répartitions d’effectifs entre le nombre de grossesses (qui était le résultat d’un comptage, et donc une variable quantitative ordonnée) et le diabète. Le tri le plus simple s’effectue comme suit en utilisant l’instruction R table :
# tri à plat sur 2 var discrètes
t <- table(df$pregnant,df$diabetes) # tri simpliste
h_t(t,
"6 lignes extraites d'un simple tri à plat, nb grossesses vs statut diabète",
"----------"
)
6 lignes extraites d'un simple tri à plat, nb grossesses vs statut diabète
----------
neg pos
0 73 38
1 106 29
2 84 19
14 0 2
15 0 1
17 0 1
Ce comptage peut être utile, en particulier si vous créez un dataset réutilisable, mais vous voudrez sans doute l’enrichir avec des sommes. Notez que addmargins vous permet de choisir une autre fonction que la somme.
t <- addmargins(table(df$pregnant,df$diabetes)) # tri avec les sommes
6 lignes, tri à plat avec sommation, nb grossesses vs statut diabète
---------------
neg pos Sum
0 73 38 111
1 106 29 135
2 84 19 103
15 0...
Feature Engineering et Data Science
Avec moins de 100 000 entrées dans Google, le Feature Engineering, que l’on pourrait traduire avec un peu d’imagination comme étant le Génie des données, pourrait sembler le parent pauvre du Machine Learning et de ses 20 millions de liens. Pourtant, celui-ci représente souvent plus de la moitié de l’effort à fournir sur un projet de Data Science.
Après avoir étudié attentivement les données brutes et les avoir visualisées avec des techniques comme celles de la section précédente, il va falloir travailler les données avec un peu plus de finesse.
1. Positionnement du problème
Le Feature Engineering, qui concerne les techniques d’ingénierie utilisées pour travailler sur les attributs du problème que l’on étudie, représente un des aspects les plus délicats des Data Science.
En effet, les caractéristiques d’un problème donné ne se dévoilent pas toujours de façon naturelle et évidente.
Il faut souvent beaucoup d’efforts pour imaginer quels pourraient être les bons attributs, les créer, les sélectionner, les tester et les transformer pour les rendre pertinents et assimilables par nos algorithmes. Les bonnes prédictions nécessitent de bons attributs (en anglais predictors ou features).
Le travail sur le choix et le paramétrage des modèles, la mesure des erreurs de prédiction (ou de classification) et l’interprétation attentive des résultats sont trois éléments indissociables de la discipline dénommée Feature Engineering.
L’idée générale est d’affiner et de transformer les données brutes (data) afin que celles-ci nous apportent un gain d’informations. Mathématiquement, ce gain correspond à une diminution d’entropie. En quelque sorte, l’acquisition d’informations significatives et utilisables diminue le désordre ambiant au travers de notre compréhension du phénomène étudié.
Le premier écueil est souvent la détermination de l’objectif même de l’étude ! En effet la question posée n’est pas toujours complètement...
PCA classique, éléments mathématiques
L’assimilation de cette section n’est pas indispensable à la mise en œuvre opérationnelle des concepts décrits plus haut.
Cette petite section devrait vous permettre de lire et déchiffrer avec profit la littérature sur la PCA et donne un aperçu de quelques techniques matricielles courantes (dont le changement de base).
Avec les conventions suivantes :
-
n : nombre de lignes de données.
-
p : nombre de features (c’est-à-dire de dimensions).
-
q : nombre (réduit) de dimensions, que l’on aimerait inférieur à p !
-
i : indice, de 1 à n.
-
j : indice, de 1 à p.
-
k : indice, de 1 à q.
-
X : matrice (xij) de données centrées, ou centrées et réduites (on a appliqué une transformation préalable, centrée signifiant avoir soustrait à chaque colonne sa moyenne, réduite signifiant que l’on a de plus divisé ce résultat par l’écart-type de la colonne ; dans la littérature anglaise centré et réduit c’est le z-score). Attention deux colonnes ne doivent pas être colinéaires (c’est-à-dire une colonne ne doit pas être complètement proportionnelle à l’autre).
-
X’ : matrice (x’ij) des données transformées dans une nouvelle base.
-
X’’ : matrice (x’’ik) de données représentées dans une base tronquée de q dimensions, c’est l’objectif !

Si on remplace p par (p-1) dans la formule du calcul de la matrice de covariance, on est en train d’appliquer la correction de Bessel qui a pour objet de supprimer le biais de la variance. À l’inverse on applique parfois dans certains calculs...
Réduction des données (data reduction)
Cette petite section ne concerne pas stricto sensu le "Feature Engineering", mais a également trait au nettoyage des données avant l’utilisation d’un algorithme, souvent lié au Machine Learning. Comme la confusion est courante, jetons un œil sur cette notion. Ici le problème est inverse, la préparation ne porte plus sur les "colonnes" mais sur les "lignes".
Cette opération consiste dans l’extraction puis l’utilisation d’un sous-ensemble cohérent de lignes issues d’un dataset de grand volume. Elle est parfois utile pour économiser des ressources machines, mais aussi pour améliorer l’efficacité de certains algorithmes ou pour en diminuer l’exposition au "bruit".
Cette notion de bruit est tout à fait intuitive dans le cas de l’interprétation d’images ou de sons, où on est habitué à l’idée que les capteurs soient moins efficaces que souhaité et y introduisent du "bruit". Ce problème d’introduction de bruit n’est pas propre aux capteurs "physiques" : du "bruit" peut être introduit accidentellement dans n’importe quel type de données en fonction du processus de captation de l’information.
Une des techniques...
Réduction de la dimensionnalité et entropie
Il peut à juste titre sembler gênant de baser toute sa stratégie de réduction de la dimensionnalité sur l’algèbre linéaire, comme on le fait avec la PCA, car ces techniques pourraient embarquer certaines hypothèses simplificatrices sur la nature des données sur lesquelles le data scientist a peu de prise.
Le concept "d’entropie et d’information partagée" décrit dans l’introduction de cet ouvrage semble plus général et il semble donc légitime de bâtir une part de sa stratégie sur ces concepts.
Dans le chapitre Machine Learning, nous avons exprimé l’information mutuelle de deux variables comme étant représentable par l’expression suivante (en fonction de l’entropie) : I(X,Y) = H(X) + H(Y) - H(X,Y).
Cette expression s’annulant dans le cas de deux variables dépendantes. Ici la notion de dépendance ne suppose pas une dépendance linéaire ou même une dépendance linéaire après une quelconque transformation.
1. Description théorique du problème
Nous allons appeler S (comme set) l’ensemble de nos variables explicatives xi et y notre variable de réponse.
Notre objectif est de sélectionner un sous-ensemble de S comportant p features, à savoir certaines variables explicatives (features). Nous nommerons ce sous-ensemble s et m son nombre de features.
Il nous faut donc un critère de sélection.
En première approximation, on imagine rapidement qu’il faut trouver l’ensemble de features s qui possède la plus grande dépendance avec la cible y. En effet, si un ensemble de features possède plus d’informations mutuelles qu’un autre avec la cible, cet ensemble sera le plus à même de prédire la cible.

L’idée sera alors d’explorer toutes les possibilités d’ensemble s inclus dans S, de calculer cette dépendance et de retenir la plus élevée.
Ce qui, dès que p est peu grand, induit à calculer un très grand nombre de combinaisons d’informations...