Självstudie: Identifiera avvikelser i produktförsäljning med ML.NET

Lär dig hur du skapar ett program för avvikelseidentifiering för produktförsäljningsdata. Den här självstudien skapar ett .NET Core-konsolprogram med C# i Visual Studio.

I den här guiden får du lära dig att:

  • Läsa in data
  • Skapa en transformering för toppavvikelseidentifiering
  • Identifiera toppavvikelser med transformen
  • Skapa en transformering för avvikelseidentifiering för ändringspunkt
  • Identifiera avvikelser i ändringspunkter med transformen

Du hittar källkoden för den här självstudien på lagringsplatsen dotnet/samples .

Krav

Anteckning

Dataformatet i product-sales.csv baseras på datauppsättningen "Shampoo Sales Over a Three Year Period" som ursprungligen hämtades från DataMarket och tillhandahålls av Time Series Data Library (TSDL), skapad av Rob Hyndman. "Shampoo Sales Over a Three Year Period" Dataset Licensed under DataMarket Default Open License.

Skapa ett konsolprogram

  1. Skapa ett C# -konsolprogram med namnet "ProductSalesAnomalyDetection". Klicka på knappen Nästa.

  2. Välj .NET 6 som ramverk att använda. Klicka på knappen Skapa.

  3. Skapa en katalog med namnet Data i projektet för att spara datamängdsfilerna.

  4. Installera Microsoft.ML NuGet-paketet:

    Anteckning

    I det här exemplet används den senaste stabila versionen av De NuGet-paket som nämns om inget annat anges.

    I Solution Explorer högerklickar du på projektet och väljer Hantera NuGet-paket. Välj "nuget.org" som paketkälla, välj fliken Bläddra, sök efter Microsoft.ML och välj knappen Installera . Välj knappen OK i dialogrutan Förhandsgranska ändringar och välj sedan knappen Jag accepterar i dialogrutan Godkännande av licens om du godkänner licensvillkoren för de paket som anges. Upprepa de här stegen för Microsoft.ML.TimeSeries.

  5. Lägg till följande using -instruktioner överst i filen Program.cs :

    using Microsoft.ML;
    using ProductSalesAnomalyDetection;
    

Ladda ned dina data

  1. Ladda ned datauppsättningen och spara den i mappen Data som du skapade tidigare:

    • Högerklicka på product-sales.csv och välj "Spara länk (eller mål) som..."

      Se till att du antingen sparar filen *.csv i mappen Data eller när du har sparat den någon annanstans, flytta filen *.csv till mappen Data .

  2. I Solution Explorer högerklickar du på filen *.csv och väljer Egenskaper. Under Avancerat ändrar du värdet för Kopiera till utdatakatalog till Kopiera om nyare.

Följande tabell är en dataförhandsgranskning från din *.csv-fil:

Månad ProductSales
1 jan 271
2 jan 150.9
..... .....
1-feb 199.3
..... .....

Skapa klasser och definiera sökvägar

Definiera sedan dina indata- och förutsägelseklassdatastrukturer.

Lägg till en ny klass i projektet:

  1. I Solution Explorer högerklickar du på projektet och väljer sedan Lägg till > nytt objekt.

  2. I dialogrutan Lägg till nytt objekt väljer du Klass och ändrar fältet Namn till ProductSalesData.cs. Välj sedan knappen Lägg till .

    Filen ProductSalesData.cs öppnas i kodredigeraren.

  3. Lägg till följande using -instruktion överst i ProductSalesData.cs:

    using Microsoft.ML.Data;
    
  4. Ta bort den befintliga klassdefinitionen och lägg till följande kod, som har två klasser ProductSalesData och ProductSalesPrediction, i filen 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 anger en indataklass. Attributet LoadColumn anger vilka kolumner (efter kolumnindex) i datauppsättningen som ska läsas in.

    ProductSalesPrediction anger förutsägelsedataklassen. För avvikelseidentifiering består förutsägelsen av en avisering som anger om det finns en avvikelse, en råpoäng och ett p-värde. Ju närmare p-värdet är 0, desto troligare är det att en avvikelse har inträffat.

  5. Skapa två globala fält för att lagra sökvägen till den nyligen nedladdade datauppsättningsfilen och den sparade modellfilens sökväg:

    • _dataPath har sökvägen till den datauppsättning som används för att träna modellen.
    • _docsize har antalet poster i datauppsättningsfilen. Du använder _docSize för att beräkna pvalueHistoryLength.
  6. Lägg till följande kod på raden precis under using-instruktionerna för att ange dessa sökvägar:

    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;
    

Initiera variabler

  1. Ersätt raden Console.WriteLine("Hello World!") med följande kod för att deklarera och initiera variabeln mlContext :

    MLContext mlContext = new MLContext();
    

    KLASSEN MLContext är en startpunkt för alla ML.NET åtgärder, och initiering mlContext skapar en ny ML.NET miljö som kan delas mellan arbetsflödesobjekten för modellskapande. Det liknar begreppsmässigt DBContext i Entity Framework.

