Après avoir vu les bases des données et des types d’apprentissage, il est important de savoir visualiser les données.
La visualisation permet de mieux comprendre les informations, de repérer des tendances et de prendre de meilleures décisions.
Solutions de visualisation des données
Pour bien cerner notre problème et mieux l’envisager par la suite, observons nos données pour mieux les comprendre. L’objectif de cette phase d’analyse est d’avoir une estimation de la distribution des données pour se faire une idée de leur représentativité. Les données sont-elles bien réparties ou notre échantillon ne représente-t-il que certains types ou intervalles en particulier ? Cela nous permettra ensuite de connaître les limites potentielles de notre modèle.
- Diagramme à bâtons
- Ce type de diagramme permet de visualiser les effectifs en ordonnées en fonction de catégories en abscisses.
- Ce type de diagramme sera très utilisé dans nos études de données pour les données numériques discrètes (sans retraitement nécessaire) et numériques continues (avec une création d’intervalles de données pour définir des catégories en abscisses).
- Diagramme en camembert
- Ce type de diagramme permet de visualiser les proportions des effectifs de chaque catégorie au sein de toutes les autres catégories d’un même ensemble de données.
- Ce type de diagramme est particulièrement approprié à la visualisation des données catégorielles, ordinales et binaires.
- Diagramme nuage de points
- Ce type de diagramme permet de visualiser l’évolution de la valeur d’une donnée en fonction d’une autre donnée. Par exemple, nous pouvons afficher une représentation du tarif réellement payé en fonction de l’âge de chacun des individus d’un ensemble.
- Les nuages de points permettent une visualisation pertinente des données de type temporelles, des données de sons pour représenter la relation entre deux données d’un ensemble
- Diagramme Boite à moustaches
- Ce type de diagramme permet de visualiser la répartition, la dispersion et les éventuelles anomalies d’un ensemble de données
- Le trait du bas (la « moustache« ) montre la plus petite valeur normale des données.
- La boîte représente la majorité des données :
- Le trait au milieu de la boîte, c’est la médiane (la valeur au centre).
- Les bords de la boîte montrent les quartiles, c’est-à-dire où se situent les 25% du bas et les 25% du haut des données.
- Le trait du haut (autre moustache) monte jusqu’à 1,5 fois l’écart entre les deux quartiles.
- Les points au-dessus (ou en dessous), ce sont les valeurs anormales ou extrêmes.
- Ce diagramme permet de voir comment les données sont réparties, s’il y a des valeurs très éloignées (anormales), et si les données sont bien équilibrées ou non.
- Il est très utile pour nettoyer les données avant de les utiliser dans un modèle d’intelligence artificielle ou une analyse.
- Médecine : analyser des niveaux de cholestérol dans une population.
- Ce type de diagramme permet de visualiser la répartition, la dispersion et les éventuelles anomalies d’un ensemble de données
- Diagramme Carte de chaleur
- Ce type de diagramme permet de visualiser des données en trois dimensions. En effet, il permet d’apporter une couleur correspondant à la valeur de la 3e dimension qui doit être une valeur numérique
- En magasin : on peut visualiser les zones les plus visitées dans un plan.
- Ce type de diagramme permet de visualiser des données en trois dimensions. En effet, il permet d’apporter une couleur correspondant à la valeur de la 3e dimension qui doit être une valeur numérique
- Diagramme de carte géographique
- Ce type de diagramme permet de se faire une idée de la répartition géographique d’un ensemble de données sur une vue avec un fond de carte
- Les diagrammes de carte géographique sont la meilleure manière de visualiser la répartition de données géospatiales.






