Esercitazione: Rilevare le anomalie nelle vendite di prodotti con ML.NET
Informazioni su come creare un'applicazione di rilevamento anomalie per i dati di vendita dei prodotti. Questa esercitazione crea un'applicazione console .NET usando C# in Visual Studio.
In questa esercitazione si apprenderà come:
- Carica i dati
- Creare una trasformazione per il rilevamento delle anomalie di picco
- Rilevare le anomalie nei picchi con il transform
- Creare una trasformazione per il rilevamento delle anomalie nei punti di cambiamento
- Rilevare le anomalie nei punti di cambiamento attraverso la trasformazione
Puoi trovare il codice sorgente per questa esercitazione nel repository dotnet/samples.
Prerequisiti
Visual Studio 2022 con il workload ".NET Desktop Development" installato.
Nota
Il formato dei dati in product-sales.csv
si basa sul set di dati "Shampoo Sales Over a Three Year Period" originariamente originato da DataMarket e fornito da Time Series Data Library (TSDL), creato da Rob Hyndman.
Set di dati "Vendite di Shampoo in un Periodo di Tre Anni" concesso in licenza con Licenza Aperta Predefinita di DataMarket.
Creare un'applicazione console
Crea un'applicazione console C# denominata "ProductSalesAnomalyDetection". Fare clic sul pulsante Avanti.
Scegliere .NET 8 come framework da usare. Fare clic sul pulsante Crea.
Creare una directory denominata Data nel progetto per salvare i file del set di dati.
Installare il pacchetto NuGet Microsoft.ML:
Nota
In questo esempio viene usata la versione stabile più recente dei pacchetti NuGet menzionati, a meno che non diversamente specificato.
In Esplora soluzioni, fare clic con il pulsante destro del mouse sul progetto e selezionare Gestisci pacchetti NuGet. Impostare "nuget.org" come origine del pacchetto, selezionare la scheda Sfoglia, cercare Microsoft.ML e selezionare Installa. Selezionare il pulsante OK nella finestra di dialogo Anteprima modifiche e quindi selezionare il pulsante Accetto nella finestra di dialogo accettazione della licenza se si accettano le condizioni di licenza per i pacchetti elencati. Ripeta questi passaggi per Microsoft.ML.TimeSeries.
Aggiungete le direttive
using
seguenti all'inizio del file Program.cs:using Microsoft.ML; using ProductSalesAnomalyDetection;
Scarica i tuoi dati
Scaricare il set di dati e salvarlo nella cartella
dati creata in precedenza: Fare clic con il pulsante destro del mouse su product-sales.csv e selezionare "Salva collegamento (o Destinazione) con nome..."
Assicurarsi di salvare il file *.csv nella cartella data
oppure dopo averlo salvato altrove, spostare il file *.csv nella cartella Data .
In Esplora soluzioni fare clic con il pulsante destro del mouse sul file *.csv e selezionare Proprietà. In Avanzate, cambia l'opzione di Copia nella directory di output in Copia se più recente.
La tabella seguente è un'anteprima dei dati dal file *.csv:
Mese | ProductSales |
---|---|
1 gennaio | 271 |
2 gennaio | 150.9 |
..... | ..... |
1 febbraio | 199.3 |
..... | ..... |
Creare classi e definire percorsi
Definire quindi le strutture di dati della classe di input e stima.
Aggiungere una nuova classe al progetto:
Nell'Esplora Soluzioni , fare clic con il pulsante destro del mouse sul progetto e quindi selezionare Aggiungi > Nuovo elemento.
Nella finestra di dialogo Aggiungi nuovo elemento, selezionare Class e modificare il campo Nome in ProductSalesData.cs. Selezionare quindi Aggiungi.
Il file ProductSalesData.cs viene aperto nell'editor di codice.
Aggiungere la direttiva
using
seguente all'inizio di ProductSalesData.cs:using Microsoft.ML.Data;
Rimuovere la definizione di classe esistente e aggiungere il codice seguente, che include due classi
ProductSalesData
eProductSalesPrediction
, al file 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
specifica una classe di dati di input. L'attributo LoadColumn specifica le colonne (in base all'indice di colonna) nel set di dati da caricare.ProductSalesPrediction
specifica la classe di dati di stima. Per il rilevamento anomalie, la stima è costituita da un avviso per indicare se è presente un'anomalia, un punteggio non elaborato e un valore p. Più il valore p è più vicino a 0, maggiore è la probabilità che si sia verificata un'anomalia.Creare due campi globali per contenere il percorso del file del set di dati scaricato di recente e il percorso del file del modello salvato:
-
_dataPath
ha il percorso del set di dati usato per addestrare il modello. -
_docsize
ha il numero di record nel file del set di dati. Userai_docSize
per calcolarepvalueHistoryLength
.
-
Aggiungere il codice seguente alla riga immediatamente sotto le direttive
using
per specificare tali percorsi: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;
Inizializzare le variabili
Sostituire la riga
Console.WriteLine("Hello World!")
con il codice seguente per dichiarare e inizializzare la variabilemlContext
:MLContext mlContext = new MLContext();
La classe MLContext è un punto di partenza per tutte le operazioni di ML.NET e l'inizializzazione di
mlContext
crea un nuovo ambiente ML.NET che può essere condiviso tra gli oggetti flusso di lavoro di creazione del modello. È simile, concettualmente, aDBContext
in Entity Framework.
Carica i dati
I dati in ML.NET sono rappresentati come interfaccia IDataView .
IDataView
è un modo flessibile ed efficiente di descrivere i dati tabulari (numerici e di testo). I dati possono essere caricati da un file di testo o da altre origini ,ad esempio da un database SQL o da file di log, a un oggetto IDataView
.
Aggiungere il codice seguente dopo aver creato la variabile
mlContext
:IDataView dataView = mlContext.Data.LoadFromTextFile<ProductSalesData>(path: _dataPath, hasHeader: true, separatorChar: ',');
Il LoadFromTextFile() definisce lo schema dei dati e legge il file. Accetta le variabili del percorso dei dati e restituisce un
IDataView
.
Rilevamento anomalie delle serie temporali
Il rilevamento anomalie contrassegna eventi o comportamenti imprevisti o insoliti. Fornisce indizi su dove cercare i problemi e ti aiuta a rispondere alla domanda "È strano?".
Il rilevamento delle anomalie è il processo di individuazione degli outlier nei dati delle serie temporali; punti su una serie temporale di input specificata dove il comportamento non è quello atteso o risulta "strano".
Il rilevamento anomalie può essere utile in molti modi. Per esempio:
Se hai un'auto, potresti voler sapere: è normale la lettura del misuratore dell'olio o ho una perdita? Se si monitora il consumo energetico, si vuole sapere: Si verifica un'interruzione?
È possibile rilevare due tipi di anomalie delle serie temporali:
picchi indicano picchi temporanei di comportamento anomalo nel sistema.
Punti di modifica indicano l'inizio delle modifiche persistenti nel sistema nel corso del tempo.
In ML.NET, gli algoritmi IID Spike Detection o IID Change Point Detection sono adatti per set di dati indipendenti e distribuiti in modo identico. Presuppongono che i dati di input siano una sequenza di punti dati campionati in modo indipendente da una distribuzione fissa.
A differenza dei modelli nelle altre esercitazioni, le trasformazioni di rilevamento delle anomalie delle serie temporali operano direttamente sui dati di input. Il metodo IEstimator.Fit()
non richiede dati di training per produrre la trasformazione. È tuttavia necessario lo schema dei dati, il quale è fornito da una visualizzazione dei dati generata da un elenco vuoto di ProductSalesData
.
Verranno analizzati gli stessi dati sulle vendite dei prodotti per rilevare picchi e punti di modifica. Il processo di compilazione e training del modello è lo stesso per il rilevamento dei picchi e il rilevamento dei punti di modifica; la differenza principale è l'algoritmo di rilevamento specifico usato.
Rilevamento dei picchi
L'obiettivo del rilevamento dei picchi è identificare picchi improvvisi ma temporanei che differiscono significativamente dalla maggior parte dei valori dei dati delle serie temporali. È importante rilevare tempestivamente questi elementi rari, eventi o osservazioni sospetti per ridurli al minimo. L'approccio seguente può essere usato per rilevare diverse anomalie, ad esempio interruzioni, attacchi informatici o contenuti Web virali. L'immagine seguente è un esempio di picchi in un set di dati time series:
Aggiungere il metodo CreateEmptyDataView()
Aggiungere il metodo seguente a 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);
}
Il CreateEmptyDataView()
produce un oggetto visualizzazione dati vuoto con lo schema corretto da utilizzare come input per il metodo IEstimator.Fit()
.
Creare il metodo DetectSpike()
Metodo DetectSpike()
:
- Crea la trasformazione dall' *estimator*.
- Rileva i picchi in base ai dati cronologici sulle vendite.
- Visualizza i risultati.
Creare il metodo
DetectSpike()
nella parte inferiore del file Program.cs usando il codice seguente:DetectSpike(MLContext mlContext, int docSize, IDataView productSales) { }
Usare il IidSpikeEstimator per addestrare il modello per il rilevamento dei picchi. Aggiungerlo al metodo
DetectSpike()
con il codice seguente:var iidSpikeEstimator = mlContext.Transforms.DetectIidSpike(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, pvalueHistoryLength: docSize / 4);
Creare la trasformazione per il rilevamento dei picchi aggiungendo il codice seguente come nuova riga di codice nel metodo
DetectSpike()
:Suggerimento
I parametri
confidence
epvalueHistoryLength
influiscono sulla modalità di rilevamento dei picchi.confidence
determina la sensibilità del modello ai picchi. Minore è la fiducia, più è probabile che l'algoritmo rilevi picchi "più piccoli". Il parametropvalueHistoryLength
definisce il numero di punti dati in una finestra scorrevole. Il valore di questo parametro è in genere una percentuale dell'intero set di dati. Più è basso ilpvalueHistoryLength
, più velocemente il modello dimentica i picchi di grandi dimensioni precedenti.ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
Aggiungere la riga di codice seguente per trasformare i dati
productSales
come riga successiva nel metodoDetectSpike()
:IDataView transformedData = iidSpikeTransform.Transform(productSales);
Il codice precedente usa il metodo transform()
per eseguire stime per più righe di input di un set di dati. Converti il
transformedData
in unIEnumerable
fortemente tipizzato per facilitare la visualizzazione utilizzando il metodo CreateEnumerable() con il seguente codice:var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Creare una riga di intestazione di visualizzazione usando il codice Console.WriteLine() seguente:
Console.WriteLine("Alert\tScore\tP-Value");
Nei risultati del rilevamento dei picchi verranno visualizzate le informazioni seguenti:
-
Alert
indica un avviso di picco per un determinato punto dati. -
Score
è il valoreProductSales
per un determinato punto di dati nell'insieme di dati. -
P-Value
"P" indica la probabilità. Più il valore p è più vicino a 0, maggiore è la probabilità che il punto dati sia un'anomalia.
-
Usate il codice seguente per scorrere il
predictions
IEnumerable
e mostrare i risultati: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("");
Aggiungi la chiamata al metodo
DetectSpike()
sotto la chiamata al metodoLoadFromTextFile()
.DetectSpike(mlContext, _docsize, dataView);
Risultati del rilevamento dei picchi
I risultati dovrebbero essere simili ai seguenti. Durante l'elaborazione, vengono visualizzati i messaggi. Puoi vedere avvisi o messaggi di elaborazione. Alcuni dei messaggi sono stati rimossi dai risultati seguenti per maggiore chiarezza.
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
Rilevamento dei punti di cambiamento
Change points
sono modifiche persistenti in una distribuzione del flusso di eventi di serie temporali di valori, ad esempio cambiamenti di livello e tendenze. Queste modifiche persistenti durano molto più a lungo di spikes
e potrebbero indicare eventi irreversibili.
Change points
non sono in genere visibili a occhio nudo, ma possono essere rilevati nei dati usando approcci come nel metodo seguente. L'immagine seguente è un esempio di rilevamento dei punti di modifica:
Creare il metodo DetectChangepoint()
Il metodo DetectChangepoint()
esegue le attività seguenti:
- Crea la trasformata dall'estimatore.
- Rileva i punti di modifica in base ai dati cronologici delle vendite.
- Visualizza i risultati.
Creare il metodo
DetectChangepoint()
, subito dopo la dichiarazione del metodoDetectSpike()
, usando il codice seguente:void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales) { }
Creare il iidChangePointEstimator nel metodo
DetectChangepoint()
con il codice seguente:var iidChangePointEstimator = mlContext.Transforms.DetectIidChangePoint(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, changeHistoryLength: docSize / 4);
Come in precedenza, creare la trasformazione dallo strumento di stima aggiungendo la riga di codice seguente nel metodo
DetectChangePoint()
:Suggerimento
Il rilevamento dei punti di modifica si verifica con un lieve ritardo perché il modello deve assicurarsi che la deviazione corrente sia una modifica persistente e non solo alcuni picchi casuali prima di creare un avviso. La quantità di questo ritardo è uguale al parametro
changeHistoryLength
. Aumentando il valore di questo parametro, gli avvisi di rilevamento delle modifiche riguardano cambiamenti più persistenti, ma a scapito di un ritardo più lungo.var iidChangePointTransform = iidChangePointEstimator.Fit(CreateEmptyDataView(mlContext));
Usare il metodo
Transform()
per trasformare i dati aggiungendo il codice seguente aDetectChangePoint()
:IDataView transformedData = iidChangePointTransform.Transform(productSales);
Come fatto in precedenza, converte il
transformedData
in unIEnumerable
fortemente tipizzato per facilitare la visualizzazione usando il metodoCreateEnumerable()
con il codice seguente.var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Creare un'intestazione di visualizzazione con il codice seguente come riga successiva nel metodo
DetectChangePoint()
:Console.WriteLine("Alert\tScore\tP-Value\tMartingale value");
Nei risultati del rilevamento dei punti di modifica verranno visualizzate le informazioni seguenti:
-
Alert
indica un avviso di punto di cambiamento per un punto dati specifico. -
Score
è il valoreProductSales
per un determinato punto dati nel dataset. -
P-Value
"P" indica la probabilità. Più il valore P è più vicino a 0, maggiore è la probabilità che il punto dati sia un'anomalia. -
Martingale value
viene usato per identificare quanto "strano" sia un punto dati, in base alla sequenza di valori di P.
-
Scorrere il
predictions
IEnumerable
e visualizzare i risultati con il codice seguente: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("");
Aggiungere la chiamata seguente al metodo
DetectChangepoint()
dopo la chiamata al metodoDetectSpike()
:DetectChangepoint(mlContext, _docsize, dataView);
Risultati del rilevamento dei punti di modifica
I risultati dovrebbero essere simili ai seguenti. Durante l'elaborazione, vengono visualizzati i messaggi. Potresti vedere avvisi o messaggi di elaborazione. Alcuni messaggi sono stati rimossi dai risultati seguenti per maggiore chiarezza.
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
Felicitazioni! Hai ora costruito con successo modelli di apprendimento automatico per rilevare picchi e anomalie dei punti di cambiamento nei dati di vendita.
È possibile trovare il codice sorgente di questo tutorial nel repository dotnet/samples .
In questa esercitazione si è appreso come:
- Carica i dati
- Allenare il modello per il rilevamento delle anomalie di picco
- Rilevare le anomalie dei picchi con il modello sottoposto a training
- Eseguire il training del modello per il rilevamento delle anomalie nei punti di cambiamento
- Rilevare le anomalie dei punti di cambiamento con la modalità addestrata
Passaggi successivi
Consulta il repository GitHub degli esempi di apprendimento automatico per esplorare un esempio di rilevamento delle anomalie nei dati stagionali.