Partilhar via


Tutorial: Detetar anomalias nas vendas de produtos com ML.NET

Saiba como criar uma aplicação de deteção de anomalias para dados de vendas de produtos. Este tutorial cria uma aplicação de consola .NET Core com C# no Visual Studio.

Neste tutorial, ficará a saber como:

  • Carregar os dados
  • Criar uma transformação para deteção de anomalias de pico
  • Detetar anomalias de pico com a transformação
  • Criar uma transformação para a deteção de anomalias do ponto de alteração
  • Detetar anomalias do ponto de alteração com a transformação

Pode encontrar o código fonte deste tutorial no repositório dotnet/samples .

Pré-requisitos

Nota

O formato de dados no product-sales.csv baseia-se no conjunto de dados "Sales Over a Three Year Period" originalmente proveniente do DataMarket e fornecido pela Time Series Data Library (TSDL), criado por Rob Hyndman. Conjunto de Dados "Champô vendas ao longo de um período de três anos" Licenciado sob a Licença Open Predefinida do DataMarket.

Criar uma aplicação de consola

  1. Crie uma Aplicação de Consola C# denominada "ProductSalesAnomalyDetection". Clique no botão Seguinte .

  2. Selecione .NET 6 como a arquitetura a utilizar. Clique no botão Criar.

  3. Crie um diretório com o nome Dados no projeto para guardar os ficheiros do conjunto de dados.

  4. Instale o Pacote NuGet Microsoft.ML:

    Nota

    Este exemplo utiliza a versão estável mais recente dos pacotes NuGet mencionados, salvo indicação em contrário.

    No Explorador de Soluções, clique com o botão direito do rato no projeto e selecione Gerir Pacotes NuGet. Selecione "nuget.org" como origem do pacote, selecione o separador Procurar, procure Microsoft.ML e selecione o botão Instalar . Selecione o botão OK na caixa de diálogo Pré-visualizar Alterações e, em seguida, selecione o botão Aceito na caixa de diálogo Aceitação da Licença se concordar com os termos de licenciamento dos pacotes listados. Repita estes passos para Microsoft.ML.TimeSeries.

  5. Adicione as seguintes using instruções na parte superior do ficheiro Program.cs :

    using Microsoft.ML;
    using ProductSalesAnomalyDetection;
    

Transferir os seus dados

  1. Transfira o conjunto de dados e guarde-o na pasta Dados que criou anteriormente:

    • Clique com o botão direito do rato emproduct-sales.csv e selecione "Guardar Ligação (ou Destino) Como..."

      Certifique-se de que guarda o ficheiro *.csv na pasta Dados ou, depois de guardá-lo noutro local, mova o ficheiro *.csv para a pasta Dados .

  2. No Explorador de Soluções, clique com o botão direito do rato no ficheiro *.csv e selecione Propriedades. Em Avançadas, altere o valor de Copiar para Diretório de Saída para Copiar se for mais recente.

A tabela seguinte é uma pré-visualização de dados do seu ficheiro *.csv:

Mensal Vendas de Produtos
1-Jan 271
2-Jan 150.9
..... .....
1-Fev 199.3
..... .....

Criar classes e definir caminhos

Em seguida, defina as estruturas de dados da sua classe de entrada e predição.

