Partage via


Préparer des données pour la création d’un modèle

Découvrez comment utiliser ML.NET pour préparer des données pour un traitement supplémentaire ou créer un modèle.

Les données sont souvent impures et éparses. ML.NET algorithmes de Machine Learning s’attendent à ce que les entrées ou fonctionnalités soient dans un seul vecteur numérique. De même, la valeur à prédire (étiquette), en particulier lorsqu’il s’agit de données catégorielles, doit être encodée. Par conséquent, l’un des objectifs de préparation des données consiste à obtenir les données dans le format attendu par ML.NET algorithmes.

Fractionner les données en jeux de test et d’apprentissage

La section suivante décrit les problèmes courants lors de l’entraînement d’un modèle appelé surajustement et sous-ajustement. Le fractionnement de vos données et de la validation de vos modèles à l’aide d’un ensemble conservé peut vous aider à identifier et à atténuer ces problèmes.

Surajustement et sous-ajustement

Le surajustement et le sous-ajustement sont les deux problèmes les plus courants que vous rencontrez lors de l’entraînement d’un modèle. Le sous-ajustement signifie que l’entraîneur sélectionné n’est pas suffisamment capable d’ajuster le jeu de données d’entraînement, ce qui entraîne généralement une perte élevée pendant l’entraînement et un score/une métrique faible sur le jeu de données de test. Pour résoudre ce problème, vous devez sélectionner un modèle plus puissant ou effectuer davantage d’ingénierie des fonctionnalités. Le surajustement est le contraire : il se produit lorsque le modèle s'adapte trop bien aux données d’entraînement. Cela entraîne généralement une faible métrique de perte pendant l’entraînement, mais une perte élevée sur le jeu de données de test.

Une bonne analogie pour ces concepts est l’étude d’un examen. Supposons que vous connaissiez les questions et réponses à l’avance. Après avoir étudié, vous prenez le test et obtenez un score parfait. Bonne nouvelle ! Toutefois, lorsque vous recevez à nouveau l’examen avec les questions réorganisés et avec une formulation légèrement différente, vous obtenez un score inférieur. Cela suggère que vous avez mémorisé les réponses et n’a pas réellement appris les concepts sur lesquels vous étiez testé. Il s’agit d’un exemple de surajustement. Le sous-ajustement est le case contraire où les documents d’étude que vous avez reçus ne représentent pas précisément ce sur quoi vous êtes évalué pour l’examen. Par conséquent, vous avez recours à deviner les réponses, car vous n’avez pas suffisamment de connaissances pour répondre correctement.

Fractionner les données

Prenez les données d’entrée suivantes et chargez-les dans une IDataView appelée data:

var homeDataList = new HomeData[]
{
    new()
    {
        NumberOfBedrooms = 1f,
        Price = 100_000f
    },
    new()
    {
        NumberOfBedrooms = 2f,
        Price = 300_000f
    },
    new()
    {
        NumberOfBedrooms = 6f,
        Price = 600_000f
    },
    new()
    {
        NumberOfBedrooms = 3f,
        Price = 300_000f
    },
    new()
    {
        NumberOfBedrooms = 2f,
        Price = 200_000f
    }
};

Pour fractionner des données en jeux d'entraînement/test, utilisez la méthode TrainTestSplit(IDataView, Double, String, Nullable<Int32>).

// Apply filter
TrainTestData dataSplit = mlContext.Data.TrainTestSplit(data, testFraction: 0.2);

Le paramètre testFraction est utilisé pour prendre 0,2 ou 20% du jeu de données à des fins de test. Les 80% restants sont utilisés pour l’entraînement.

Le résultat est DataOperationsCatalog.TrainTestData avec deux IDataViews auxquels vous pouvez accéder via TrainSet et TestSet.

Filtrer les données