Läsa in data

Data i ML.NET representeras som ett IDataView-gränssnitt. IDataView är ett flexibelt och effektivt sätt att beskriva tabelldata (numeriska data och text). Data kan läsas in från en textfil eller från andra källor (till exempel SQL-databas eller loggfiler) till ett IDataView objekt.

  1. Lägg till följande kod när du har skapat variabeln mlContext :

    IDataView dataView = mlContext.Data.LoadFromTextFile<ProductSalesData>(path: _dataPath, hasHeader: true, separatorChar: ',');
    

    LoadFromTextFile() definierar dataschemat och läser i filen. Den tar in datasökvägsvariablerna och returnerar en IDataView.

Avvikelseidentifiering för tidsserier

Avvikelseidentifiering flaggar oväntade eller ovanliga händelser eller beteenden. Det ger ledtrådar var du ska leta efter problem och hjälper dig att svara på frågan "Är det här konstigt?".

Exempel på avvikelseidentifieringen

Avvikelseidentifiering är processen att identifiera extremvärden för tidsseriedata. punkter i en viss tidsserie för indata där beteendet inte är vad som förväntades eller "konstigt".

Avvikelseidentifiering kan vara användbart på många olika sätt. Till exempel:

Om du har en bil, kanske du vill veta: Är denna oljemätare läser normalt, eller har jag en läcka? Om du övervakar energiförbrukning vill du veta: Finns det ett avbrott?

Det finns två typer av time series-avvikelser som kan identifieras:

  • Toppar indikerar tillfälliga ökningar av avvikande beteende i systemet.

  • Ändringspunkter anger början på beständiga ändringar över tid i systemet.

I ML.NET passar algoritmerna för IID-toppidentifiering eller IID-ändringspunktsidentifiering för oberoende och identiskt distribuerade datauppsättningar. De förutsätter att dina indata är en sekvens med datapunkter som samplas oberoende av en stationär fördelning.

Till skillnad från modellerna i de andra självstudierna fungerar transformeringar av tidsserieavvikelseidentifiering direkt på indata. Metoden IEstimator.Fit() behöver inte träningsdata för att skapa transformen. Det behöver dock dataschemat, som tillhandahålls av en datavy som genereras från en tom lista med ProductSalesData.

Du analyserar samma produktförsäljningsdata för att identifiera toppar och ändringspunkter. Processen för att skapa och träna modell är densamma för identifiering av toppar och identifiering av ändringspunkter. den största skillnaden är den specifika identifieringsalgoritm som används.

Toppidentifiering

Målet med toppidentifiering är att identifiera plötsliga men tillfälliga toppar som skiljer sig avsevärt från majoriteten av tidsseriedatavärdena. Det är viktigt att identifiera dessa misstänkta sällsynta objekt, händelser eller observationer i tid för att minimeras. Följande metod kan användas för att identifiera en mängd olika avvikelser, till exempel avbrott, cyberattacker eller viralt webbinnehåll. Följande bild är ett exempel på toppar i en tidsseriedatauppsättning:

Skärmbild som visar två toppidentifieringar.

Lägg till metoden CreateEmptyDataView()

Lägg till följande metod i 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);
}

CreateEmptyDataView() skapar ett tomt datavyobjekt med rätt schema som ska användas som indata till IEstimator.Fit() metoden.

Skapa metoden DetectSpike()

