Partilhar via


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

Saiba como criar um aplicativo de deteção de anomalias para dados de vendas de produtos. Este tutorial cria um aplicativo de console .NET usando C# no Visual Studio.

Neste tutorial, você aprenderá a:

  • Carregue os dados
  • Criar uma transformação para deteção de anomalias de pico
  • Detete anomalias de pico com a transformação
  • Criar uma transformação para deteção de anomalias no ponto de alteração
  • Detetar anomalias de ponto de alteração com a transformação

Você pode encontrar o código-fonte deste tutorial no repositório dotnet/samples .

Pré-requisitos

Observação

O formato de dados no product-sales.csv é baseado no conjunto de dados "Shampoo Sales Over a Three Year Period" originalmente proveniente do DataMarket e fornecido pela Time Series Data Library (TSDL), criada por Rob Hyndman. Conjunto de dados "Vendas de shampoo durante um período de três anos" licenciado sob a licença aberta padrão DataMarket.

Criar um aplicativo de console

  1. Crie um aplicativo de console C# chamado "ProductSalesAnomalyDetection". Clique no botão Avançar.

  2. Escolha .NET 8 como a estrutura a ser usada. Clique no botão Criar.

  3. Crie um diretório chamado Data em seu projeto para salvar seus arquivos de conjunto de dados.

  4. Instale o Microsoft.ML pacote NuGet:

    Observação

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

    No Gerenciador de Soluções, clique com o botão direito do mouse em seu projeto e selecione Gerenciar pacotes NuGet. Escolha "nuget.org" como origem do pacote, selecione o separador Procurar, procure por Microsoft.ML e depois clique em Instalar. Selecione o botão OK na caixa de diálogo de Pré-visualização de Alterações e, em seguida, selecione o botão Aceito na caixa de diálogo de Aceitação de Licença caso concorde com os termos de licença para os pacotes listados. Repita estas etapas para Microsoft.ML.TimeSeries.

  5. Adicione as seguintes diretivas using na parte superior do ficheiro Program.cs:

    using Microsoft.ML;
    using ProductSalesAnomalyDetection;
    

Faça o download dos seus dados

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

    • Clique com o botão direito do mouse em product-sales.csv e selecione "Salvar link (ou destino) como..."

      Certifique-se de salvar o arquivo *.csv na pasta Data ou, depois de salvá-lo em outro lugar, mova o arquivo *.csv para a pasta Data.

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

A tabela a seguir é uma visualização de dados do seu arquivo *.csv:

Mês Vendas de Produtos
1-janeiro 271
2-janeiro 150.9
..... .....
1-fev 199.3
..... .....

Criar classes e definir caminhos

Em seguida, defina suas estruturas de dados de classe de entrada e previsão.

Adicione uma nova classe ao seu projeto:

  1. No Gerenciador de Soluções , clique com o botão direito do mouse no projeto e 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 Adicionar.

    O arquivo ProductSalesData.cs é aberto no editor de códigos.

  3. Adicione a seguinte diretiva using ao topo da 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 arquivo 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 quais colunas (por índice de coluna) no conjunto de dados devem ser carregadas.

    ProductSalesPrediction especifica a classe de dados de previsão. Para a deteção de anomalias, a previsão consiste em um alerta para indicar se há uma anomalia, uma pontuação bruta e um valor p. Quanto mais próximo o valor p estiver de 0, maior a probabilidade de ocorrência de uma anomalia.

  5. Crie dois campos globais para armazenar o caminho do arquivo do conjunto de dados baixado recentemente e o caminho do arquivo de modelo salvo:

    • _dataPath tem o caminho para o conjunto de dados usado para treinar o modelo.
    • _docsize contém o número de registos no arquivo do conjunto de dados. Você usará _docSize para calcular pvalueHistoryLength.
  6. Adicione o seguinte código à linha logo abaixo das diretivas 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 linha Console.WriteLine("Hello World!") pelo código a seguir para declarar e inicializar a variável mlContext:

    MLContext mlContext = new MLContext();
    

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

Carregue 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 de texto). Os dados podem ser carregados de um arquivo de texto ou de outras fontes (por exemplo, banco de dados SQL ou arquivos de log) para um objeto IDataView.

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

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

    O LoadFromTextFile() define o esquema de dados e lê no arquivo. Recebe as variáveis de caminho de dados e retorna um IDataView.

Deteção de anomalias em séries cronológicas

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

Exemplo de deteção de anomalias

A deteção de anomalias é o processo de deteção de valores anómalos em dados de séries temporais: pontos em uma determinada série temporal de entrada onde o comportamento não é o esperado, ou "estranho".

A deteção de anomalias pode ser útil de muitas maneiras. Por exemplo:

Se tiveres um carro, podes querer saber: Este indicador de óleo está a funcionar normalmente, ou tenho uma fuga? Se você está monitorando o consumo de energia, gostaria de saber: Há uma interrupção?

Existem dois tipos de anomalias de séries cronológicas que podem ser detetadas:

  • Spikes indica explosões temporárias de comportamento anómalo no sistema.

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

No ML.NET, os algoritmos IID Spike Detection ou IID Change Point Detection são adequados para conjuntos de dados independentes e distribuídos de forma idêntica . Eles assumem que os seus dados de entrada são uma sequência de pontos de dados, que são amostrados independentemente de a uma distribuição estacionária.

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

