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
Visual Studio 2022 com a carga de trabalho ".NET Desktop Development" instalada.
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
Crie uma Aplicação de Consola C# denominada "ProductSalesAnomalyDetection". Clique no botão Seguinte .
Selecione .NET 6 como a arquitetura a utilizar. Clique no botão Criar.
Crie um diretório com o nome Dados no projeto para guardar os ficheiros do conjunto de dados.
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.
Adicione as seguintes
using
instruções na parte superior do ficheiro Program.cs :using Microsoft.ML; using ProductSalesAnomalyDetection;
Transferir os seus dados
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 .
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:
No Explorador de Soluções, clique com o botão direito do rato no projeto e, em seguida, selecione Adicionar > Novo Item.
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.
Adicione a seguinte
using
instrução à parte superior de ProductSalesData.cs:using Microsoft.ML.Data;
Remova a definição de classe existente e adicione o seguinte código, que tem duas classes
ProductSalesData
eProductSalesPrediction
, 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.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 calcularpvalueHistoryLength
.
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
Substitua a
Console.WriteLine("Hello World!")
linha pelo seguinte código para declarar e inicializar amlContext
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, aDBContext
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.
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?".
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:
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.
Crie o
DetectSpike()
método na parte inferior do ficheiro Program.cs com o seguinte código:DetectSpike(MLContext mlContext, int docSize, IDataView productSales) { }
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);
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 epvalueHistoryLength
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". OpvalueHistoryLength
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 opvalueHistoryLength
, mais rápido o modelo esquecerá os picos grandes anteriores.ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
Adicione a seguinte linha de código para transformar os
productSales
dados como a linha seguinte noDetectSpike()
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.
Converta-o
transformedData
num ecrã fortemente escritoIEnumerable
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);
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
é oProductSales
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.
Utilize o seguinte código para iterar através do
predictions
IEnumerable
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("");
Adicione a chamada ao
DetectSpike()
método abaixo da chamada aoLoadFromTextFile()
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:
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.
Crie o
DetectChangepoint()
método logo após a declaração doDetectSpike()
método, com o seguinte código:void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales) { }
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);
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));
Utilize o
Transform()
método para transformar os dados ao adicionar o seguinte código aDetectChangePoint()
:IDataView transformedData = iidChangePointTransform.Transform(productSales);
Tal como fez anteriormente, converta-o
transformedData
num ecrã fortemente escritoIEnumerable
para uma apresentação mais fácil com oCreateEnumerable()
método com o seguinte código:var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
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
é oProductSales
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.
Iterar através do
predictions
IEnumerable
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("");
Adicione a seguinte chamada ao
DetectChangepoint()
método após a chamada para oDetectSpike()
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.