Metoden DetectSpike() :

  • Skapar transformen från beräknaren.
  • Identifierar toppar baserat på historiska försäljningsdata.
  • Visar resultatet.
  1. DetectSpike() Skapa metoden längst ned i filen Program.cs med hjälp av följande kod:

    DetectSpike(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. Använd IidSpikeEstimator för att träna modellen för toppidentifiering. Lägg till den i DetectSpike() metoden med följande kod:

    var iidSpikeEstimator = mlContext.Transforms.DetectIidSpike(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, pvalueHistoryLength: docSize / 4);
    
  3. Skapa transformeringen för toppidentifiering genom att lägga till följande som nästa kodrad i DetectSpike() metoden :

    Tips

    Parametrarna confidence och pvalueHistoryLength påverkar hur toppar identifieras. confidence avgör hur känslig din modell är för toppar. Ju lägre konfidens desto mer sannolikt är det att algoritmen identifierar "mindre" toppar. Parametern pvalueHistoryLength definierar antalet datapunkter i ett skjutfönster. Värdet för den här parametern är vanligtvis en procentandel av hela datamängden. Ju lägre pvalueHistoryLengthdesto snabbare glömmer modellen tidigare stora toppar.

    ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
    
  4. Lägg till följande kodrad för att transformera productSales data som nästa rad i DetectSpike() metoden:

    IDataView transformedData = iidSpikeTransform.Transform(productSales);
    

    Den tidigare koden använder metoden Transform() för att göra förutsägelser för flera indatarader i en datauppsättning.

  5. Konvertera din transformedData till ett starkt skrivet IEnumerable för enklare visning med hjälp av metoden CreateEnumerable() med följande kod:

    var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
    
  6. Skapa en huvudrad för visning med hjälp av följande Console.WriteLine() kod:

    Console.WriteLine("Alert\tScore\tP-Value");
    

    Du visar följande information i resultatet av toppidentifieringen:

    • Alert anger en toppavisering för en viss datapunkt.
    • Score är värdet ProductSales för en viss datapunkt i datauppsättningen.
    • P-Value "P" står för sannolikhet. Ju närmare p-värdet är 0, desto troligare är datapunkten en avvikelse.
  7. Använd följande kod för att iterera genom predictionsIEnumerable och visa resultatet:

    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. Lägg till anropet DetectSpike() till metoden under anropet LoadFromTextFile() till metoden :

    DetectSpike(mlContext, _docsize, dataView);
    

Resultat av toppidentifiering

Resultatet bör se ut ungefär så här. Under bearbetningen visas meddelanden. Du kan se varningar eller bearbeta meddelanden. Några av meddelandena har tagits bort från följande resultat för tydlighetens skull.

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

Identifiering av ändringspunkt

Change points är beständiga ändringar i en tidsseriehändelseströmdistribution av värden, till exempel nivåändringar och trender. Dessa beständiga ändringar varar mycket längre än spikes och kan tyda på oåterkalleliga händelser. Change points är vanligtvis inte synliga för blotta ögat, men kan identifieras i dina data med hjälp av metoder som i följande metod. Följande bild är ett exempel på en identifiering av ändringspunkter:

Skärmbild som visar en identifiering av ändringspunkt.

Skapa metoden DetectChangepoint()

Metoden DetectChangepoint() kör följande uppgifter:

  • Skapar transformen från beräknaren.
  • Identifierar ändringspunkter baserat på historiska försäljningsdata.
  • Visar resultatet.
  1. DetectChangepoint() Skapa metoden, precis efter metoddeklarationenDetectSpike(), med hjälp av följande kod:

    void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. Skapa iidChangePointEstimator i DetectChangepoint() metoden med följande kod:

    var iidChangePointEstimator = mlContext.Transforms.DetectIidChangePoint(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, changeHistoryLength: docSize / 4);
    
  3. Som du gjorde tidigare skapar du transformen från beräkningsobjektet genom att lägga till följande kodrad i DetectChangePoint() metoden :

    Tips

    Identifieringen av ändringspunkter sker med en liten fördröjning eftersom modellen måste se till att den aktuella avvikelsen är en beständig ändring och inte bara några slumpmässiga toppar innan en avisering skapas. Den här fördröjningen är lika med parametern changeHistoryLength . Genom att öka värdet för den här parametern aviserar ändringsidentifiering vid mer beständiga ändringar, men kompromissen skulle vara en längre fördröjning.

    var iidChangePointTransform = iidChangePointEstimator.Fit(CreateEmptyDataView(mlContext));
    
  4. Transform() Använd metoden för att transformera data genom att lägga till följande kod i DetectChangePoint():

    IDataView transformedData = iidChangePointTransform.Transform(productSales);
    
  5. Precis som tidigare konverterar du transformedData till en starkt typad IEnumerable för enklare visning med hjälp av CreateEnumerable()metoden med följande kod:

    var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
    
  6. Skapa ett visningshuvud med följande kod som nästa rad i DetectChangePoint() metoden :

    Console.WriteLine("Alert\tScore\tP-Value\tMartingale value");
    

    Du visar följande information i dina resultat för identifiering av ändringspunkter:

    • Alert anger en ändringspunktsavisering för en viss datapunkt.
    • Score är värdet ProductSales för en viss datapunkt i datauppsättningen.
    • P-Value "P" står för sannolikhet. Ju närmare P-värdet är 0, desto troligare är datapunkten en avvikelse.
    • Martingale value används för att identifiera hur "konstig" en datapunkt är, baserat på sekvensen med P-värden.
  7. Iterera genom predictionsIEnumerable och visa resultatet med följande kod:

    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. Lägg till följande anrop till DetectChangepoint()metoden efter anropet DetectSpike() till metoden :

    DetectChangepoint(mlContext, _docsize, dataView);
    

Resultat av ändringspunktsidentifiering

Resultatet bör se ut ungefär så här. Under bearbetningen visas meddelanden. Du kan se varningar eller bearbeta meddelanden. Vissa meddelanden har tagits bort från följande resultat för tydlighetens skull.

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

Grattis! Nu har du skapat maskininlärningsmodeller för att identifiera toppar och avvikelser i försäljningspunkter.

Du hittar källkoden för den här självstudien på lagringsplatsen dotnet/samples .

I den här självstudiekursen lärde du dig att:

  • Läsa in data
  • Träna modellen för toppavvikelseidentifiering
  • Identifiera toppavvikelser med den tränade modellen
  • Träna modellen för avvikelseidentifiering för ändringspunkt
  • Identifiera avvikelser i ändringspunkter med tränat läge

Nästa steg

Titta på GitHub-lagringsplatsen machine learning-exempel för att utforska ett exempel på avvikelseidentifiering av säsongsdata.