Você analisará os mesmos dados de vendas de produtos para detetar picos e pontos de alteração. O processo do modelo de construção e treinamento é 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 explosões súbitas, mas temporárias, que diferem significativamente da maioria dos valores de dados de séries temporais. É importante detetar esses itens raros, eventos ou observações suspeitos em tempo hábil para serem minimizados. A abordagem a seguir pode ser usada para detetar uma variedade de anomalias, tais como: interrupções, ataques cibernéticos ou conteúdo viral da Web. A imagem a seguir é um exemplo de picos em um conjunto de dados de série temporal:

Imagem que mostra duas deteções de pico.

Adicione 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);
}

O CreateEmptyDataView() produz um objeto de exibição de dados vazio com o esquema correto a ser usado como entrada para o método IEstimator.Fit().

Criar o método DetectSpike()

O método DetectSpike():

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

    DetectSpike(MLContext mlContext, int docSize, IDataView productSales)
    {
    
    }
    
  2. Use o IidSpikeEstimator para treinar o modelo para deteção de picos. Adicione-o ao método DetectSpike() 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 pico adicionando o seguinte como a próxima linha de código no método DetectSpike():

    Dica

    Os parâmetros confidence e pvalueHistoryLength afetam a forma como os picos são detetados. confidence determina o quão sensível seu modelo é a picos. Quanto menor a confiança, maior a probabilidade de o algoritmo detetar picos "menores". O parâmetro pvalueHistoryLength define o número de pontos de dados em uma janela deslizante. O valor desse parâmetro geralmente é uma porcentagem de todo o conjunto de dados. Quanto mais baixa a pvalueHistoryLength, mais rápido o modelo esquece os grandes picos anteriores.

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

    IDataView transformedData = iidSpikeTransform.Transform(productSales);
    

    O código anterior usa o método Transform() para fazer previsões para várias linhas de entrada de um conjunto de dados.

  5. Converta seu transformedData em um IEnumerable fortemente tipado para facilitar a exibição usando 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 exibição usando o seguinte código Console.WriteLine():

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

    Você exibirá 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 valor ProductSales para um determinado ponto de dados no conjunto de dados.
    • P-Value O "P" significa probabilidade. Quanto mais próximo o valor p estiver de 0, maior a probabilidade de o ponto de dados ser uma anomalia.
  7. Use o código a seguir para iterar através do predictionsIEnumerable e exibir 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 método DetectSpike() para que fique abaixo da chamada ao método LoadFromTextFile().

    DetectSpike(mlContext, _docsize, dataView);
    

Resultados da deteção de picos

Os resultados devem ser semelhantes aos seguintes. Durante o processamento, as mensagens são exibidas. Poderá receber 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 ponto de alteração

Change points são alterações persistentes em uma distribuição de fluxo de eventos de série temporal de valores, como mudanças de nível e tendências. Estas alterações persistentes duram muito mais do que spikes e podem indicar acontecimento(s) catastrófico(s). Change points geralmente não são visíveis a olho nu, mas podem ser detetados em seus dados usando abordagens como no método a seguir. A imagem a seguir é 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 método DetectChangepoint() executa as seguintes tarefas:

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

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

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

    Dica

    A deteção de pontos de alteração acontece com um ligeiro atraso, pois o modelo precisa certificar-se 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 parâmetro changeHistoryLength. Ao aumentar o valor desse parâmetro, a deteção de alterações alerta sobre alterações mais persistentes, mas a compensação seria um atraso maior.

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

    IDataView transformedData = iidChangePointTransform.Transform(productSales);
    
  5. Como fez anteriormente, converta o seu transformedData em um IEnumerable com tipagem forte para simplificar o processo de exibição usando o método CreateEnumerable()com o seguinte código:

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

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

    Você exibirá as seguintes informações nos resultados de deteção de ponto de alteração:

    • Alert indica um alerta de ponto de alteração para um determinado ponto de dados.
    • Score é o valor ProductSales para um determinado ponto de dados no conjunto de dados.
    • P-Value O "P" significa probabilidade. Quanto mais próximo o valor P estiver de 0, maior a probabilidade de o ponto de dados ser uma anomalia.
    • Martingale value é usado para identificar o quão "estranho" é um ponto de dados, com base na sequência de valores P.
  7. Itere através do predictionsIEnumerable e exiba 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 método DetectChangepoint()após a chamada para o método DetectSpike():

    DetectChangepoint(mlContext, _docsize, dataView);
    

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

Os resultados devem ser semelhantes aos seguintes. Durante o processamento, as mensagens são exibidas. 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;! Agora você criou com sucesso modelos de aprendizado de máquina para detetar picos e anomalias de ponto de alteração nos dados de vendas.

Você pode encontrar o código-fonte deste tutorial no repositório dotnet/samples .

Neste tutorial, você aprendeu como:

  • Carregue os dados
  • Treine o modelo para deteção de anomalias de pico
  • Detecte anomalias de picos com o modelo treinado
  • Treinar o modelo para deteção de anomalias no ponto de alteração
  • Detetar anomalias em pontos de mudança com o modelo treinado

Próximos passos

Confira o repositório GitHub de exemplos de Machine Learning para explorar uma amostra de deteção de anomalias de dados de sazonalidade.