Récolte, nettoyage et imputation des données
Les données qui serviront à créer nos modèles, à les entraîner et à les utiliser peuvent être récoltées soit directement via des fichiers de données pré-exportées aux formats CSV, NDJSON soit directement depuis des bases de données SQL. Quoiqu’il en soit, toutes les données que nous explorerons et utiliserons avec Rubix ML devront implémenter l’interface Traversable de PHP afin de permettre de les parcourir via des boucles foreach. Voyons maintenant les objets mis à disposition par Rubix ML pour faciliter les récoltes de données dans différents formats.
- Récolte de données au format CSV
-
use Rubix\ML\Extractors\CSV; $extractorCSV = new CSV('donnees_flux.csv', true, ',');
- Récole de données au format NDJSON (contenant des objets JSON non pas stockés dans un array JSON mais affichés les uns à la suite des autres, à la ligne)
$extractorNDJSON = new NDJSON('data_exported.ndjson');
- Récolte de données depuis une base de données
- Get l’info depuis la base de données (Doctrine ou PDO ou …)
- Extraction/Filtrage de colonnes
- Il est parfois utile d’isoler certaines colonnes dans les tableaux des données récoltées pour pouvoir effectuer des traitements sur les données conservées ou sinon pour ne garder que les données utiles et apportant une valeur ajoutée lors de l’éducation de modèles.
- Extraction de colonnes
- Il y a deux moyens de conserver des données d’un tableau : soit on les prélève pour créer un nouveau tableau à partir du premier, soit on peut supprimer des colonnes directement et ne conserver que celles souhaitées.
$path = __DIR__ . '/../../data/columnfilter.csv';
$extractor = new CSV($path, true, ';');
dump($extractor);
$dataset = Unlabeled::fromIterator($extractor);
$extractor1 = new ColumnPicker($extractor, ['name', 'frequence']);
$dataset1 = Unlabeled::fromIterator($extractor1);
$extractor2 = new ColumnPicker($extractor, ['date', 'phone']);
$dataset2 = Unlabeled::fromIterator($extractor2);
dd($dataset, $dataset1, $dataset2);
- Filtrage de colonnes
- Le filtrage permet d’isoler certaines données inutiles d’un ensemble de données récoltées
$filteredData = new ColumnFilter($extractor, ['frequence']);
$dataset = Unlabeled::fromIterator($filteredData);$csvNotNamed = new CSV('columnfilterNotNamed.csv', false, ';', '"');
$cleanDataNotNamed = new ColumnFilter($csvNotNamed, [3])
- Les ensembles de données dans Rubix ML
- Rubix ML repose fortement sur l’objet Dataset qui permet de manipuler simplement et efficacement nos tableaux de données récoltées depuis nos différentes sources.
- Comme nous l’avons vu précédemment, en fonction du type d’apprentissage que nous allons utiliser (supervisé ou non), nous utiliserons un des deux types d’objets héritant de dataset :
- Labeled : pour les ensembles de données étiquetées dans le cadre d’apprentissages supervisés. Ces objets-là contiennent chaque échantillon de données ainsi que leur étiquette associée.
$samples = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
// Ce sont les valeurs cibles (ou classes) associées à chaque échantillon :
$labels = ['a', 'b', 'c'];
$datasetLabeled = new Labeled($samples, $labels, true);- Il est possible de le faire directement depuis un objet Traversable tel que CSV, NDJSON ou un array (qui est aussi un Traversable) issu d’une base de données via la fonction statique fromIterator(Traversable $iterator) comme suit :
$datasetLabeledNDJSON = Labeled::fromIterator($extractorNDSJSON);
$datasetLabeledCSV = Labeled::fromIterator($extractorCSV);
$datasetLabeledSQL = Labeled::fromIterator($samplesSQL);
- Unlabeled : pour les ensembles de données non étiquetées dans le cadre d’apprentissages non supervisés.
$samplesUnlabeled =
[
[3.8, 8.0, 1.0, 1.0],
[2, 4.8, 3, 1.1],
[3.5, 7.5, 1.2, 1.2]
];
$datasetUnlabeled = new Unlabeled($samplesUnlabeled, true);
- Labeled : pour les ensembles de données étiquetées dans le cadre d’apprentissages supervisés. Ces objets-là contiennent chaque échantillon de données ainsi que leur étiquette associée.
- Nettoyage et imputation des données
- Une fois les données réagencées, il se peut que certains défauts apparaissent dans les ensembles obtenus. Nous allons maintenant voir de quelles solutions nous disposons pour pallier des problèmes comme la présence de contenu dupliqué, d’anomalies dans les types de données ou comment traiter les échantillons avec des données manquantes.
- Supression des doublons
- Les regroupements peuvent entraîner l’apparition de doublons dans un ensemble de données résultant. En avoir dans son ensemble d’entraînement n’est jamais très favorable car les algorithmes s’éduqueront sur des données répétitives et cela aura tendance à créer davantage de biais. Ce nettoyage pourra se faire grâce à la méthode
deduplicate()qui renverra l’ensemble de données purgé des échantillons en double pour n’en conserver qu’un seul.
- Les regroupements peuvent entraîner l’apparition de doublons dans un ensemble de données résultant. En avoir dans son ensemble d’entraînement n’est jamais très favorable car les algorithmes s’éduqueront sur des données répétitives et cela aura tendance à créer davantage de biais. Ce nettoyage pourra se faire grâce à la méthode
- Traitement en masse des données avec les transformers
- Il est possible d’appliquer des traitements en masse à nos ensembles de données via des objets nommés les transformers. Ces traitements de masse s’appliquent à un ensemble de données via la méthode
apply($transformer)d’un dataset. - Pour illustrer cette nouvelle notion, utilisons un transformer connu et indispensable, le
NumericStringConverterd’espace de nomsRubix\ML\Transformers\NumericStringConverter. Son rôle est de transformer toutes les données numériques présentes sous forme de chaîne de caractères en leur équivalent numérique avec un type numérique (int, float ou double). Il est très souvent appliqué aux ensembles de données récoltées via l’objet CSV car les données issues des fichiers CSV sont automatiquement importées en chaînes de caractères $path = __DIR__ . '/../../data/columnfilter.csv';
$extractor = new CSV($path, true, ';');
// $extractorCSV = new CSV('donnees_flux.csv', true, ',');
dump($extractor);
$dataset = Unlabeled::fromIterator($extractor);
$transformerNumeric = new NumericStringConverter();
//Application of the transformer to the Dataset
dump($dataset);
$dataset->apply($transformerNumeric);
dump($dataset);
die;- Certains transformers nécessitent des réglages avant de les appliquer à nos données. Ce sont des transformers à états (stateful en anglais)
- D’autres transformers ont la capacité de se réajuster, ce sont des transformers élastiques. Ce sont des transformers à états qui peuvent se réajuster sans remettre à zéro les réglages précédents
- Enfin, certains transformers ont la capacité d’appliquer à un ensemble de données leur transformation réciproque. Ils sont alors réversibles via la méthode
reverseApply($transformer)de l’ensemble de données auquel appliquer la transformation inverse. Ces transformers sont appelés réversibles.
- Il est possible d’appliquer des traitements en masse à nos ensembles de données via des objets nommés les transformers. Ces traitements de masse s’appliquent à un ensemble de données via la méthode
- Gestion des données manquantes, imputation des données
- Il n’est pas rare qu’il manque des données dans les ensembles fournis, par exemple il se peut que plusieurs échantillons n’aient pas tous une valeur d’une caractéristique ou d’une autre. Étant donné que nous n’arriverons pas à appliquer nos algorithmes d’IA à des données partiellement remplies, nous devons trouver des solutions pour gérer ces absences de données.
- Il existe plusieurs stratégies d’imputation de données, et il n’y a malheureusement pas de vérité générale quant à la meilleure stratégie à adopter, il faut vraiment traiter cela au cas par cas. Nous listerons ici les méthodes les plus utilisées. Avant toute autre chose, pour juger de l’impact de ces données manquantes, il est important de les compter.
- Comptage global des données manquantes
- Avant de corriger ou remplacer des données manquantes, il faut d’abord savoir combien d’échantillons sont incomplets.
Un échantillon est considéré comme incomplet dès qu’au moins une de ses valeurs est manquante. - Dans nos données, une valeur manquante peut apparaître sous deux formes :
NaNpour les variables numériques"?"pour les variables catégorielles
$missingValueCategorical = '?';
$missingValues = function ($record) use ($missingValueCategorical){
$missesContinuousValue = \iterator_contains_nan($record);
$missesCategoricalValue = in_array($missingValueCategorical, $record);
return $missesCategoricalValue || $missesContinuousValue;
};
$incompleteRecords = $datasetLabeledCSV->filter($missingValues);
$numberOfIncompleteRecords = count($incompleteRecords);- Ce code permet d’identifier et de compter tous les échantillons du jeu de données qui contiennent au moins une valeur manquante, qu’elle soit numérique (
NaN) ou catégorielle ("?").
- Avant de corriger ou remplacer des données manquantes, il faut d’abord savoir combien d’échantillons sont incomplets.
- Comptage détaillé des données manquantes
- Après avoir compté globalement les échantillons incomplets, il peut être utile de se concentrer sur une seule caractéristique (une colonne précise du jeu de données).
Cela permet de savoir combien d’échantillons n’ont pas de valeur pour cette caractéristique donnée. $column = 2;
$missingValuesAtColumn = function ($record) use ($missingValueCategorical, $column){
$missesContinuousValue = is_nan((float)$record[$column]);
$missesCategoricalValue =
($missingValueCategorical === $record[$column]);
return $missesCategoricalValue || $missesContinuousValue;
};
$incompleteRecordsAtColumn = $datasetLabeledCSV->filter($missingValuesAtColumn);
$numberOfIncompleteRecordsAtColumn =
count($incompleteRecordsAtColumn);- Ce code permet de compter combien d’échantillons ont une valeur manquante pour une caractéristique donnée, identifiée par son index de colonne.
- Après avoir compté globalement les échantillons incomplets, il peut être utile de se concentrer sur une seule caractéristique (une colonne précise du jeu de données).
- Suppression d’échantillons ou de caractéristiques (colonnes)
- Lorsqu’un jeu de données contient des valeurs manquantes, une première solution consiste à supprimer les données incomplètes. Deux approches sont possibles :
- Supprimer les échantillons incomplets
$missingValueCategorical = '?';
$cleanRecord = function ($record) use ($missingValueCategorical){
$missesContinuousValue = iterator_contains_nan($record);
$missesCategoricalValue = in_array($missingValueCategorical, $record);
return !$missesCategoricalValue && !$missesContinuousValue;
};
$cleanRecords = $datasetLabeledCSV->filter($cleanRecord);
- Supprimer une caractéristique entière (une colonne)
$cleanRecords->dropFeature(2);
- Supprimer les échantillons incomplets
- Cette méthode n’est envisageable que si le jeu de données contient suffisamment d’échantillons. En effet, supprimer trop de données peut réduire fortement la qualité des résultats, car les algorithmes d’apprentissage ont besoin d’un volume de données important.
- Lorsqu’un jeu de données contient des valeurs manquantes, une première solution consiste à supprimer les données incomplètes. Deux approches sont possibles :
- Remplacement des valeurs manquantes par une constante
- Lorsque le nombre de données manquantes est raisonnable, une solution courante consiste à remplacer ces valeurs par une constante plutôt que de supprimer des données.
- Cette constante peut être :
- Une valeur choisie arbitrairement (ex.
0,-1,100) - Une valeur représentative des données, comme la moyenne, la médiane ou un percentile
- Une catégorie fréquente pour les données catégorielles
- Une valeur choisie arbitrairement (ex.
- Ce remplacement sur un ensemble peut être réalisé via le transformer
MissingDataImputerdont l’espace de noms estRubix\ML\Transformers\MissingDataImputer. $imputer = new MissingDataImputer(
new Constant(100), // numérique
new Prior(), // catégoriel
'?'
);
$imputer->fit($datasetLabeledCSV);
if ($imputer->fitted()) {
$datasetLabeledCSV->apply($imputer);
}- Les valeurs numériques manquantes sont remplacées par
100 - Les valeurs catégorielles manquantes sont remplacées par la catégorie la plus fréquente
- Le dataset devient exploitable par les algorithmes d’IA
- Les valeurs numériques manquantes sont remplacées par
- Remplacement des valeurs manquantes par la moyenne des plus proches voisins
- Parfois, remplacer une valeur manquante par une constante (comme une moyenne globale) n’est pas suffisant, car certaines caractéristiques peuvent être liées entre elles.
Dans ce cas, une meilleure solution consiste à utiliser les plus proches voisins de chaque échantillon. - Le principe est simple :
- On cherche les $k échantillons les plus proches
- Pour les données numériques, on remplace la valeur manquante par la moyenne des voisins
- Pour les données catégorielles, on remplace par la catégorie la plus fréquente parmi les voisins
- Les voisins peuvent être pondérés par leur distance ou non
- Rubix ML fournit le transformer
KNNImputer, qui fonctionne sur le principe du voisinage. $imputerKnn = new KNNImputer(
3, // nombre de voisins
true, // pondération par la distance
'?', // valeur manquante catégorielle
new BallTree(30, new Gower())
);
$imputerKnn->fit($datasetLabeledCSV);
if ($imputerKnn->fitted()) {
$datasetLabeledCSV->apply($imputerKnn);
}- Explication simple des paramètres
- 3 : nombre de voisins utilisés pour l’imputation
- true : les voisins les plus proches ont plus d’influence
- « ? » : symbole des valeurs manquantes
- BallTree + Gower : méthode pour trouver les voisins et mesurer la distance
- Choix de la distance (important)
- Gower : adaptée aux données mixtes (numériques + catégorielles)
- Euclidienne : uniquement pour les données numériques
- Le mauvais choix de distance peut fausser l’imputation
- Pour rappel, les distances implémentées par la librairie Rubix ML sont les suivantes :
- Rubix\ML\Kernels\Canberra
- Rubix\ML\Kernels\Cosine
- Rubix\ML\Kernels\Diagonal
- Rubix\ML\Kernels\Euclidean
- Rubix\ML\Kernels\Gower
- Rubix\ML\Kernels\Hamming
- Rubix\ML\Kernels\Jaccard
- Rubix\ML\Kernels\Manhattan
- Rubix\ML\Kernels\Minkowski
- Rubix\ML\Kernels\SafeEuclidean
- Rubix\ML\Kernels\SparseCosine
- Parfois, remplacer une valeur manquante par une constante (comme une moyenne globale) n’est pas suffisant, car certaines caractéristiques peuvent être liées entre elles.
- Remplacement des valeurs manquantes par sélection aléatoire d’un des plus proches voisins
- Cette méthode est proche de l’imputation par les plus proches voisins (KNN), mais au lieu de calculer une moyenne, on copie directement la valeur d’un voisin.
- Le principe est le suivant :
- On cherche les $k plus proches voisins
- On choisit au hasard l’un de ces voisins
- On remplace la valeur manquante par la valeur de ce voisin
- Le tirage peut être pondéré par la distance (un voisin plus proche a plus de chances d’être choisi)
- Rubix ML fournit le transformer
HotDeckImputer, qui fonctionne sur le principe du voisinage. $imputerHotDeck = new HotDeckImputer(
2, // nombre de voisins
true, // pondération par la distance
'?', // valeur manquante
new BallTree(30, new Gower())
);
$imputerHotDeck->fit($datasetLabeledCSV);
if ($imputerHotDeck->fitted()) {
$datasetLabeledCSV->apply($imputerHotDeck);
}- Explication simple
- On utilise 2 voisins
- Le voisin le plus proche a plus de chances d’être choisi
- La distance Gower permet de gérer des données numériques et catégorielles
- La valeur manquante est remplacée par une valeur existante, pas par une moyenne
- Cette méthode permet de conserver des valeurs réalistes, car elles proviennent directement d’échantillons proches. Elle est utile lorsque l’on souhaite éviter de créer des valeurs artificielles.
- Supression des doublons
- Une fois les données réagencées, il se peut que certains défauts apparaissent dans les ensembles obtenus. Nous allons maintenant voir de quelles solutions nous disposons pour pallier des problèmes comme la présence de contenu dupliqué, d’anomalies dans les types de données ou comment traiter les échantillons avec des données manquantes.
La gestion des données manquantes est une étape clé de tout projet d’intelligence artificielle. Selon le contexte et la qualité des données disponibles, différentes stratégies peuvent être envisagées, chacune ayant ses avantages et ses limites.
Dans les prochains articles, nous irons plus loin en abordant la visualisation des données, les algorithmes d’apprentissage supervisé et leur mise en œuvre concrète avec PHP et Rubix ML.
Cette série a pour objectif de proposer une approche progressive et pratique de l’intelligence artificielle en PHP, accessible aux développeurs souhaitant découvrir ou approfondir ces concepts.
