Samouczek: wykrywanie anomalii w sprzedaży produktów za pomocą ML.NET
Dowiedz się, jak utworzyć aplikację wykrywania anomalii dla danych sprzedaży produktów. Ten samouczek tworzy aplikację konsolową platformy .NET Core przy użyciu języka C# w programie Visual Studio.
Ten samouczek zawiera informacje na temat wykonywania następujących czynności:
- Ładowanie danych
- Tworzenie przekształcenia na potrzeby wykrywania anomalii skoku
- Wykrywanie anomalii skoków za pomocą przekształcenia
- Tworzenie przekształcenia na potrzeby wykrywania anomalii w punkcie zmian
- Wykrywanie anomalii punktów zmian za pomocą przekształcenia
Kod źródłowy tego samouczka można znaleźć w repozytorium dotnet/samples .
Wymagania wstępne
Program Visual Studio 2022 z zainstalowanym obciążeniem ".NET Desktop Development".
Uwaga
Format danych w programie product-sales.csv
jest oparty na zestawie danych "Shampoo Sales Over a Three Year Period" pierwotnie pochodzącego z dataMarket i dostarczonego przez bibliotekę danych szeregów czasowych (TSDL), utworzoną przez Roba Hyndmana.
Zestaw danych "Shampoo Sales Over a Three Year Period" (Sprzedaż szamponu w ciągu trzech lat) licencjonowany w ramach domyślnej licencji Open License firmy DataMarket.
Tworzenie aplikacji konsolowej
Utwórz aplikację konsolową języka C# o nazwie "ProductSalesAnomalyDetection". Kliknij przycisk Dalej.
Wybierz platformę .NET 6 jako platformę do użycia. Kliknij przycisk Utwórz.
Utwórz katalog o nazwie Dane w projekcie, aby zapisać pliki zestawu danych.
Zainstaluj pakiet NuGet Microsoft.ML:
Uwaga
W tym przykładzie użyto najnowszej stabilnej wersji pakietów NuGet wymienionych, chyba że określono inaczej.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz polecenie Zarządzaj pakietami NuGet. Wybierz pozycję "nuget.org" jako źródło pakietu, wybierz kartę Przeglądaj, wyszukaj Microsoft.ML i wybierz przycisk Zainstaluj . Wybierz przycisk OK w oknie dialogowym Podgląd zmian , a następnie wybierz przycisk Akceptuję w oknie dialogowym Akceptacja licencji , jeśli zgadzasz się z postanowieniami licencyjnymi dla wymienionych pakietów. Powtórz te kroki dla zestawów Microsoft.ML.TimeSeries.
Dodaj następujące
using
instrukcje w górnej części pliku Program.cs :using Microsoft.ML; using ProductSalesAnomalyDetection;
Pobierz swoje dane
Pobierz zestaw danych i zapisz go w utworzonym wcześniej folderze Data :
Kliknij prawym przyciskiem myszy product-sales.csv i wybierz pozycję "Zapisz link (lub element docelowy) jako..."
Upewnij się, że zapiszesz plik *.csv w folderze Dane lub po zapisaniu go w innym miejscu przenieś plik *.csv do folderu Dane .
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy plik *.csv i wybierz polecenie Właściwości. W obszarze Zaawansowane zmień wartość opcji Kopiuj do katalogu wyjściowego , aby skopiować, jeśli jest nowsza.
Poniższa tabela zawiera podgląd danych z pliku *.csv:
Month (Miesiąc) | ProductSales |
---|---|
1–styczeń | 271 |
2 stycznia | 150.9 |
..... | ..... |
1 lutego | 199.3 |
..... | ..... |
Tworzenie klas i definiowanie ścieżek
Następnie zdefiniuj struktury danych klasy wejściowej i przewidywania.
Dodaj nową klasę do projektu:
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt, a następnie wybierz polecenie Dodaj > nowy element.
W oknie dialogowym Dodawanie nowego elementu wybierz pozycję Klasa i zmień pole Nazwa na ProductSalesData.cs. Następnie wybierz przycisk Dodaj .
Plik ProductSalesData.cs zostanie otwarty w edytorze kodu.
Dodaj następującą
using
instrukcję na początku pliku ProductSalesData.cs:using Microsoft.ML.Data;
Usuń istniejącą definicję klasy i dodaj następujący kod, który ma dwie klasy
ProductSalesData
iProductSalesPrediction
, do pliku 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
określa klasę danych wejściowych. Atrybut LoadColumn określa, które kolumny (według indeksu kolumn) w zestawie danych powinny zostać załadowane.ProductSalesPrediction
określa klasę danych przewidywania. W przypadku wykrywania anomalii przewidywanie składa się z alertu wskazującego, czy istnieje anomalia, nieprzetworzona ocena i wartość p. Im bliżej wartość p wynosi 0, tym bardziej prawdopodobne, że wystąpiła anomalia.Utwórz dwa pola globalne do przechowywania ostatnio pobranej ścieżki pliku zestawu danych i zapisanej ścieżki pliku modelu:
_dataPath
zawiera ścieżkę do zestawu danych używanego do trenowania modelu._docsize
zawiera liczbę rekordów w pliku zestawu danych. Użyjesz polecenia_docSize
, aby obliczyć wartośćpvalueHistoryLength
.
Dodaj następujący kod do wiersza bezpośrednio poniżej instrukcji using, aby określić te ścieżki:
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;
Inicjowanie zmiennych
Zastąp
Console.WriteLine("Hello World!")
wiersz następującym kodem, aby zadeklarować i zainicjować zmiennąmlContext
:MLContext mlContext = new MLContext();
Klasa MLContext jest punktem wyjścia dla wszystkich operacji ML.NET, a inicjowanie
mlContext
tworzy nowe środowisko ML.NET, które można udostępnić w obiektach przepływu pracy tworzenia modelu. Jest ona podobna, koncepcyjnie, doDBContext
w programie Entity Framework.
Ładowanie danych
Dane w ML.NET są reprezentowane jako interfejs IDataView. IDataView
jest elastycznym, wydajnym sposobem opisywania danych tabelarycznych (liczbowych i tekstowych). Dane można załadować z pliku tekstowego lub z innych źródeł (na przykład bazy danych SQL lub plików dziennika) do IDataView
obiektu.
Dodaj następujący kod po utworzeniu zmiennej
mlContext
:IDataView dataView = mlContext.Data.LoadFromTextFile<ProductSalesData>(path: _dataPath, hasHeader: true, separatorChar: ',');
Element LoadFromTextFile() definiuje schemat danych i odczytuje go w pliku. Pobiera ona zmienne ścieżki danych i zwraca wartość
IDataView
.
Wykrywanie anomalii szeregów czasowych
Wykrywanie anomalii flaguje nieoczekiwane lub nietypowe zdarzenia lub zachowania. Daje wskazówki, gdzie szukać problemów i pomaga odpowiedzieć na pytanie "Czy to dziwne?".
Wykrywanie anomalii to proces wykrywania odstających danych szeregów czasowych; wskazuje na dany wejściowy szereg czasowy, w którym zachowanie nie jest oczekiwane lub "dziwne".
Wykrywanie anomalii może być przydatne na wiele sposobów. Przykład:
Jeśli masz samochód, możesz chcieć wiedzieć: Czy ten miernik oleju odczytuje normalnie, czy mam wyciek? Jeśli monitorujesz zużycie energii, warto wiedzieć: Czy wystąpiła awaria?
Istnieją dwa typy anomalii szeregów czasowych, które można wykryć:
Skoki wskazują tymczasowe wzrosty nietypowego zachowania w systemie.
Punkty zmian wskazują początek trwałych zmian w czasie w systemie.
W ML.NET algorytmy wykrywania punktów zmian IID lub IID są odpowiednie dla niezależnych i identycznych zestawów danych rozproszonych. Zakładają oni, że dane wejściowe są sekwencją punktów danych, które są niezależnie próbkowane z jednej dystrybucji stacjonarnej.
W przeciwieństwie do modeli w innych samouczkach, przekształcenia detektora anomalii szeregów czasowych działają bezpośrednio na danych wejściowych. Metoda IEstimator.Fit()
nie wymaga danych szkoleniowych w celu wygenerowania przekształcenia. Wymaga jednak schematu danych, który jest dostarczany przez widok danych wygenerowany na podstawie pustej listy .ProductSalesData
Przeanalizujesz te same dane sprzedaży produktu, aby wykryć skoki i punkty zmian. Proces tworzenia i trenowania modelu jest taki sam w przypadku wykrywania skoków i wykrywania punktu zmiany; główną różnicą jest używany określony algorytm wykrywania.
Wykrywanie skoków
Celem wykrywania skoków jest zidentyfikowanie nagłych, ale tymczasowych wzrostów, które znacznie różnią się od większości wartości danych szeregów czasowych. Ważne jest, aby wykryć te podejrzane rzadkie elementy, zdarzenia lub obserwacje w odpowiednim czasie, aby być zminimalizowane. Następujące podejście może służyć do wykrywania różnych anomalii, takich jak: awarie, cyberataki lub wirusowa zawartość internetowa. Na poniższej ilustracji przedstawiono przykład skoków w zestawie danych szeregów czasowych:
Dodawanie metody CreateEmptyDataView()
Dodaj następującą metodę do 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);
}
Obiekt CreateEmptyDataView()
tworzy pusty obiekt widoku danych z poprawnym schematem, który ma być używany jako dane wejściowe metody IEstimator.Fit()
.
Tworzenie metody DetectSpike()
Metoda DetectSpike()
:
- Tworzy przekształcenie z narzędzia do szacowania.
- Wykrywa skoki na podstawie historycznych danych sprzedaży.
- Wyświetla wyniki.
Utwórz metodę
DetectSpike()
w dolnej części pliku Program.cs przy użyciu następującego kodu:DetectSpike(MLContext mlContext, int docSize, IDataView productSales) { }
Użyj IidSpikeEstimator , aby wytrenować model na potrzeby wykrywania skoków. Dodaj go do
DetectSpike()
metody przy użyciu następującego kodu:var iidSpikeEstimator = mlContext.Transforms.DetectIidSpike(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, pvalueHistoryLength: docSize / 4);
Utwórz przekształcenie wykrywania skoku, dodając następujący wiersz kodu w metodzie
DetectSpike()
:Porada
Parametry
confidence
ipvalueHistoryLength
wpływają na sposób wykrywania skoków.confidence
określa, jak poufny jest model do skoków. Niższa pewność, tym bardziej prawdopodobne jest, że algorytm wykrywa "mniejsze" skoki. ParametrpvalueHistoryLength
definiuje liczbę punktów danych w oknie przesuwanym. Wartość tego parametru jest zwykle procentem całego zestawu danych. Niższa wartośćpvalueHistoryLength
, tym szybciej model zapomina o poprzednich dużych skokach.ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
Dodaj następujący wiersz kodu, aby przekształcić
productSales
dane jako następny wiersz w metodzieDetectSpike()
:IDataView transformedData = iidSpikeTransform.Transform(productSales);
Poprzedni kod używa metody Transform(), aby przewidywać wiele wierszy wejściowych zestawu danych.
Przekonwertuj element
transformedData
na silnie typizowaneIEnumerable
, aby ułatwić wyświetlanie przy użyciu metody CreateEnumerable() z następującym kodem:var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Utwórz wiersz nagłówka wyświetlania przy użyciu następującego Console.WriteLine() kodu:
Console.WriteLine("Alert\tScore\tP-Value");
W wynikach wykrywania skoku zostaną wyświetlone następujące informacje:
Alert
wskazuje alert o skoku dla danego punktu danych.Score
ProductSales
jest wartością danego punktu danych w zestawie danych.P-Value
"P" oznacza prawdopodobieństwo. Im bliżej wartości p jest 0, tym bardziej prawdopodobne jest, że punkt danych jest anomalią.
Użyj następującego kodu, aby iterować dane
predictions
IEnumerable
i wyświetlić wyniki: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("");
Dodaj wywołanie metody poniżej wywołania metody do
DetectSpike()
LoadFromTextFile()
metody :DetectSpike(mlContext, _docsize, dataView);
Wyniki wykrywania skoku
Wyniki powinny być podobne do poniższych. Podczas przetwarzania są wyświetlane komunikaty. Mogą pojawić się ostrzeżenia lub komunikaty przetwarzania. Niektóre komunikaty zostały usunięte z poniższych wyników w celu uzyskania jasności.
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
Wykrywanie punktu zmiany
Change points
są trwałymi zmianami w rozkładie strumienia zdarzeń szeregów czasowych wartości, takich jak zmiany na poziomie i trendy. Te trwałe zmiany trwają znacznie dłużej niż spikes
i mogą wskazywać na katastrofalne zdarzenia. Change points
zwykle nie są widoczne dla nagiego oka, ale można je wykryć w danych przy użyciu metod, takich jak w poniższej metodzie. Na poniższej ilustracji przedstawiono przykład wykrywania punktu zmiany:
Tworzenie metody DetectChangepoint()
Metoda DetectChangepoint()
wykonuje następujące zadania:
- Tworzy przekształcenie z narzędzia do szacowania.
- Wykrywa punkty zmian na podstawie historycznych danych sprzedaży.
- Wyświetla wyniki.
Utwórz metodę
DetectChangepoint()
tuż poDetectSpike()
deklaracji metody, używając następującego kodu:void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales) { }
Utwórz moduł iidChangePointEstimator w metodzie
DetectChangepoint()
przy użyciu następującego kodu:var iidChangePointEstimator = mlContext.Transforms.DetectIidChangePoint(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, changeHistoryLength: docSize / 4);
Podobnie jak wcześniej, utwórz przekształcenie z narzędzia do szacowania, dodając następujący wiersz kodu w metodzie
DetectChangePoint()
:Porada
Wykrywanie punktów zmian występuje z niewielkim opóźnieniem, ponieważ model musi upewnić się, że bieżące odchylenie jest trwałą zmianą, a nie tylko niektóre losowe skoki przed utworzeniem alertu. Ilość tego opóźnienia jest równa parametrowi
changeHistoryLength
. Zwiększając wartość tego parametru, alerty wykrywania zmian dotyczące bardziej trwałych zmian, ale kompromis byłby dłuższy.var iidChangePointTransform = iidChangePointEstimator.Fit(CreateEmptyDataView(mlContext));
Transform()
Użyj metody , aby przekształcić dane, dodając następujący kod doDetectChangePoint()
elementu :IDataView transformedData = iidChangePointTransform.Transform(productSales);
Tak jak wcześniej, przekonwertuj element
transformedData
na silnie typizowaneIEnumerable
, aby ułatwić wyświetlanie przy użyciuCreateEnumerable()
metody z następującym kodem:var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
Utwórz nagłówek wyświetlania z następującym kodem jako następny wiersz w metodzie
DetectChangePoint()
:Console.WriteLine("Alert\tScore\tP-Value\tMartingale value");
W wynikach wykrywania punktu zmiany zostaną wyświetlone następujące informacje:
Alert
wskazuje alert punktu zmiany dla danego punktu danych.Score
ProductSales
jest wartością danego punktu danych w zestawie danych.P-Value
"P" oznacza prawdopodobieństwo. Im bliżej wartości P jest wartość 0, tym bardziej prawdopodobne jest, że punkt danych jest anomalią.Martingale value
służy do identyfikowania, jak "dziwny" jest punkt danych, na podstawie sekwencji wartości P.
Iteracja przez
predictions
IEnumerable
element i wyświetlanie wyników przy użyciu następującego kodu: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("");
Dodaj następujące wywołanie do
DetectChangepoint()
metody po wywołaniu metodyDetectSpike()
:DetectChangepoint(mlContext, _docsize, dataView);
Wyniki wykrywania punktu zmiany
Wyniki powinny być podobne do poniższych. Podczas przetwarzania są wyświetlane komunikaty. Mogą pojawić się ostrzeżenia lub komunikaty przetwarzania. Niektóre komunikaty zostały usunięte z poniższych wyników w celu uzyskania jasności.
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
Gratulacje! Udało Ci się utworzyć modele uczenia maszynowego do wykrywania skoków i anomalii punktów zmian w danych sprzedaży.
Kod źródłowy tego samouczka można znaleźć w repozytorium dotnet/samples .
W niniejszym samouczku zawarto informacje na temat wykonywania następujących czynności:
- Ładowanie danych
- Trenowanie modelu pod kątem wykrywania anomalii skoku
- Wykrywanie anomalii skoków za pomocą wytrenowanego modelu
- Trenowanie modelu pod kątem wykrywania anomalii w punkcie zmian
- Wykrywanie anomalii punktów zmian za pomocą wytrenowanego trybu
Następne kroki
Zapoznaj się z repozytorium GitHub przykładów usługi Machine Learning, aby zapoznać się z przykładem wykrywania anomalii danych sezonowych.