Adicione uma nova classe ao seu projeto:

  1. No Explorador de Soluções, clique com o botão direito do rato no projeto e, em seguida, selecione Adicionar > Novo Item.

  2. Na caixa de diálogo Adicionar Novo Item, selecione Classe e altere o campo Nome para ProductSalesData.cs. Em seguida, selecione o botão Adicionar .

    O ficheiro ProductSalesData.cs é aberto no editor de código.

  3. Adicione a seguinte using instrução à parte superior de ProductSalesData.cs:

    using Microsoft.ML.Data;
    
  4. Remova a definição de classe existente e adicione o seguinte código, que tem duas classes ProductSalesData e ProductSalesPrediction, ao ficheiro 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 especifica uma classe de dados de entrada. O atributo LoadColumn especifica as colunas (por índice de coluna) no conjunto de dados que devem ser carregadas.

    ProductSalesPrediction especifica a classe de dados de predição. Para a deteção de anomalias, a predição consiste num alerta para indicar se existe uma anomalia, uma classificação não processada e um valor p. Quanto mais próximo for o valor p de 0, maior é a probabilidade de ter ocorrido uma anomalia.

  5. Crie dois campos globais para manter o caminho do ficheiro do conjunto de dados transferido recentemente e o caminho do ficheiro de modelo guardado:

    • _dataPath tem o caminho para o conjunto de dados utilizado para preparar o modelo.
    • _docsize tem o número de registos no ficheiro de conjunto de dados. Irá utilizar _docSize para calcular pvalueHistoryLength.
  6. Adicione o seguinte código à linha abaixo das instruções using para especificar esses caminhos:

    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;
    

Inicializar variáveis

  1. Substitua a Console.WriteLine("Hello World!") linha pelo seguinte código para declarar e inicializar a mlContext variável:

    MLContext mlContext = new MLContext();
    

    A classe MLContext é um ponto de partida para todas as operações de ML.NET e inicializar mlContext cria um novo ambiente de ML.NET que pode ser partilhado entre os objetos de fluxo de trabalho de criação de modelos. É semelhante, conceptualmente, a DBContext no Entity Framework.

Carregar os dados

Os dados no ML.NET são representados como uma interface IDataView. IDataView é uma forma flexível e eficiente de descrever dados tabulares (numéricos e texto). Os dados podem ser carregados a partir de um ficheiro de texto ou de outras origens (por exemplo, base de dados SQL ou ficheiros de registo) para um IDataView objeto.

  1. Adicione o seguinte código depois de criar a mlContext variável:

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

    LoadFromTextFile() define o esquema de dados e lê no ficheiro. Utiliza as variáveis de caminho de dados e devolve um IDataView.

Deteção de anomalias de série temporal

A deteção de anomalias sinaliza eventos ou comportamentos inesperados ou invulgares. Dá pistas sobre onde procurar problemas e ajuda-o a responder à pergunta "Isto é estranho?".

Exemplo da deteção de anomalias

A deteção de anomalias é o processo de deteção de valores atípicos de dados de série temporal; aponta para uma determinada série temporal de entrada em que o comportamento não é o esperado ou "estranho".

A deteção de anomalias pode ser útil de várias formas. Por exemplo:

Se tem um carro, talvez queira saber se este medidor de óleo está normal ou tenho uma fuga? Se estiver a monitorizar o consumo de energia, gostaria de saber: Existe alguma falha?

Existem dois tipos de anomalias de série temporal que podem ser detetadas:

  • Os picos indicam picos temporários de comportamento anómalo no sistema.

  • Os pontos de alteração indicam o início das alterações persistentes ao longo do tempo no sistema.

No ML.NET, os algoritmos de Deteção de Pico de IID ou Deteção de Ponto de Alteração de IID são adequados para conjuntos de dados independentes e distribuídos de forma idêntica. Partem do princípio de que os dados de entrada são uma sequência de pontos de dados que são amostrados independentemente de uma distribuição estacionária.

Ao contrário dos modelos nos outros tutoriais, as transformações do detetor de anomalias de série temporal operam diretamente nos dados de entrada. O IEstimator.Fit() método não precisa de dados de preparação para produzir a transformação. No entanto, precisa do esquema de dados, que é fornecido por uma vista de dados gerada a partir de uma lista vazia de ProductSalesData.

Irá analisar os mesmos dados de vendas de produtos para detetar picos e alterar pontos. O processo de criação e preparação do modelo é o mesmo para deteção de picos e deteção de pontos de alteração; a principal diferença é o algoritmo de deteção específico utilizado.