Parfois, toutes les données d’un jeu de données ne sont pas pertinentes pour l’analyse. Une approche pour supprimer les données non pertinentes est le filtrage. Le DataOperationsCatalog contient un ensemble d’opérations de filtre qui prennent un IDataView contenant toutes les données et retournent un IDataView contenant uniquement les points d’intérêt des données. Il est important de noter que, étant donné que les opérations de filtre ne sont pas une IEstimator ou ITransformer comme celles du TransformsCatalog, elles ne peuvent pas être incluses dans le cadre d’un pipeline de préparation des données EstimatorChain ou TransformerChain.

Prenez les données d’entrée suivantes et chargez-les dans une IDataView appelée data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms=1f,
        Price=100000f
    },
    new ()
    {
        NumberOfBedrooms=2f,
        Price=300000f
    },
    new ()
    {
        NumberOfBedrooms=6f,
        Price=600000f
    }
};

Pour filtrer les données en fonction de la valeur d’une colonne, utilisez la méthode FilterRowsByColumn.

// Apply filter
IDataView filteredData = mlContext.Data.FilterRowsByColumn(data, "Price", lowerBound: 200000, upperBound: 1000000);

L’exemple ci-dessus prend les lignes dans le jeu de données ayant un prix entre 200 000 et 1 000 000. Le résultat de l’application de ce filtre retourne uniquement les deux dernières lignes des données et exclut la première ligne, car son prix est 100000 et non entre la plage spécifiée.

Remplacer les valeurs manquantes

Les valeurs manquantes sont une occurrence courante dans les jeux de données. Une approche pour traiter les valeurs manquantes consiste à les remplacer par la valeur par défaut du type donné, s'il y en a, ou par une autre valeur significative telle que la valeur moyenne des données.

Prenez les données d’entrée suivantes et chargez-les dans une IDataView appelée data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms=1f,
        Price=100000f
    },
    new ()
    {
        NumberOfBedrooms=2f,
        Price=300000f
    },
    new ()
    {
        NumberOfBedrooms=6f,
        Price=float.NaN
    }
};

Notez que le dernier élément de la liste a une valeur manquante pour Price. Pour remplacer les valeurs manquantes dans la colonne Price, utilisez la méthode ReplaceMissingValues pour remplir cette valeur manquante.

Important

ReplaceMissingValue fonctionne uniquement avec des données numériques.

// Define replacement estimator
var replacementEstimator = mlContext.Transforms.ReplaceMissingValues("Price", replacementMode: MissingValueReplacingEstimator.ReplacementMode.Mean);

// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer replacementTransformer = replacementEstimator.Fit(data);

// Transform data
IDataView transformedData = replacementTransformer.Transform(data);

ML.NET prend en charge plusieurs modes de remplacement . L’exemple ci-dessus utilise le mode de remplacement Mean, qui remplit la valeur manquante avec la valeur moyenne de cette colonne. Le résultat du remplacement remplit la propriété Price pour le dernier élément des données avec 200 000, car il s’agit de la moyenne de 100 000 et 300 000.

Utiliser des normaliseurs

normalisation est une technique de prétraitement des données utilisée pour mettre à l’échelle les fonctionnalités dans la même plage, généralement entre 0 et 1, afin qu’elles puissent être traitées plus précisément par un algorithme machine learning. Par exemple, les plages d’âge et de revenu varient considérablement avec l’âge généralement dans la plage de 0 à 100 ans et le revenu étant généralement dans la plage de zéro à milliers. Visitez la page transformations pour obtenir une liste et une description plus détaillées des transformations de normalisation.

Normalisation Min Max

Prenez les données d’entrée suivantes et chargez-les dans une IDataView appelée data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms = 2f,
        Price = 200000f
    },
    new ()
    {
        NumberOfBedrooms = 1f,
        Price = 100000f
    }
};

La normalisation peut être appliquée aux colonnes avec des valeurs numériques uniques ainsi que des vecteurs. Normalisez les données dans la colonne Price à l’aide de la normalisation min-max avec la méthode NormalizeMinMax.

