Udostępnij za pośrednictwem


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

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

  1. Utwórz aplikację konsolową języka C# o nazwie "ProductSalesAnomalyDetection". Kliknij przycisk Dalej.

  2. Wybierz platformę .NET 6 jako platformę do użycia. Kliknij przycisk Utwórz.

  3. Utwórz katalog o nazwie Dane w projekcie, aby zapisać pliki zestawu danych.

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

  5. Dodaj następujące using instrukcje w górnej części pliku Program.cs :

    using Microsoft.ML;
    using ProductSalesAnomalyDetection;
    

Pobierz swoje dane

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

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

  1. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt, a następnie wybierz polecenie Dodaj > nowy element.

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

  3. Dodaj następującą using instrukcję na początku pliku ProductSalesData.cs:

    using Microsoft.ML.Data;
    
  4. Usuń istniejącą definicję klasy i dodaj następujący kod, który ma dwie klasy ProductSalesData i ProductSalesPrediction, 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.

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

  1. 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, do DBContext 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.

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

Przykład wykrywania anomalii

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:

Zrzut ekranu przedstawiający dwa wykrycia skoków.

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.
  1. 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)
    {
    
    }
    
  2. 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);
    
  3. Utwórz przekształcenie wykrywania skoku, dodając następujący wiersz kodu w metodzie DetectSpike() :

    Porada

    Parametry confidence i pvalueHistoryLength 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. Parametr pvalueHistoryLength 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));
    
  4. Dodaj następujący wiersz kodu, aby przekształcić productSales dane jako następny wiersz w metodzie DetectSpike() :

    IDataView transformedData = iidSpikeTransform.Transform(productSales);
    

    Poprzedni kod używa metody Transform(), aby przewidywać wiele wierszy wejściowych zestawu danych.

  5. Przekonwertuj element transformedData na silnie typizowane IEnumerable , aby ułatwić wyświetlanie przy użyciu metody CreateEnumerable() z następującym kodem:

    var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
    
  6. 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.
    • ScoreProductSales 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ą.
  7. Użyj następującego kodu, aby iterować dane predictionsIEnumerable 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("");
    
  8. 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:

Zrzut ekranu przedstawiający wykrywanie 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.
  1. Utwórz metodę DetectChangepoint() tuż po DetectSpike() deklaracji metody, używając następującego kodu:

    void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. 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);
    
  3. 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));
    
  4. Transform() Użyj metody , aby przekształcić dane, dodając następujący kod do DetectChangePoint()elementu :

    IDataView transformedData = iidChangePointTransform.Transform(productSales);
    
  5. Tak jak wcześniej, przekonwertuj element transformedData na silnie typizowane IEnumerable , aby ułatwić wyświetlanie przy użyciu CreateEnumerable()metody z następującym kodem:

    var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
    
  6. 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.
    • ScoreProductSales 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.
  7. Iteracja przez predictionsIEnumerable 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("");
    
  8. Dodaj następujące wywołanie do DetectChangepoint()metody po wywołaniu metody DetectSpike() :

    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.