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
Visual Studio 2022 com a carga de trabalho ".NET Desktop Development" instalada.
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
Crie um aplicativo de console C# chamado "ProductSalesAnomalyDetection". Clique no botão Avançar.
Escolha .NET 8 como a estrutura a ser usada. Clique no botão Criar.
Crie um diretório chamado Data em seu projeto para salvar seus arquivos de conjunto de dados.
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.
Adicione as seguintes diretivas
using
na parte superior do ficheiro Program.cs:using Microsoft.ML; using ProductSalesAnomalyDetection;
Faça o download dos seus dados
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.
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:
No Gerenciador de Soluções , clique com o botão direito do mouse no projeto e 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 Adicionar.
O arquivo ProductSalesData.cs é aberto no editor de códigos.
Adicione a seguinte diretiva
using
ao topo da 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 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.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 calcularpvalueHistoryLength
.
-
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
Substitua a linha
Console.WriteLine("Hello World!")
pelo código a seguir para declarar e inicializar a variávelmlContext
: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, aoDBContext
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
.
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?".
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:
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.
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) { }
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);
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
epvalueHistoryLength
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âmetropvalueHistoryLength
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 apvalueHistoryLength
, mais rápido o modelo esquece os grandes picos anteriores.ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));
Adicione a seguinte linha de código para transformar os dados
productSales
como a próxima linha no métodoDetectSpike()
: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. Converta seu
transformedData
em umIEnumerable
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);
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 valorProductSales
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.
-
Use o código a seguir para iterar através do
predictions
IEnumerable
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("");
Adicione a chamada ao método
DetectSpike()
para que fique abaixo da chamada ao métodoLoadFromTextFile()
.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:
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.
Crie o método
DetectChangepoint()
, logo após a declaração do métodoDetectSpike()
, usando o seguinte código:void DetectChangepoint(MLContext mlContext, int docSize, IDataView productSales) { }
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);
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));
Use o método
Transform()
para transformar os dados adicionando o seguinte código aoDetectChangePoint()
:IDataView transformedData = iidChangePointTransform.Transform(productSales);
Como fez anteriormente, converta o seu
transformedData
em umIEnumerable
com tipagem forte para simplificar o processo de exibição usando o métodoCreateEnumerable()
com o seguinte código:var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData, reuseRowObject: false);
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 valorProductSales
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.
-
Itere através do
predictions
IEnumerable
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("");
Adicione a seguinte chamada ao método
DetectChangepoint()
após a chamada para o métodoDetectSpike()
: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.