// Define min-max estimator
var minMaxEstimator = mlContext.Transforms.NormalizeMinMax("Price");

// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer minMaxTransformer = minMaxEstimator.Fit(data);

// Transform data
IDataView transformedData = minMaxTransformer.Transform(data);

Les valeurs de prix d’origine [200000,100000] sont converties en [ 1, 0.5 ] à l’aide de la formule de normalisation MinMax qui génère des valeurs de sortie dans la plage de 0 à 1.

Quantification

binning convertit les valeurs continues en une représentation discrète de l’entrée. Par exemple, supposons que l’une de vos fonctionnalités est l’âge. Au lieu d’utiliser la valeur d’âge réelle, le binning crée des plages pour cette valeur. 0-18 pourrait être une cellule, de même que 19-35, et ainsi de suite.

Prenez les données d’entrée suivantes et chargez-les dans une IDataView appelée data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms=1f,
        Price=100000f
    },
    new ()
    {
        NumberOfBedrooms=2f,
        Price=300000f
    },
    new ()
    {
        NumberOfBedrooms=6f,
        Price=600000f
    }
};

Normalisez les données en catégories à l’aide de la méthode NormalizeBinning. Le paramètre maximumBinCount vous permet de spécifier le nombre de bacs nécessaires pour classifier vos données. Dans cet exemple, les données seront placées dans deux bacs.

// Define binning estimator
var binningEstimator = mlContext.Transforms.NormalizeBinning("Price", maximumBinCount: 2);

// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
var binningTransformer = binningEstimator.Fit(data);

// Transform Data
IDataView transformedData = binningTransformer.Transform(data);

La quantification crée des bornes de cellule de [0,200000,Infinity]. Par conséquent, les bacs résultants sont [0,1,1] parce que la première observation est comprise entre 0 et 200000 et les autres sont supérieures à 200000 mais inférieures à l’infini.

Utiliser des données catégorielles

L’un des types de données les plus courants est des données catégorielles. Les données catégorielles ont un nombre fini de catégories. Par exemple, les états des États-Unis ou une liste des types d’animaux trouvés dans un ensemble d’images. Que les données catégorielles soient des caractéristiques ou des étiquettes, elles doivent être mappées sur une valeur numérique afin qu’elles puissent être utilisées pour générer un modèle Machine Learning. Il existe plusieurs façons d’utiliser des données catégorielles dans ML.NET, en fonction du problème que vous résolvez.

Mappage clé-valeur

Dans ML.NET, une clé est une valeur entière qui représente une catégorie. Le mappage de valeurs clés est le plus souvent utilisé pour mapper des étiquettes de chaîne en valeurs entières uniques pour l’entraînement, puis revenir à leurs valeurs de chaîne lorsque le modèle est utilisé pour effectuer une prédiction.

Les transformations utilisées pour effectuer le mappage de valeurs de clé sont mapValueToKey et MapKeyToValue.

MapValueToKey ajoute un dictionnaire de mappages dans le modèle, afin que MapKeyToValue puisse effectuer la transformation inverse lors d’une prédiction.

Encodage à chaud

Un encodage à chaud prend un ensemble fini de valeurs et les mappe sur des entiers dont la représentation binaire a une valeur 1 unique dans des positions uniques dans la chaîne. Un encodage à chaud peut être le meilleur choix s’il n’existe aucun ordre implicite des données catégorielles. Le tableau suivant montre un exemple avec des codes zip sous forme de valeurs brutes.

Valeur brute Valeur encodée à chaud
98052 00...01
98100 00...10
... ...
98109 10...00

La transformation pour convertir des données catégorielles en nombres encodés à chaud est OneHotEncoding.

Hashing

