Tutoriel : détecter les anomalies dans les ventes de produits avec ML.NET
Découvrez comment créer une application de détection des anomalies pour des données de ventes de produit. Ce didacticiel crée une application de console .NET Core à l’aide de C# dans Visual Studio.
Dans ce tutoriel, vous allez apprendre à :
- Chargement des données
- Créer une transformation pour la détection d’anomalie de pics
- Détecter des anomalies de pics avec la transformation
- Créer une transformation pour la détection d’anomalie de points de changement
- Détecter des anomalies de points de changement avec la transformation
Vous trouverez le code source de ce tutoriel dans le référentiel dotnet/samples.
Prérequis
Visual Studio 2022 avec la charge de travail « Développement .NET Desktop » installée.
Notes
Le format de données dans product-sales.csv
est basé sur le jeu de données « Shampoo Sales Over a Three Year Period », disponible sur DataMarket et fourni dans la bibliothèque TSDL (Time Series Data Library) créée par Rob Hyndman.
Ce jeu de données est concédé sous la licence Open par défaut de DataMarket.
Création d’une application console
Créez une application Console C# appelée « ProductSalesAnomalyDetection ». Cliquez sur le bouton Suivant.
Choisissez .NET 6 comme framework à utiliser. Cliquez sur le bouton Créer.
Créez un répertoire nommé Data dans votre projet pour enregistrer les fichiers du jeu de données.
Installez le package NuGet Microsoft.ML :
Notes
Cet exemple utilise la dernière version stable des packages NuGet mentionnés, sauf indication contraire.
Dans l'Explorateur de solutions, cliquez avec le bouton droit sur votre projet, puis sélectionnez Gérer les packages NuGet. Choisissez « nuget.org » comme source du package, sélectionnez l’onglet Parcourir, recherchez Microsoft.ML, sélectionnez le package dans la liste, puis sélectionnez le bouton Installer. Cliquez sur le bouton OK dans la boîte de dialogue Aperçu des modifications, puis sur le bouton J’accepte dans la boîte de dialogue Acceptation de la licence si vous acceptez les termes du contrat de licence pour les packages répertoriés. Répétez ces étapes pour Microsoft.ML.TimeSeries.
Ajoutez les instructions
using
suivantes en tête de votre fichier Program.cs :using Microsoft.ML; using ProductSalesAnomalyDetection;
Télécharger vos données
Téléchargez le jeu de données et enregistrez-le dans le dossier Data précédemment créé :
Cliquez avec le bouton droit sur product-sales.csv et sélectionnez « Enregistrer le lien (ou la cible) sous... ».
Veillez à enregistrer le fichier *.csv dans le dossier Data ou, si vous l’avez enregistré ailleurs, à déplacer le fichier *.csv dans le dossier Data.
Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le fichier *.csv et sélectionnez Propriétés. Sous Avancé, définissez la valeur Copier dans le répertoire de sortie sur Copier si plus récent.
Le tableau suivant présente un aperçu des données de votre fichier *.csv :
Month | ProductSales |
---|---|
1 jan | 271 |
2 jan | 150,9 |
..... | ..... |
1 fév | 199,3 |
..... | ..... |
Créer des classes et définir des chemins
Définissez à présent vos structures de données de classe d’entrée et de prédiction.
Ajoutez une nouvelle classe à votre projet :
Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter > Nouvel élément.
Dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez Classe, puis remplacez le champ Nom par ProductSalesData.cs. Ensuite, sélectionnez le bouton Ajouter.
Le fichier ProductSalesData.cs s’ouvre dans l’éditeur de code.
Ajoutez l’instruction
using
suivante en haut de ProductSalesData.cs :using Microsoft.ML.Data;
Supprimez la définition de classe existante et ajoutez le code suivant, lequel contient deux classes (
ProductSalesData
etProductSalesPrediction
), au fichier ProductSalesData.cs :public class ProductSalesData { [LoadColumn(0)] public string? Month; [LoadColumn(1)] public float numSales; } public class ProductSalesPrediction { //vector to hold alert,score,p-value values [VectorType(3)] public double[]? Prediction { get; set; } }
ProductSalesData
spécifie une classe de données d’entrée. L’attribut LoadColumn spécifie les colonnes (par index de colonne) du jeu de données qui doivent être chargées.ProductSalesPrediction
spécifie la classe de données de prédiction. Pour la détection d’anomalies, la prédiction est constituée d’une alerte indiquant s’il existe une anomalie, un score brut et une p-value. Plus la p-value est proche de 0, plus il est probable qu’une anomalie existe.Créez deux champs globaux pour le chemin du fichier de jeu de données téléchargé et celui du fichier de modèle enregistré :
_dataPath
contient le chemin d’accès au jeu de données utilisé pour l’apprentissage du modèle._docsize
contient le nombre d’enregistrements dans le fichier de jeu de données. Vous allez utiliser_docSize
pour calculerpvalueHistoryLength
.
Ajoutez le code suivant à la ligne située en dessous des instructions using pour spécifier ces chemins d’accès :
string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "product-sales.csv"); //assign the Number of records in dataset file to constant variable const int _docsize = 36;
Initialiser les variables
Remplacez la ligne
Console.WriteLine("Hello World!")
dans la méthode par le code suivant pour déclarer et initialiser la variablemlContext
:MLContext mlContext = new MLContext();
La classe MLContext est un point de départ pour toutes les opérations ML.NET, et l’initialisation de
mlContext
crée un environnement ML.NET qui peut être partagé par les objets de flux de travail de création de modèle. Sur le plan conceptuel, elle est similaire àDBContext
dans Entity Framework.
Chargement des données
Les données dans ML.NET sont représentées en tant qu’interface IDataView. IDataView
est un moyen flexible et efficace de décrire des données tabulaires (numériques et texte). Les données peuvent être chargées à partir d’un fichier texte ou d’autres sources (par exemple, fichiers journaux ou de base de données SQL) dans un objet IDataView
.
Une fois la variable
mlContext
créé, ajoutez le code suivant :IDataView dataView = mlContext.Data.LoadFromTextFile<ProductSalesData>(path: _dataPath, hasHeader: true, separatorChar: ',');
LoadFromTextFile() définit le schéma de données et lit le fichier. Elle prend les variables de chemin de données et retourne un
IDataView
.
Détection des anomalies de série chronologique
La détection d’anomalies signale des événements ou comportements inattendus ou inhabituels. Elle fournit des indices sur la localisation des problèmes potentiels et vous aide à déterminer si une situation est « étrange ».
La détection d’anomalie est le processus d’identification des valeurs hors norme dans une série chronologique donnée, c’est-à-dire les points dont le comportement est inattendu ou « étrange ».
La détection d’anomalie peut se révéler utile dans de nombreux cas. Exemple :
Si tu as une voiture, tu voudras peut-être savoir : est-ce que cette jauge d’huile est normale, ou est-ce que j’ai une fuite ? Si vous analysez la consommation d’énergie, il est important de : y a-t-il une panne ?
Vous pouvez détecter deux types d’anomalies dans les séries chronologiques :
Un pic correspond à la poussée temporaire d’un comportement anormal dans le système.
Un point de changement indique le début d’un changement persistant dans le système.
Dans ML.NET, les algorithmes de détection de pic ou de point de changement IID sont adaptés aux jeux de données indépendants et identiquement distribués. Il est supposé que vos données d’entrée sont une séquence de points de données échantillonnés indépendamment les uns des autres à partir d’une distribution stationnaire.
Contrairement aux modèles des autres tutoriels, les transformations du détecteur d’anomalies de série chronologique opèrent directement sur les données d’entrée. La méthode IEstimator.Fit()
n’a pas besoin de données d’entraînement pour produire la transformation. Toutefois, elle a besoin du schéma de données, qui est fourni par une vue de données générée à partir d’une liste vide de ProductSalesData
.
Vous allez analyser les mêmes données de ventes d’un produit pour détecter les pics et les points de changement. Le processus de génération et d’entraînement du modèle est le même pour la détection des pics et des points de changement ; la principale différence réside dans l’algorithme de détection utilisé.
Détection des pics
L’objectif est d’identifier les poussées d’activité, par définition soudaines et temporaires, qui diffèrent considérablement de la majorité des valeurs de données de la série chronologique. Il est important de détecter au plus vite ces éléments, événements ou constats suspects pour pouvoir les minimiser. Vous pouvez utiliser l’approche suivante pour détecter de nombreuses anomalies, notamment des pannes, des cyberattaques et du contenu web viral. L’image suivante illustre des pics dans le jeu de données d’une série chronologique :
Ajouter la méthode CreateEmptyDataView()
Ajoutez la méthode suivante à Program.cs
:
IDataView CreateEmptyDataView(MLContext mlContext) {
// Create empty DataView. We just need the schema to call Fit() for the time series transforms
IEnumerable<ProductSalesData> enumerableData = new List<ProductSalesData>();
return mlContext.Data.LoadFromEnumerable(enumerableData);
}
La méthode CreateEmptyDataView()
produit un objet de vue de données vide avec le bon schéma à utiliser comme entrée à la méthode IEstimator.Fit()
.
Créer la méthode DetectSpike()
La méthode DetectSpike()
:
- Crée la transformation à partir de l’estimateur.
- Détecte les pics par rapport aux données de ventes historiques.
- Affiche les résultats.
Créez la méthode
DetectSpike()
en bas du fichier Program.cs à l’aide du code suivant :DetectSpike(MLContext mlContext, int docSize, IDataView productSales) { }
Utilisez IidSpikeEstimator pour entraîner le modèle à la détection de pics. Ajoutez-le à la méthode
DetectSpike()
avec le code suivant :var iidSpikeEstimator = mlContext.Transforms.DetectIidSpike(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, pvalueHistoryLength: docSize / 4);
Créez la transformation de détection de pics en ajoutant ce qui suit comme ligne de code suivante dans la méthode
DetectSpike()
:Conseil
Les paramètres
confidence
etpvalueHistoryLength
affectent la façon dont les pics sont détectés.confidence
détermine la sensibilité de votre modèle aux pics. Plus la confiance est faible, plus l’algorithme est susceptible de détecter des pics « plus petits ». Le paramètrepvalueHistoryLength
définit le nombre de points de données dans une fenêtre coulissante. La valeur de ce paramètre est généralement un pourcentage de l’ensemble du jeu de données. Plus lepvalueHistoryLength
est bas, plus le modèle oublie les pics importants précédents.ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
Ajoutez la ligne de code suivante pour transformer les données
productSales
comme prochaine ligne de la méthodeDetectSpike()
:IDataView transformedData = iidSpikeTransform.Transform(productSales);
Le code précédent utilise la méthode Transform() pour prédire plusieurs lignes d’entrée d’un jeu de données.
Convertissez votre
transformedData
en unIEnumerable
fortement typé pour faciliter l’affichage. Utilisez pour cela la méthode CreateEnumerable() avec le code suivant :var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Créez une ligne d’en-tête d’affichage à l’aide du code Console.WriteLine() suivant :
Console.WriteLine("Alert\tScore\tP-Value");
Les informations suivantes apparaissent dans vos résultats de détection des pics :
Alert
indique une alerte de pic pour un point de données spécifique.Score
est la valeur deProductSales
pour un point de données spécifique dans le jeu de données.P-Value
où « P » correspond à la probabilité. Plus la p-value est proche de 0, plus il est probable que le point de données soit une anomalie.
Utilisez le code suivant pour effectuer une itération dans le
IEnumerable
predictions
et afficher les résultats :foreach (var p in predictions) { if (p.Prediction is not null) { var results = $"{p.Prediction[0]}\t{p.Prediction[1]:f2}\t{p.Prediction[2]:F2}"; if (p.Prediction[0] == 1) { results += " <-- Spike detected"; } Console.WriteLine(results); } } Console.WriteLine("");
Ajoutez l’appel à la méthode
DetectSpike()
sous l’appel à la méthodeLoadFromTextFile()
:DetectSpike(mlContext, _docsize, dataView);
Résultats de la détection des pics
Vos résultats doivent être similaires à ce qui suit. Durant le processus, des messages sont affichés. Vous pouvez voir des avertissements ou des messages de traitement. Certains messages ont été supprimés des résultats suivants par souci de clarté.
Detect temporary changes in pattern
=============== Training the model ===============
=============== End of training process ===============
Alert Score P-Value
0 271.00 0.50
0 150.90 0.00
0 188.10 0.41
0 124.30 0.13
0 185.30 0.47
0 173.50 0.47
0 236.80 0.19
0 229.50 0.27
0 197.80 0.48
0 127.90 0.13
1 341.50 0.00 <-- Spike detected
0 190.90 0.48
0 199.30 0.48
0 154.50 0.24
0 215.10 0.42
0 278.30 0.19
0 196.40 0.43
0 292.00 0.17
0 231.00 0.45
0 308.60 0.18
0 294.90 0.19
1 426.60 0.00 <-- Spike detected
0 269.50 0.47
0 347.30 0.21
0 344.70 0.27
0 445.40 0.06
0 320.90 0.49
0 444.30 0.12
0 406.30 0.29
0 442.40 0.21
1 580.50 0.00 <-- Spike detected
0 412.60 0.45
1 687.00 0.01 <-- Spike detected
0 480.30 0.40
0 586.30 0.20
0 651.90 0.14
Détection des points de changement
Les points de changement (Change points
) indiquent des changements persistants dans la distribution de valeurs d’un flux d’événements d’une série chronologique, comme des changements de niveau ou des tendances. Ces changements persistants durent beaucoup plus longtemps que les pics (spikes
) et peuvent indiquer des événements catastrophiques. Change points
ne sont généralement pas visibles à l’œil nu, mais vous pouvez les détecter dans vos données à l’aide d’approches comme celles décrites dans la méthode suivante. L’image suivante illustre la détection des points de changement :
Créer la méthode DetectChangepoint()
La méthode DetectChangepoint()
exécute les tâches suivantes :
- Crée la transformation à partir de l’estimateur.
- Détecte les points de changement par rapport aux données de ventes historiques.
- Affiche les résultats.
Créez la méthode
DetectChangepoint()
juste après la déclaration de la méthodeDetectSpike()
, en utilisant le code suivant :void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales) { }
Créez iidChangePointEstimator dans la méthode
DetectChangepoint()
avec le code suivant :var iidChangePointEstimator = mlContext.Transforms.DetectIidChangePoint(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, changeHistoryLength: docSize / 4);
Comme vous l’avez fait précédemment, créez la transformation à partir de l’estimateur en ajoutant la ligne de code suivante dans la méthode
DetectChangePoint()
:Conseil
La détection des points de changement se fait avec un léger retard, car le modèle doit s’assurer que l’écart actuel est un changement persistant et pas seulement des pics aléatoires avant de créer une alerte. La quantité de ce délai est égale au paramètre
changeHistoryLength
. En augmentant la valeur de ce paramètre, les alertes de détection des modifications sur des modifications plus persistantes, mais le retard serait plus long.var iidChangePointTransform = iidChangePointEstimator.Fit(CreateEmptyDataView(mlContext));
Utilisez la méthode
Transform()
pour transformer les données en ajoutant le code suivant àDetectChangePoint()
:IDataView transformedData = iidChangePointTransform.Transform(productSales);
Comme précédemment, convertissez votre
transformedData
en unIEnumerable
fortement typé pour faciliter l’affichage. Utilisez pour cela la méthodeCreateEnumerable()
avec le code suivant :var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Créez un en-tête d’affichage en ajoutant la ligne de code suivante comme prochaine ligne de la méthode
DetectChangePoint()
:Console.WriteLine("Alert\tScore\tP-Value\tMartingale value");
Les informations suivantes apparaissent dans vos résultats de détection des points de changement :
Alert
indique une alerte de point de changement pour un point de données spécifique.Score
est la valeur deProductSales
pour un point de données spécifique dans le jeu de données.P-Value
où « P » correspond à la probabilité. Plus la P-value est proche de 0, plus il est probable que le point de données soit une anomalie.Martingale value
permet d’identifier le « degré d’étrangeté » d’un point de données en fonction de la séquence de valeurs P.
Effectuez une itération dans le
IEnumerable
predictions
et affichez les résultats avec le code suivant :foreach (var p in predictions) { if (p.Prediction is not null) { var results = $"{p.Prediction[0]}\t{p.Prediction[1]:f2}\t{p.Prediction[2]:F2}\t{p.Prediction[3]:F2}"; if (p.Prediction[0] == 1) { results += " <-- alert is on, predicted changepoint"; } Console.WriteLine(results); } } Console.WriteLine("");
Ajoutez l’appel suivant à la méthode
DetectChangepoint()
après l’appel à la méthodeDetectSpike()
:DetectChangepoint(mlContext, _docsize, dataView);
Résultats de la détection des points de changement
Vos résultats doivent être similaires à ce qui suit. Durant le processus, des messages sont affichés. Vous pouvez voir des avertissements ou des messages de traitement. Certains messages ont été supprimés des résultats suivants par souci de clarté.
Detect Persistent changes in pattern
=============== Training the model Using Change Point Detection Algorithm===============
=============== End of training process ===============
Alert Score P-Value Martingale value
0 271.00 0.50 0.00
0 150.90 0.00 2.33
0 188.10 0.41 2.80
0 124.30 0.13 9.16
0 185.30 0.47 9.77
0 173.50 0.47 10.41
0 236.80 0.19 24.46
0 229.50 0.27 42.38
1 197.80 0.48 44.23 <-- alert is on, predicted changepoint
0 127.90 0.13 145.25
0 341.50 0.00 0.01
0 190.90 0.48 0.01
0 199.30 0.48 0.00
0 154.50 0.24 0.00
0 215.10 0.42 0.00
0 278.30 0.19 0.00
0 196.40 0.43 0.00
0 292.00 0.17 0.01
0 231.00 0.45 0.00
0 308.60 0.18 0.00
0 294.90 0.19 0.00
0 426.60 0.00 0.00
0 269.50 0.47 0.00
0 347.30 0.21 0.00
0 344.70 0.27 0.00
0 445.40 0.06 0.02
0 320.90 0.49 0.01
0 444.30 0.12 0.02
0 406.30 0.29 0.01
0 442.40 0.21 0.01
0 580.50 0.00 0.01
0 412.60 0.45 0.01
0 687.00 0.01 0.12
0 480.30 0.40 0.08
0 586.30 0.20 0.03
0 651.90 0.14 0.09
Félicitations ! Vous venez de générer des modèles de machine learning pour détecter des anomalies (pics et points de changement) dans des données de ventes.
Vous trouverez le code source de ce tutoriel dans le référentiel dotnet/samples.
Dans ce didacticiel, vous avez appris à :
- Chargement des données
- Entraîner le modèle pour détecter des pics
- Détecter des pics avec le modèle entraîné
- Entraîner le modèle pour détecter des points de changement
- Détecter des points de changement avec le modèle entraîné
Étapes suivantes
Consultez le dépôt GitHub d’exemples d’apprentissage automatique pour explorer un exemple de détection d’anomalies dans les données de saisonnalité.