Partager via


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

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

  1. Créez une application Console C# appelée « ProductSalesAnomalyDetection ». Cliquez sur le bouton Suivant.

  2. Choisissez .NET 6 comme framework à utiliser. Cliquez sur le bouton Créer.

  3. Créez un répertoire nommé Data dans votre projet pour enregistrer les fichiers du jeu de données.

  4. 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.

  5. Ajoutez les instructions using suivantes en tête de votre fichier Program.cs :

    using Microsoft.ML;
    using ProductSalesAnomalyDetection;
    

Télécharger vos données

  1. 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.

  2. 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 :

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet, puis sélectionnez Ajouter > Nouvel élément.

  2. 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.

  3. Ajoutez l’instruction using suivante en haut de ProductSalesData.cs :

    using Microsoft.ML.Data;
    
  4. Supprimez la définition de classe existante et ajoutez le code suivant, lequel contient deux classes (ProductSalesData et ProductSalesPrediction), 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.

  5. 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 calculer pvalueHistoryLength.
  6. 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

  1. Remplacez la ligne Console.WriteLine("Hello World!") dans la méthode par le code suivant pour déclarer et initialiser la variable mlContext :

    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.

  1. 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 ».

Exemple de détection d’anomalie « Est-ce bizarre ».

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 :

Capture d’écran montrant deux détections de pics.

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.
  1. Créez la méthode DetectSpike() en bas du fichier Program.cs à l’aide du code suivant :

    DetectSpike(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. 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);
    
  3. 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 et pvalueHistoryLength 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ètre pvalueHistoryLength 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 le pvalueHistoryLength est bas, plus le modèle oublie les pics importants précédents.

    ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
    
  4. Ajoutez la ligne de code suivante pour transformer les données productSales comme prochaine ligne de la méthode DetectSpike() :

    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.

  5. Convertissez votre transformedData en un IEnumerable 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);
    
  6. 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 de ProductSales 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.
  7. Utilisez le code suivant pour effectuer une itération dans le IEnumerablepredictions 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("");
    
  8. Ajoutez l’appel à la méthode DetectSpike() sous l’appel à la méthode LoadFromTextFile() :

    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 :

Capture d’écran montrant une détection de point de modification.

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.
  1. Créez la méthode DetectChangepoint() juste après la déclaration de la méthode DetectSpike(), en utilisant le code suivant :

    void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. 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);
    
  3. 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));
    
  4. Utilisez la méthode Transform() pour transformer les données en ajoutant le code suivant à DetectChangePoint() :

    IDataView transformedData = iidChangePointTransform.Transform(productSales);
    
  5. Comme précédemment, convertissez votre transformedData en un IEnumerable 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);
    
  6. 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 de ProductSales 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.
  7. Effectuez une itération dans le IEnumerablepredictions 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("");
    
  8. Ajoutez l’appel suivant à la méthode DetectChangepoint() après l’appel à la méthode DetectSpike() :

    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é.