Le hachage est une autre façon de convertir des données catégorielles en nombres. Une fonction de hachage mappe les données d’une taille arbitraire (une chaîne de texte par exemple) sur un nombre avec une plage fixe. Le hachage peut être un moyen rapide et efficace de vectoriser les caractéristiques. L’un des exemples notables de hachage dans le Machine Learning est le filtrage du courrier indésirable où, au lieu de conserver un dictionnaire de mots connus, chaque mot de l’e-mail est haché et ajouté à un grand vecteur de fonctionnalité. L’utilisation du hachage de cette façon évite le problème de filtrage malveillant du courrier indésirable par l’utilisation de mots qui ne se trouvent pas dans le dictionnaire.

ML.NET fournit une transformation de hachage pour effectuer le hachage sur le texte, les dates et les données numériques. Comme pour le mappage clé-valeur, les sorties de la transformation de hachage sont des types de clés.

Utiliser des données texte

Comme les données catégorielles, les données textuelles doivent être transformées en fonctionnalités numériques avant de les utiliser pour créer un modèle Machine Learning. Visitez la page transformations pour obtenir une liste et une description plus détaillées des transformations de texte.

Supposons que nous utilisons des données telles que celles ci-dessous qui ont été chargées dans un IDataView :

ReviewData[] reviews = new ReviewData[]
{
    new ReviewData
    {
        Description="This is a good product",
        Rating=4.7f
    },
    new ReviewData
    {
        Description="This is a bad product",
        Rating=2.3f
    }
};

ML.NET fournit la transformation FeaturizeText qui prend la valeur de chaîne d’un texte et crée un ensemble de caractéristiques à partir du texte, en appliquant une série de transformations individuelles.

// Define text transform estimator
var textEstimator  = mlContext.Transforms.Text.FeaturizeText("Description");

// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer textTransformer = textEstimator.Fit(data);

// Transform data
IDataView transformedData = textTransformer.Transform(data);

La transformation résultante convertit les valeurs de texte de la colonne Description en vecteur numérique qui ressemble à la sortie ci-dessous :

[ 0.2041241, 0.2041241, 0.2041241, 0.4082483, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0, 0, 0, 0, 0.4472136, 0.4472136, 0.4472136, 0.4472136, 0.4472136, 0 ]

Les transformations qui composent FeaturizeText peuvent également être appliquées individuellement pour un contrôle plus fin sur la génération de caractéristiques.

// Define text transform estimator
var textEstimator = mlContext.Transforms.Text.NormalizeText("Description")
    .Append(mlContext.Transforms.Text.TokenizeIntoWords("Description"))
    .Append(mlContext.Transforms.Text.RemoveDefaultStopWords("Description"))
    .Append(mlContext.Transforms.Conversion.MapValueToKey("Description"))
    .Append(mlContext.Transforms.Text.ProduceNgrams("Description"))
    .Append(mlContext.Transforms.NormalizeLpNorm("Description"));

textEstimator contient un sous-ensemble d’opérations effectuées par la méthode FeaturizeText. L’avantage d’un pipeline plus complexe est le contrôle et la visibilité des transformations appliquées aux données.

À l’aide de la première entrée comme exemple, voici une description détaillée des résultats générés par les étapes de transformation définies par textEstimator:

Texte d’origine : il s’agit d’un bon produit

Transformer Description Résultat
1. NormalizeText Convertit toutes les lettres en minuscules par défaut c’est un bon produit
2. TokenizeWords Fractionne la chaîne en mots individuels ["this","is","a","good","product"]
3. RemoveDefaultStopWords Supprime les mots vides comme is et a. ["bon", "produit"]
4. MapValueToKey Mappe les valeurs aux clés (catégories) en fonction des données d’entrée [1,2]
5. ProduceNGrams Transforme le texte en séquence de mots consécutifs [1,1,1,0,0]
6. NormalizeLpNorm Applique une mise à l’échelle aux entrées d’après leur norme IP [ 0.577350529, 0.577350529, 0.577350529, 0, 0 ]