Deteção de picos

O objetivo da deteção de picos é identificar picos repentinos mas temporários que diferem significativamente da maioria dos valores de dados da série temporal. É importante detetar estes itens, eventos ou observações raros suspeitos em tempo útil para serem minimizados. A abordagem seguinte pode ser utilizada para detetar uma variedade de anomalias, tais como falhas, ciberataques ou conteúdo Web viral. A imagem seguinte é um exemplo de picos num conjunto de dados de série temporal:

Captura de ecrã a mostrar duas deteções de pico.

Adicionar o método CreateEmptyDataView()

Adicione o seguinte método 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);
}

Produz CreateEmptyDataView() um objeto de vista de dados vazio com o esquema correto a ser utilizado como entrada para o IEstimator.Fit() método .

Criar o método DetectSpike()

O DetectSpike() método :

  • Cria a transformação a partir do avaliador.
  • Deteta picos com base em dados de vendas históricos.
  • Apresenta os resultados.
  1. Crie o DetectSpike() método na parte inferior do ficheiro Program.cs com o seguinte código:

    DetectSpike(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. Utilize o IidSpikeEstimator para preparar o modelo para deteção de picos. Adicione-o ao DetectSpike() método com o seguinte código:

    var iidSpikeEstimator = mlContext.Transforms.DetectIidSpike(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, pvalueHistoryLength: docSize / 4);
    
  3. Crie a transformação de deteção de picos ao adicionar o seguinte como a próxima linha de código no DetectSpike() método :

    Dica

    Os confidence parâmetros e pvalueHistoryLength afetam a forma como os picos são detetados. confidence determina a sensibilidade do modelo aos picos. Quanto menor for a confiança, maior é a probabilidade de o algoritmo detetar picos "mais pequenos". O pvalueHistoryLength parâmetro define o número de pontos de dados numa janela deslizante. Normalmente, o valor deste parâmetro é uma percentagem de todo o conjunto de dados. Quanto mais baixo for o pvalueHistoryLength, mais rápido o modelo esquecerá os picos grandes anteriores.

    ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
    
  4. Adicione a seguinte linha de código para transformar os productSales dados como a linha seguinte no DetectSpike() método :

    IDataView transformedData = iidSpikeTransform.Transform(productSales);
    

    O código anterior utiliza o método Transform() para fazer predições para múltiplas linhas de entrada de um conjunto de dados.

  5. Converta-o transformedData num ecrã fortemente escrito IEnumerable para uma apresentação mais fácil com o método CreateEnumerable() com o seguinte código:

    var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
    
  6. Crie uma linha de cabeçalho de apresentação com o seguinte Console.WriteLine() código:

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

    Irá apresentar as seguintes informações nos resultados da deteção de picos:

    • Alert indica um alerta de pico para um determinado ponto de dados.
    • Score é o ProductSales valor de um determinado ponto de dados no conjunto de dados.
    • P-Value O "P" significa probabilidade. Quanto mais próximo for o valor p de 0, maior é a probabilidade de o ponto de dados ser uma anomalia.
  7. Utilize o seguinte código para iterar através do predictionsIEnumerable e apresentar os resultados:

    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. Adicione a chamada ao DetectSpike() método abaixo da chamada ao LoadFromTextFile() método :

    DetectSpike(mlContext, _docsize, dataView);
    

Resultados da deteção de picos

Os seus resultados devem ser semelhantes aos seguintes. Durante o processamento, as mensagens são apresentadas. Poderá ver avisos ou mensagens de processamento. Algumas das mensagens foram removidas dos seguintes resultados para maior clareza.

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

Deteção de pontos de alteração

Change points são alterações persistentes numa distribuição de fluxos de eventos de série temporal de valores, como alterações de nível e tendências. Estas alterações persistentes duram muito mais tempo do que spikes e podem indicar eventos catastróficos. Change points Normalmente, não são visíveis a olho nu, mas podem ser detetados nos seus dados através de abordagens como no seguinte método. A imagem seguinte é um exemplo de uma deteção de ponto de alteração:

Captura de ecrã que mostra uma deteção de ponto de alteração.

Criar o método DetectChangepoint()

O DetectChangepoint() método executa as seguintes tarefas:

  • Cria a transformação a partir do avaliador.
  • Deteta pontos de alteração com base em dados de vendas históricos.
  • Apresenta os resultados.
  1. Crie o DetectChangepoint() método logo após a declaração do DetectSpike() método, com o seguinte código:

    void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. Crie o iidChangePointEstimator no DetectChangepoint() método com o seguinte código:

    var iidChangePointEstimator = mlContext.Transforms.DetectIidChangePoint(outputColumnName: nameof(ProductSalesPrediction.Prediction), inputColumnName: nameof(ProductSalesData.numSales), confidence: 95d, changeHistoryLength: docSize / 4);
    
  3. Tal como fez anteriormente, crie a transformação a partir do avaliador ao adicionar a seguinte linha de código no DetectChangePoint() método :

    Dica

    A deteção de pontos de alteração ocorre com um ligeiro atraso, uma vez que o modelo precisa de se certificar de que o desvio atual é uma alteração persistente e não apenas alguns picos aleatórios antes de criar um alerta. A quantidade deste atraso é igual ao changeHistoryLength parâmetro . Ao aumentar o valor deste parâmetro, os alertas de deteção de alterações sobre alterações mais persistentes, mas a troca seria um atraso maior.

    var iidChangePointTransform = iidChangePointEstimator.Fit(CreateEmptyDataView(mlContext));
    
  4. Utilize o Transform() método para transformar os dados ao adicionar o seguinte código a DetectChangePoint():

    IDataView transformedData = iidChangePointTransform.Transform(productSales);
    
  5. Tal como fez anteriormente, converta-o transformedData num ecrã fortemente escrito IEnumerable para uma apresentação mais fácil com o CreateEnumerable()método com o seguinte código:

    var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
    
  6. Crie um cabeçalho de apresentação com o seguinte código como a linha seguinte no DetectChangePoint() método :

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

    Irá apresentar as seguintes informações nos resultados da deteção do ponto de alteração:

    • Alert indica um alerta de ponto de alteração para um determinado ponto de dados.
    • Score é o ProductSales valor de um determinado ponto de dados no conjunto de dados.
    • P-Value O "P" significa probabilidade. Quanto mais próximo for o valor P de 0, maior é a probabilidade de o ponto de dados ser uma anomalia.
    • Martingale value é utilizado para identificar o quão "estranho" é um ponto de dados, com base na sequência de valores P.
  7. Iterar através do predictionsIEnumerable e apresentar os resultados com o seguinte código:

    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. Adicione a seguinte chamada ao DetectChangepoint()método após a chamada para o DetectSpike() método :

    DetectChangepoint(mlContext, _docsize, dataView);
    

Resultados da deteção de pontos de alteração

Os seus resultados devem ser semelhantes aos seguintes. Durante o processamento, as mensagens são apresentadas. Poderá ver avisos ou mensagens de processamento. Algumas mensagens foram removidas dos seguintes resultados para maior clareza.

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

Parabéns! Criou com êxito modelos de machine learning para detetar picos e alterar anomalias de pontos nos dados de vendas.

Pode encontrar o código fonte deste tutorial no repositório dotnet/samples .

Neste tutorial, ficou a saber como:

  • Carregar os dados
  • Preparar o modelo para deteção de anomalias de picos
  • Detetar anomalias de pico com o modelo preparado
  • Preparar o modelo para deteção de anomalias de ponto de alteração
  • Detetar anomalias do ponto de alteração com o modo preparado

Passos seguintes

Veja o repositório do GitHub de exemplos do Machine Learning para explorar um exemplo de deteção de anomalias de dados de sazonalidade.