Tutorial: Erkennen von Anomalien in Produktverkäufen mit ML.NET
Erfahren Sie, wie Sie eine Anwendung zur Anomalieerkennung bei Produktvertriebsdaten erstellen. Dieses Tutorial erstellt mithilfe von C# in Visual Studio eine .NET Core-Konsolenanwendung.
In diesem Tutorial lernen Sie, wie die folgenden Aufgaben ausgeführt werden:
- Laden der Daten
- Erstellen einer Transformation zur Erkennung von Anomaliespitzen
- Erkennen von Anomaliespitzen mit der Transformation
- Erstellen einer Transformation für die Anomalieerkennung bei Änderungspunkten
- Erkennen von Änderungspunktanomalien mit der Transformation
Sie finden den Quellcode für dieses Tutorial im Repository dotnet/samples.
Voraussetzungen
Visual Studio 2022 mit installierter Workload „.NET-Desktopentwicklung“.
Hinweis
Das Datenformat in product-sales.csv
basiert auf dem Dataset „Shampoo Sales Over a Three Year Period“ von Rob Hyndman, ursprünglich aus dem DataMarket und von der Time Series Data Library (TSDL) bereitgestellt.
Das Dataset „Shampoo Sales Over a Three Year Period“ ist im Rahmen der DataMarket Default Open License lizenziert.
Erstellen einer Konsolenanwendung
Erstellen Sie eine C#-Konsolenanwendung mit namens „ProductSalesAnomalyDetection“. Klicken Sie auf die Schaltfläche Weiter.
Wählen Sie .NET 6 als zu verwendendes Framework aus. Klicken Sie auf die Schaltfläche Erstellen .
Erstellen Sie ein Verzeichnis mit dem Namen Data in Ihrem Projekt, um die Datasetdateien zu speichern.
Installieren des Microsoft.ML NuGet-Pakets:
Hinweis
In diesem Beispiel wird, sofern nicht anders angegeben, die neueste stabile Version der genannten NuGet-Pakete verwendet.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie NuGet-Pakete verwalten aus. Wählen Sie als Paketquelle „nuget.org“ aus. Klicken Sie dann auf die Registerkarte „Durchsuchen“ aus, suchen Sie nach Microsoft.ML, und klicken Sie anschließend auf Installieren. Wählen Sie die Schaltfläche OK im Dialogfeld Vorschau der Änderungen und dann die Schaltfläche Ich stimme zu im Dialogfeld Zustimmung zur Lizenz aus, wenn Sie den Lizenzbedingungen für die aufgelisteten Pakete zustimmen. Wiederholen Sie diese Schritte für Microsoft.ML.TimeSeries.
Fügen Sie am Anfang der Datei Program.cs die folgenden
using
-Anweisungen hinzu:using Microsoft.ML; using ProductSalesAnomalyDetection;
Herunterladen der Daten
Laden Sie die das Dataset herunter, und speichern Sie es im Ordner Data, den Sie vorher erstellt haben:
Klicken Sie mit der rechten Maustaste auf product-sales.csv und anschließend auf „Link speichern unter“ oder „Ziel speichern unter“.
Achten Sie darauf, die CSV-Datei entweder im Ordner Data zu speichern oder sie in den Ordner Data zu verschieben, nachdem Sie die CSV-Datei an anderer Stelle gespeichert haben.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die CSV-Datei, und wählen Sie Eigenschaften aus. Ändern Sie unter Erweitert den Wert von In Ausgabeverzeichnis kopieren in Kopieren, wenn neuer.
Die folgende Tabelle enthält eine Datenvorschau aus Ihrer CSV-Datei:
Monat | ProductSales |
---|---|
1-Jan | 271 |
2-Jan | 150,9 |
..... | ..... |
1-Feb | 199,3 |
..... | ..... |
Erstellen von Klassen und Definieren von Pfaden
Als Nächstes definieren Sie Ihre Datenstruktur der Eingabe- und Vorhersageklasse.
Fügen Sie dem Projekt eine neue Klasse hinzu:
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und klicken Sie auf Hinzufügen > Neues Element.
Wählen Sie im Dialogfeld Neues Element hinzufügen die Option Klasse aus, und ändern Sie das Feld Name inProductSalesData.cs. Wählen Sie dann die Schaltfläche Hinzufügen aus.
Die Datei ProductSalesData.cs wird im Code-Editor geöffnet.
Fügen Sie die folgende
using
-Anweisung am Anfang der ProductSalesData.cs-Datei hinzu:using Microsoft.ML.Data;
Entfernen Sie die vorhandene Klassendefinition, und fügen Sie der Datei ProductSalesData.cs den folgenden Code mit den beiden Klassen
ProductSalesData
undProductSalesPrediction
hinzu: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
ist eine Klasse für Eingabedaten. Das LoadColumn-Attribut legt fest, welche Spalten (durch Angabe des Spaltenindex) im Dataset geladen werden sollen.ProductSalesPrediction
gibt die Vorhersagedatenklasse an. Zur Anomalieerkennung besteht die Vorhersage aus einer Warnung, die angibt, ob eine Anomalie, eine Rohbewertung und ein Signifikanzwert (p-value; P-Wert) vorhanden sind. Je näher der Signifikanzwert an 0 ist, desto größer ist die Wahrscheinlichkeit einer Anomalie.Erstellen Sie zwei globale Felder zum Speichern des gerade heruntergeladenen Datasetdateipfads und des gespeicherten Modelldateipfads:
_dataPath
enthält den Pfad zu dem Dataset, das zum Trainieren des Modells verwendet wird._docsize
enthält die Anzahl der Datensätze in der Datendatei. Sie verwenden_docSize
zum Berechnen vonpvalueHistoryLength
.
Fügen Sie der Zeile direkt unter den using-Anweisungen den folgenden Code hinzu, um diese Pfade anzugeben:
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;
Initialisieren der Variablen
Ersetzen Sie die Zeile
Console.WriteLine("Hello World!")
durch den folgenden Code, um diemlContext
-Variable zu deklarieren und zu initialisieren:MLContext mlContext = new MLContext();
Die MLContext-Klasse ist der Startpunkt für alle ML.NET-Vorgänge. Durch das Initialisieren von
mlContext
wird eine neue ML.NET-Umgebung erstellt, die für mehrere Objekte des Modellerstellungsworkflows verwendet werden kann. Die Klasse ähnelt dem Konzept vonDBContext
in Entity Framework.
Laden der Daten
Daten im ML.NET werden angezeigt als ein IDataView interface. Mit IDataView
können Tabellendaten (Zahlen und Text) flexibel und effizient beschrieben werden. Daten können aus einer Textdatei oder aus anderen Ressourcen (z. B. aus einer SQL-Datenbank oder aus Protokolldateien) in ein IDataView
-Objekt geladen werden.
Fügen Sie nach dem Erstellen der
mlContext
-Variablen den folgenden Code hinzu:IDataView dataView = mlContext.Data.LoadFromTextFile<ProductSalesData>(path: _dataPath, hasHeader: true, separatorChar: ',');
Die LoadFromTextFile()-Methode definiert das Datenschema und liest die Datei ein. Diese Methode akzeptiert Datenpfadvariablen und gibt ein
IDataView
-Objekt zurück.
Anomalieerkennung in Zeitreihen
Die Anomalieerkennung zeigt unerwartete oder ungewöhnliche Ereignisse oder Verhaltensweisen an. Sie erhalten Hinweise darauf, wo Sie nach Problemen schauen müssen, und können die Frage beantworten, ob das Ereignis oder Verhalten ungewöhnlich ist.
Die Anomalieerkennung ist ein Prozess, bei dem Ausreißer in Zeitreihendaten ermittelt. Damit wird auf Eingabezeitreihen hingewiesen, bei denen nicht das erwartete oder ein ungewöhnliches Verhalten aufgetreten ist.
Die Anomalieerkennung kann auf viele Weisen nützlich sein. Zum Beispiel:
Wenn Sie ein Auto besitzen, möchten Sie vielleicht wissen: Ist diese Ölstandsanzeige normal oder habe ich ein Leck? Wenn Sie den Energieverbrauch überwachen, möchten Sie vielleicht wissen: Gibt es einen Stromausfall?
Es können zwei Arten von Zeitreihenanomalien erkannt werden:
Spitzen zeigen temporäre Häufungen von anomalem Verhalten im System an.
Änderungspunkte zeigen den Beginn anhaltender Änderungen im Zeitverlauf im System an.
In ML.NET eignen sich die Algorithmen „IID Spike Detection“ oder „IID Change point Detection“ für unabhängige und identisch verteilte Datasets. Sie gehen davon aus, dass die Eingabedaten eine Sequenz von Datenpunkten sind, die unabhängig von einer stationären Verteilung entnommen werden.
Im Gegensatz zu den Modellen in den anderen Tutorials werden die Transformationen für die Zeitreihenanomalieerkennung direkt auf Eingabedaten angewendet. Die IEstimator.Fit()
-Methode benötigt keine Trainingsdaten, um die Transformation zu entwickeln. Sie benötigt jedoch das Datenschema, das aus einer Datenansicht bereitgestellt wird, die aus einer leeren Liste von ProductSalesData
generiert wird.
Sie analysieren die gleichen Produktvertriebsdaten, um Spitzen und Änderungspunkte zu erkennen. Der Prozess zum Erstellen und Trainieren eines Modells ist für die Erkennung von Spitzen und Änderungspunkten gleich; der Hauptunterschied besteht in dem verwendeten spezifischen Erkennungsalgorithmus.
Spitzenerkennung
Das Ziel der Spitzenerkennung ist es, plötzliche, aber temporäre Häufungen zu identifizieren, die sich signifikant von der Mehrzahl der Zeitreihen-Datenwerte unterscheiden. Es ist wichtig, diese verdächtigen seltenen Elemente, Ereignisse oder Beobachtungen rechtzeitig zu erkennen, um sie zu minimieren. Der folgende Ansatz kann zur Erkennung einer Vielzahl von Anomalien verwendet werden: z.B. Ausfälle, Cyberangriffe oder virale Webinhalte. Das folgende Bild zeigt ein Beispiel für Spitzen in einem Zeitreihen-Dataset:
Hinzufügen der CreateEmptyDataView()-Methode
Fügen Sie Program.cs
zur folgenden Methode hinzu:
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);
}
Die Methode CreateEmptyDataView()
erzeugt ein leeres Datenansichtsobjekt mit dem korrekten Schema, das für die Methode IEstimator.Fit()
als Eingabe verwendet werden soll.
Erstellen der DetectSpike()-Methode
Die DetectSpike()
-Methode:
- erstellt die Transformation aus der Schätzung
- Erkennen von Spitzen basierend auf historischen Vertriebsdaten.
- Anzeigen der Ergebnisse.
Erstellen Sie mithilfe des folgenden Codes unten in der Datei Program.cs eine
DetectSpike()
-Methode:DetectSpike(MLContext mlContext, int docSize, IDataView productSales) { }
Verwenden Sie IidSpikeEstimator, um das Modell zum Erkennen von Spitzen zu trainieren. Fügen Sie ihn mit dem folgenden Code zur
DetectSpike()
-Methode hinzu:var iidSpikeEstimator = mlContext.Transforms.DetectIidSpike(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, pvalueHistoryLength: docSize / 4);
Fügen Sie den unten aufgeführten Code als nächste Codezeile in die
DetectSpike()
-Methode ein, um die Spitzenerkennungstransformation zu erstellen.Tipp
Die
confidence
- undpvalueHistoryLength
-Parameter beeinflussen, wie Spitzen erkannt werden.confidence
bestimmt, wie empfindlich Ihr Modell auf Spitzen reagiert. Je geringer die Konfidenz, desto wahrscheinlicher ist es, dass der Algorithmus „kleinere“ Spitzen erkennt. DerpvalueHistoryLength
-Parameter definiert die Anzahl der Datenpunkte in einem gleitenden Fenster. Der Wert dieses Parameters ist in der Regel ein Prozentsatz des gesamten Datasets. Je niedriger derpvalueHistoryLength
, desto schneller verlernt das Modell vorherige große Spitzen.ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
Fügen Sie die folgende Codezeile hinzu, um die
productSales
-Daten als nächste Zeile in derDetectSpike()
-Methode zu transformieren:IDataView transformedData = iidSpikeTransform.Transform(productSales);
Der vorherige Code verwendet die Transform()-Methode trifft Vorhersagen für mehrere Eingabezeilen eines Datasets.
Konvertieren Sie Ihre
transformedData
mit der CreateEnumerable()-Methode mit dem folgenden Code in ein stark typisiertesIEnumerable
-Element zur einfacheren Anzeige:var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Erstellen Sie mit dem folgenden Console.WriteLine()-Code eine Anzeige für die Kopfzeile:
Console.WriteLine("Alert\tScore\tP-Value");
In den Ergebnissen der Spitzenerkennung werden folgende Informationen angezeigt:
Alert
gibt eine Spitzenwarnung für einen bestimmten Datenpunkt an.Score
ist derProductSales
-Wert für einen bestimmten Datenpunkt im Dataset.P-Value
Das „P“ steht für „Probability“ (Wahrscheinlichkeit). Je näher der Signifikanzwert an 0 ist, desto größer ist die Wahrscheinlichkeit, dass der Datenpunkt eine Anomalie darstellt.
Verwenden Sie den folgenden Code, um
predictions
IEnumerable
zu durchlaufen und die Ergebnisse anzuzeigen: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("");
Fügen Sie den Aufruf der
DetectSpike()
-Methode unter dem Aufruf derLoadFromTextFile()
-Methode hinzu:DetectSpike(mlContext, _docsize, dataView);
Ergebnisse der Spitzenerkennung
Die Ergebnisse sollten den unten dargestellten ähneln. Während der Verarbeitung werden Meldungen angezeigt. Sie können Warnungen oder Verarbeitungsmeldungen sehen. Einige dieser Nachrichten wurden der Übersichtlichkeit halber aus den folgenden Ergebnissen entfernt.
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
Erkennen von Änderungspunkten
Change points
sind anhaltende Änderungen in der Verteilung der Werte in einem Zeitreihen-Ereignisstrom, wie Niveauänderungen und Trends. Diese anhaltenden Änderungen dauern wesentlich länger als spikes
und könnten auf katastrophale Ereignisse hinweisen. Change points
sind in der Regel nicht mit bloßem Auge erkennbar, können aber mit Ansätzen wie beispielsweise der folgenden Methode in Ihren Daten festgestellt werden. Das folgende Bild ist ein Beispiel für eine Änderungspunkterkennung:
Erstellen der DetectChangepoint()-Methode
Die DetectChangepoint()
-Methode führt die folgenden Aufgaben aus:
- erstellt die Transformation aus der Schätzung
- Erkennen von Änderungspunkten basierend auf historischen Vertriebsdaten.
- Anzeigen der Ergebnisse.
Erstellen Sie die
DetectChangepoint()
-Methode mit dem folgenden Code direkt nach der Deklaration derDetectSpike()
-Methode:void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales) { }
Erstellen Sie den iidChangePointEstimator in der
DetectChangepoint()
-Methode mit folgendem Code:var iidChangePointEstimator = mlContext.Transforms.DetectIidChangePoint(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, changeHistoryLength: docSize / 4);
Erstellen Sie wie zuvor die Transformation aus der Schätzung, indem Sie die folgende Codezeile in der
DetectChangePoint()
-Methode hinzufügen.Tipp
Die Erkennung von Änderungspunkten erfolgt mit einer geringfügigen Verzögerung, da das Modell sicherstellen muss, dass die aktuelle Abweichung eine dauerhafte Änderung darstellt und nicht nur einige zufällige Spitzen, bevor eine Warnung erstellt wird. Der Länge dieser Verzögerung entspricht dem
changeHistoryLength
-Parameter. Wenn Sie den Wert dieses Parameters erhöhen, warnt die Änderungserkennung bei beständigeren Änderungen, doch dafür wäre die Verzögerung länger.var iidChangePointTransform = iidChangePointEstimator.Fit(CreateEmptyDataView(mlContext));
Verwenden Sie die
Transform()
-Methode, um die Daten zu transformieren, indem Sie den folgenden Code zuDetectChangePoint()
hinzufügen:IDataView transformedData = iidChangePointTransform.Transform(productSales);
Konvertieren Sie wie bereits zuvor Ihre
transformedData
mit derCreateEnumerable()
-Methode mit dem folgenden Code in ein stark typisiertesIEnumerable
-Element zur einfacheren Anzeige:var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Erstellen Sie mit dem folgenden Code als nächste Zeile in der
DetectChangePoint()
-Methode einen Anzeigeheader:Console.WriteLine("Alert\tScore\tP-Value\tMartingale value");
In den Ergebnissen der Änderungspunkterkennung werden folgende Informationen angezeigt:
Alert
gibt eine Änderungspunktwarnung für einen bestimmten Datenpunkt an.Score
ist derProductSales
-Wert für einen bestimmten Datenpunkt im Dataset.P-Value
Das „P“ steht für „Probability“ (Wahrscheinlichkeit). Je näher der Signifikanzwert an 0 ist, desto größer ist die Wahrscheinlichkeit, dass der Datenpunkt eine Anomalie darstellt.Martingale value
wird verwendet, um basierend auf der Reihenfolge der P-Werte zu bestimmen, wie „ungewöhnlich ein Datenpunkt ist.
Mit dem folgenden Code können Sie
predictions
IEnumerable
durchlaufen und die Ergebnisse anzeigen: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("");
Fügen Sie den folgenden Aufruf der
DetectChangepoint()
-Methode nach Aufruf derDetectSpike()
-Methode hinzu:DetectChangepoint(mlContext, _docsize, dataView);
Ergebnisse der Änderungspunkterkennung
Die Ergebnisse sollten den unten dargestellten ähneln. Während der Verarbeitung werden Meldungen angezeigt. Sie können Warnungen oder Verarbeitungsmeldungen sehen. Einige der Nachrichten wurden der Übersichtlichkeit halber aus den folgenden Ergebnissen entfernt.
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
Herzlichen Glückwunsch! Sie haben jetzt erfolgreich Machine Learning-Modelle zur Erkennung von Spitzen und Änderungspunktanomalien in Vertriebsdaten erstellt.
Sie finden den Quellcode für dieses Tutorial im Repository dotnet/samples.
In diesem Tutorial haben Sie gelernt, wie die folgenden Aufgaben ausgeführt werden:
- Laden der Daten
- Trainieren des Modells zur Erkennung von Anomaliespitzen
- Erkennen von Anomaliespitzen mit dem trainierten Modell
- Trainieren des Modells zur Erkennung einer Änderungspunktanomalie
- Erkennen von Änderungspunktanomalien mit dem trainierten Modell
Nächste Schritte
Durchsuchen Sie das GitHub-Repository für Machine Learning-Beispiele nach einem Beispiel für die Anomalieerkennung bei Saisondaten, damit Sie dieses untersuchen können.