Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Saiba como prever a demanda por um serviço de aluguel de bicicletas usando análise de série temporal não variável em dados armazenados em um banco de dados do SQL Server com ML.NET.
Neste tutorial, você aprenderá como:
- Compreender o problema
- Carregar dados de um banco de dados
- Criar um modelo de previsão
- Avaliar o modelo de previsão
- Salvar um modelo de previsão
- Usar um modelo de previsão
Pré-requisitos
- Visual Studio 2022 ou posterior com a carga de trabalho de Desenvolvimento da Área de Trabalho do .NET instalada.
Visão geral do exemplo de previsão de série temporal
Este exemplo é um aplicativo de console C# que prevê a demanda por aluguel de bicicletas usando um algoritmo de análise de série temporal não variável conhecido como Análise de Espectro Singular. O código deste exemplo pode ser encontrado no repositório dotnet/machinelearning-samples no GitHub.
Compreender o problema
Para executar uma operação eficiente, o gerenciamento de inventário desempenha um papel fundamental. Ter muito de um produto em estoque significa produtos não vendidos sentados nas prateleiras não gerando nenhuma receita. Ter muito pouco produto leva a vendas perdidas e clientes comprando de concorrentes. Portanto, a pergunta constante é: qual é a quantidade ideal de inventário a ser mantida em mãos? A análise de série temporal ajuda a fornecer uma resposta para essas perguntas examinando dados históricos, identificando padrões e usando essas informações para prever valores em algum momento no futuro.
A técnica para analisar os dados usados neste tutorial é uma análise de série temporal não variável. A análise de série temporal univariada analisa uma única observação numérica durante um período de tempo em intervalos específicos, como vendas mensais.
O algoritmo usado neste tutorial é Singular Spectrum Analysis (SSA). O SSA funciona decompondo uma série temporal em um conjunto de componentes principais. Esses componentes podem ser interpretados como partes de um sinal que correspondem a tendências, ruído, sazonalidade e muitos outros fatores. Em seguida, esses componentes são reconstruídos e usados para prever valores em algum momento no futuro.
Criar aplicativo de console
Crie um aplicativo de console C# chamado "BikeDemandForecasting". Clique no botão Avançar.
Escolha .NET 8 como a estrutura a ser usada. Clique no botão Criar .
Instale o pacote NuGet da versão Microsoft.ML
Observação
Este exemplo usa a versão estável mais recente dos pacotes NuGet mencionados, a menos que indicado de outra forma.
- 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 a origem do pacote, selecione a guia Procurar , pesquise Microsoft.ML.
- Marque a caixa de seleção Incluir pré-lançamento .
- Selecione o botão Instalar.
- Selecione o botão OK na caixa de diálogo Alterações de Visualização e, em seguida, selecione o botão I Accept na caixa de diálogo Aceitação da Licença se você concordar com os termos de licença dos pacotes listados.
- Repita estas etapas para System.Data.SqlClient e Microsoft.ML.TimeSeries.
Preparar e entender os dados
- Crie um diretório chamado Dados.
- Baixe o arquivo de banco de dados DailyDemand.mdf e salve-o no diretório de dados.
Observação
Os dados usados neste tutorial são provenientes do conjunto de dados de compartilhamento de bicicletas da UCI. Hadi Fanaee-T e João Gama, 'Rotulagem de eventos combinando detectores de conjuntos e conhecimento em segundo plano', Progresso em Inteligência Artificial (2013): pp. 1-15, Springer Berlin Heidelberg, Web Link.
O conjunto de dados original contém várias colunas correspondentes à sazonalidade e ao clima. Para fins de brevidade e como o algoritmo usado neste tutorial requer apenas os valores de uma única coluna numérica, o conjunto de dados original foi condensado para incluir apenas as seguintes colunas:
- dteday: a data da observação.
- ano: o ano codificado da observação (0=2011, 1=2012).
- cnt: O número total de aluguéis de bicicletas para aquele dia.
O conjunto de dados original é mapeado para uma tabela de banco de dados com o esquema a seguir em um banco de dados do SQL Server.
CREATE TABLE [Rentals] (
[RentalDate] DATE NOT NULL,
[Year] INT NOT NULL,
[TotalRentals] INT NOT NULL
);
Veja a seguir um exemplo dos dados:
| RentalDate | Ano | TotalRentals |
|---|---|---|
| 1/1/2011 | 0 | 985 |
| 1/2/2011 | 0 | 801 |
| 1/3/2011 | 0 | 1349 |
Criar classes de entrada e saída
Abra Program.cs arquivo e substitua as diretivas existentes
usingpelo seguinte:using Microsoft.ML; using Microsoft.ML.Data; using Microsoft.ML.Transforms.TimeSeries; using System.Data.SqlClient;Criar
ModelInputclasse. Abaixo daProgramclasse, adicione o código a seguir.public class ModelInput { public DateTime RentalDate { get; set; } public float Year { get; set; } public float TotalRentals { get; set; } }A
ModelInputclasse contém as seguintes colunas:- RentalDate: a data da observação.
- Ano: o ano codificado da observação (0=2011, 1=2012).
- TotalRentals: O número total de aluguéis de bicicletas para aquele dia.
Crie
ModelOutputuma classe abaixo da classe recém-criadaModelInput.public class ModelOutput { public float[] ForecastedRentals { get; set; } public float[] LowerBoundRentals { get; set; } public float[] UpperBoundRentals { get; set; } }A
ModelOutputclasse contém as seguintes colunas:- ForecastedRentals: Os valores previstos para o período previsto.
- LowerBoundRentals: os valores mínimos previstos para o período previsto.
- UpperBoundRentals: os valores máximos previstos para o período previsto.
Definir caminhos e inicializar variáveis
Abaixo das
usingdiretivas, defina variáveis para armazenar o local de seus dados, cadeia de conexão e onde salvar o modelo treinado.string rootDir = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../")); string dbFilePath = Path.Combine(rootDir, "Data", "DailyDemand.mdf"); string modelPath = Path.Combine(rootDir, "MLModel.zip"); var connectionString = $"Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename={dbFilePath};Integrated Security=True;Connect Timeout=30;";Inicialize a variável
mlContextcom uma nova instância deMLContextadicionando a linha a seguir depois de definir os caminhos.MLContext mlContext = new MLContext();A
MLContextclasse é um ponto de partida para todas as operações de ML.NET e a inicialização do mlContext cria um novo ambiente ML.NET que pode ser compartilhado entre os objetos de fluxo de trabalho de criação de modelo. É semelhante, conceitualmente, aoDBContextEntity Framework.
Carregar os dados
Crie
DatabaseLoaderque carrega registros do tipoModelInput.DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();Defina a consulta para carregar os dados do banco de dados.
string query = "SELECT RentalDate, CAST(Year as REAL) as Year, CAST(TotalRentals as REAL) as TotalRentals FROM Rentals";ML.NET algoritmos esperam que os dados sejam do tipo
Single. Portanto, os valores numéricos provenientes do banco de dados que não são do tipoReal, um valor de ponto flutuante de precisão única, precisam ser convertidosRealem .As colunas
YeareTotalRentalsão do tipo inteiro no banco de dados. Usando aCASTfunção embutida, ambos são convertidos paraReal.Crie um
DatabaseSourcepara se conectar ao banco de dados e executar a consulta.DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance, connectionString, query);Carregue os dados em um
IDataView.IDataView dataView = loader.Load(dbSource);O conjunto de dados contém dois anos de dados. Somente os dados do primeiro ano são usados para treinamento, o segundo ano é mantido para comparar os valores reais com a previsão produzida pelo modelo. Filtre os dados usando a
FilterRowsByColumntransformação.IDataView firstYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", upperBound: 1); IDataView secondYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", lowerBound: 1);Para o primeiro ano, somente os valores na
Yearcoluna menor que 1 são selecionados definindo oupperBoundparâmetro como 1. Por outro lado, para o segundo ano, valores maiores ou iguais a 1 são selecionados definindo olowerBoundparâmetro como 1.
Definir o pipeline de análise de série temporal
Defina um pipeline que usa o SsaForecastingEstimator para prever valores em um conjunto de dados de série temporal.
var forecastingPipeline = mlContext.Forecasting.ForecastBySsa( outputColumnName: "ForecastedRentals", inputColumnName: "TotalRentals", windowSize: 7, seriesLength: 30, trainSize: 365, horizon: 7, confidenceLevel: 0.95f, confidenceLowerBoundColumn: "LowerBoundRentals", confidenceUpperBoundColumn: "UpperBoundRentals");O
forecastingPipelineusa 365 pontos de dados para o primeiro ano e amostra ou divide o conjunto de dados de série temporal em intervalos de 30 dias (mensais), conforme especificado peloseriesLengthparâmetro. Cada um desses exemplos é analisado por meio de uma janela semanal ou de sete dias. Ao determinar qual é o valor previsto para o próximo período, os valores dos sete dias anteriores são usados para fazer uma previsão. O modelo está definido para prever sete períodos no futuro, conforme definido pelohorizonparâmetro. Como uma previsão é um palpite informado, nem sempre é 100% precisa. Portanto, é bom saber o intervalo de valores nos melhores e piores cenários, conforme definido pelos limites superior e inferior. Nesse caso, o nível de confiança para os limites inferior e superior é definido como 95%. O nível de confiança pode ser aumentado ou reduzido adequadamente. Quanto maior o valor, maior o intervalo entre os limites superior e inferior para atingir o nível de confiança desejado.Use o
Fitmétodo para treinar o modelo e ajustar os dados ao definidoforecastingPipelineanteriormente.SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
Avaliar o modelo
Avalie o desempenho do modelo ao prever os dados do próximo ano e compará-lo com os valores reais.
Crie um novo método de utilitário chamado
Evaluatena parte inferior do arquivo Program.cs .Evaluate(IDataView testData, ITransformer model, MLContext mlContext) { }Dentro do
Evaluatemétodo, prevea os dados do segundo ano usando oTransformmétodo com o modelo treinado.IDataView predictions = model.Transform(testData);Obtenha os valores reais dos dados usando o
CreateEnumerablemétodo.IEnumerable<float> actual = mlContext.Data.CreateEnumerable<ModelInput>(testData, true) .Select(observed => observed.TotalRentals);Obtenha os valores de previsão usando o
CreateEnumerablemétodo.IEnumerable<float> forecast = mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true) .Select(prediction => prediction.ForecastedRentals[0]);Calcule a diferença entre os valores reais e de previsão, geralmente chamados de erro.
var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);Medir o desempenho calculando os valores de erro médio absoluto absoluto e erro quadrado médio raiz.
var MAE = metrics.Average(error => Math.Abs(error)); // Mean Absolute Error var RMSE = Math.Sqrt(metrics.Average(error => Math.Pow(error, 2))); // Root Mean Squared ErrorPara avaliar o desempenho, as seguintes métricas são usadas:
- Erro absoluto médio: mede o quão próximas são as previsões do valor real. Esse valor varia entre 0 e infinito. Quanto mais próximo de 0, melhor a qualidade do modelo.
- Erro quadrado médio raiz: resume o erro no modelo. Esse valor varia entre 0 e infinito. Quanto mais próximo de 0, melhor a qualidade do modelo.
Exiba as métricas no console.
Console.WriteLine("Evaluation Metrics"); Console.WriteLine("---------------------"); Console.WriteLine($"Mean Absolute Error: {MAE:F3}"); Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");Chame o
Evaluatemétodo abaixo chamando oFit()método.Evaluate(secondYearData, forecaster, mlContext);
Salvar o modelo
Se você estiver satisfeito com seu modelo, salve-o para uso posterior em outros aplicativos.
Abaixo do
Evaluate()método, crie umTimeSeriesPredictionEngine.TimeSeriesPredictionEngineé um método de conveniência para fazer previsões simples.var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);Salve o modelo em um arquivo chamado
MLModel.zipconforme especificado pela variável definidamodelPathanteriormente. Use oCheckpointmétodo para salvar o modelo.forecastEngine.CheckPoint(mlContext, modelPath);
Usar o modelo para prever a demanda
Abaixo do
Evaluatemétodo, crie um novo método utilitário chamadoForecast.void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext) { }Dentro do
Forecastmétodo, use oPredictmétodo para prever aluguéis para os próximos sete dias.ModelOutput forecast = forecaster.Predict();Alinhe os valores reais e de previsão para sete períodos.
IEnumerable<string> forecastOutput = mlContext.Data.CreateEnumerable<ModelInput>(testData, reuseRowObject: false) .Take(horizon) .Select((ModelInput rental, int index) => { string rentalDate = rental.RentalDate.ToShortDateString(); float actualRentals = rental.TotalRentals; float lowerEstimate = Math.Max(0, forecast.LowerBoundRentals[index]); float estimate = forecast.ForecastedRentals[index]; float upperEstimate = forecast.UpperBoundRentals[index]; return $"Date: {rentalDate}\n" + $"Actual Rentals: {actualRentals}\n" + $"Lower Estimate: {lowerEstimate}\n" + $"Forecast: {estimate}\n" + $"Upper Estimate: {upperEstimate}\n"; });Iterar pelo resultado da previsão e mostrá-lo no terminal.
Console.WriteLine("Rental Forecast"); Console.WriteLine("---------------------"); foreach (var prediction in forecastOutput) { Console.WriteLine(prediction); }
Executar o aplicativo
Abaixo, chamar o
Checkpoint()método chama oForecastmétodo.Forecast(secondYearData, 7, forecastEngine, mlContext);Execute o aplicativo. Uma saída semelhante à abaixo deve aparecer no console. Por brevidade, o resultado foi condensado.
Evaluation Metrics --------------------- Mean Absolute Error: 726.416 Root Mean Squared Error: 987.658 Rental Forecast --------------------- Date: 1/1/2012 Actual Rentals: 2294 Lower Estimate: 1197.842 Forecast: 2334.443 Upper Estimate: 3471.044 Date: 1/2/2012 Actual Rentals: 1951 Lower Estimate: 1148.412 Forecast: 2360.861 Upper Estimate: 3573.309
A inspeção dos valores reais e previstos mostra as seguintes relações:
Embora os valores previstos não estejam prevendo o número exato de aluguéis, eles fornecem um intervalo mais estreito de valores que permite que uma operação otimize o uso de recursos.
Parabéns! Agora você criou com êxito um modelo de machine learning de série temporal para prever a demanda de aluguel de bicicletas.
Você pode encontrar o código-fonte deste tutorial no repositório dotnet/machinelearning-samples .