Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Découvrez comment prévoir la demande d’un service de location de vélos à l’aide d’une analyse de série chronologique univariée sur les données stockées dans une base de données SQL Server avec ML.NET.
Dans ce tutoriel, vous allez apprendre à :
- Comprendre le problème
- Charger des données à partir d’une base de données
- Créer un modèle de prévision
- Évaluer le modèle de prévision
- Enregistrer un modèle de prévision
- Utiliser un modèle de prévision
Prerequisites
- Visual Studio 2022 ou version ultérieure avec la charge de travail développement .NET Desktop installée.
Vue d’ensemble de l’exemple de prévision de série chronologique
Cet exemple est une application console C# qui prévoit la demande de locations de vélos à l’aide d’un algorithme d’analyse de série chronologique univarié appelé Singular Spectrum Analysis. Le code de cet exemple se trouve dans le référentiel dotnet/machinelearning-samples sur GitHub.
Comprendre le problème
Pour exécuter une opération efficace, la gestion de l’inventaire joue un rôle clé. Avoir trop d’un produit en stock signifie des produits non vendus assis sur les étagères ne produisant aucun chiffre d’affaires. Le fait d’avoir un produit trop petit conduit à des ventes perdues et des clients achetant auprès des concurrents. Par conséquent, la question constante est, quelle est la quantité optimale d’inventaire à garder en main ? L’analyse des séries chronologiques permet de fournir une réponse à ces questions en examinant les données historiques, en identifiant les modèles et en utilisant ces informations pour prévoir des valeurs à un moment donné à l’avenir.
La technique d’analyse des données utilisées dans ce didacticiel est une analyse univariée des séries chronologiques. L’analyse de série chronologique univariée examine une seule observation numérique sur une période donnée à intervalles spécifiques, tels que les ventes mensuelles.
L’algorithme utilisé dans ce didacticiel est Singular Spectrum Analysis(SSA). SSA fonctionne en décomposant une série chronologique en un ensemble de composants principaux. Ces composants peuvent être interprétés comme les parties d’un signal qui correspondent aux tendances, au bruit, à la saisonnalité et à de nombreux autres facteurs. Ensuite, ces composants sont reconstruits et utilisés pour prévoir des valeurs à un moment donné.
Créer une application console
Créez une application console C# appelée « BikeDemandForecasting ». Cliquez sur le bouton Suivant .
Choisissez .NET 8 comme framework à utiliser. Cliquez sur le bouton Créer.
Installer la version de package NuGet Microsoft.ML
Note
Cet exemple utilise la dernière version stable des packages NuGet mentionnés, sauf indication contraire.
- Dans l’Explorateur de solutions, cliquez avec le bouton droit sur votre projet, puis sélectionnez Gérer les packages NuGet.
- Choisissez « nuget.org » comme source du package, sélectionnez l’onglet Parcourir, recherchezMicrosoft.ML.
- Cochez la case Inclure la préversion .
- Sélectionnez le bouton Installer.
- Sélectionnez le bouton OK dans la boîte de dialogue Aperçu des modifications , puis sélectionnez le bouton J’accepte dans la boîte de dialogue Acceptation de licence si vous acceptez les termes du contrat de licence pour les packages répertoriés.
- Répétez ces étapes pour System.Data.SqlClient et Microsoft.ML.TimeSeries.
Préparer et comprendre les données
- Créez un répertoire appelé Données.
- Téléchargez le fichier de base de données DailyDemand.mdf et enregistrez-le dans le répertoire de données.
Note
Les données utilisées dans ce tutoriel proviennent du jeu de données UCI Bike Sharing. Hadi Fanaee-T et João Gama, « Étiquetage d'événements en combinant des détecteurs ensemblistes et des connaissances de fond », Progress in Artificial Intelligence (2013) : pp. 1-15, Springer Berlin Heidelberg, Lien Web.
Le jeu de données d’origine contient plusieurs colonnes correspondant à la saisonnalité et au temps. Pour la concision et parce que l’algorithme utilisé dans ce didacticiel nécessite uniquement les valeurs d’une seule colonne numérique, le jeu de données d’origine a été condensé pour inclure uniquement les colonnes suivantes :
- dteday : Date de l’observation.
- année : année codée de l’observation (0=2011, 1=2012).
- cnt : Nombre total de locations de vélos pour cette journée.
Le jeu de données d’origine est mappé à une table de base de données avec le schéma suivant dans une base de données SQL Server.
CREATE TABLE [Rentals] (
[RentalDate] DATE NOT NULL,
[Year] INT NOT NULL,
[TotalRentals] INT NOT NULL
);
Voici un exemple de données :
| LocationDate | Année | TotalRentals |
|---|---|---|
| 1/1/2011 | 0 | 985 |
| 1/2/2011 | 0 | 801 |
| 1/3/2011 | 0 | 1349 |
Créer des classes d’entrée et de sortie
Ouvrez Program.cs fichier et remplacez les directives existantes
usingpar les éléments suivants :using Microsoft.ML; using Microsoft.ML.Data; using Microsoft.ML.Transforms.TimeSeries; using System.Data.SqlClient;Créez une
ModelInputclasse. En dessous de laProgramclasse, ajoutez le code suivant.public class ModelInput { public DateTime RentalDate { get; set; } public float Year { get; set; } public float TotalRentals { get; set; } }La
ModelInputclasse contient les colonnes suivantes :- LocationDate : date de l’observation.
- Année : année encodée de l’observation (0=2011, 1=2012).
- TotalRentals : Nombre total de locations de vélos pour cette journée.
Créez une
ModelOutputclasse sous la classe nouvellement crééeModelInput.public class ModelOutput { public float[] ForecastedRentals { get; set; } public float[] LowerBoundRentals { get; set; } public float[] UpperBoundRentals { get; set; } }La
ModelOutputclasse contient les colonnes suivantes :- ForecastedRentals : valeurs prédites pour la période prévue.
- LowerBoundRentals : valeurs minimales prédites pour la période prévue.
- UpperBoundRentals : valeurs maximales prédites pour la période prévue.
Définir des chemins d’accès et initialiser des variables
Sous les
usingdirectives, définissez des variables pour stocker l’emplacement de vos données, chaîne de connexion et où enregistrer le modèle entraîné.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;";Initialisez la variable
mlContextavec une nouvelle instance deMLContexten ajoutant la ligne suivante après avoir défini les chemins d'accès.MLContext mlContext = new MLContext();La
MLContextclasse est un point de départ pour toutes les opérations de ML.NET, et l’initialisation de mlContext crée un environnement ML.NET qui peut être partagé entre les objets de flux de travail de création de modèle. Il est similaire, conceptuellement, àDBContextentity Framework.
Chargement des données
Créez
DatabaseLoaderqui charge les enregistrements de typeModelInput.DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();Définissez la requête pour charger les données à partir de la base de données.
string query = "SELECT RentalDate, CAST(Year as REAL) as Year, CAST(TotalRentals as REAL) as TotalRentals FROM Rentals";ML.NET algorithmes s’attendent à ce que les données soient de type
Single. Par conséquent, les valeurs numériques provenant de la base de données qui ne sont pas de typeReal, une valeur à virgule flottante simple précision doivent être converties enReal.Les colonnes et
YearlesTotalRentaltypes entiers sont tous deux dans la base de données. À l’aide de laCASTfonction intégrée, ils sont tous les deux castés enReal.Créez un
DatabaseSourceélément pour vous connecter à la base de données et exécuter la requête.DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance, connectionString, query);Chargez les données dans un
IDataView.IDataView dataView = loader.Load(dbSource);Le jeu de données contient deux années de données. Seules les données de la première année sont utilisées pour l’entraînement, la deuxième année est conservée pour comparer les valeurs réelles par rapport aux prévisions produites par le modèle. Filtrez les données à l’aide de la
FilterRowsByColumntransformation.IDataView firstYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", upperBound: 1); IDataView secondYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", lowerBound: 1);Pour la première année, seules les valeurs de la
Yearcolonne inférieure à 1 sont sélectionnées en définissant leupperBoundparamètre sur 1. À l’inverse, pour la deuxième année, les valeurs supérieures ou égales à 1 sont sélectionnées en définissant lelowerBoundparamètre sur 1.
Définir un pipeline d’analyse de série chronologique
Définissez un pipeline qui utilise SsaForecastingEstimator pour prévoir des valeurs dans un jeu de données de série chronologique.
var forecastingPipeline = mlContext.Forecasting.ForecastBySsa( outputColumnName: "ForecastedRentals", inputColumnName: "TotalRentals", windowSize: 7, seriesLength: 30, trainSize: 365, horizon: 7, confidenceLevel: 0.95f, confidenceLowerBoundColumn: "LowerBoundRentals", confidenceUpperBoundColumn: "UpperBoundRentals");forecastingPipelineprend 365 points de données pour la première année et échantillonne ou fractionne la série chronologique en intervalles de 30 jours (mensuels), comme spécifié par le paramètreseriesLength. Chacun de ces échantillons est analysé par semaine ou par une fenêtre de 7 jours. Lorsque vous déterminez la valeur prévue pour la ou les périodes suivantes, les valeurs des sept jours précédents sont utilisées pour effectuer une prédiction. Le modèle est défini pour prévoir sept périodes à l’avenir, comme défini par lehorizonparamètre. Étant donné qu’une prévision est une estimation informée, il n’est pas toujours 100% précis. Par conséquent, il est judicieux de connaître la plage de valeurs dans les meilleurs scénarios et les pires scénarios, tels que définis par les limites supérieures et inférieures. Dans ce cas, le niveau de confiance pour les limites inférieures et supérieures est défini sur 95%. Le niveau de confiance peut être augmenté ou diminué en conséquence. Plus la valeur est élevée, plus la plage est comprise entre les limites supérieures et inférieures pour atteindre le niveau de confiance souhaité.Utilisez la
Fitméthode pour entraîner le modèle et ajuster les données à l’élément définiforecastingPipelineprécédemment.SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
Évaluer le modèle
Évaluez le niveau de performance du modèle en prévision des données de l’année prochaine et en la comparant aux valeurs réelles.
Créez une méthode utilitaire appelée
Evaluateen bas du fichier Program.cs .Evaluate(IDataView testData, ITransformer model, MLContext mlContext) { }À l’intérieur de la
Evaluateméthode, prévoyez les données de la deuxième année à l’aide de laTransformméthode avec le modèle entraîné.IDataView predictions = model.Transform(testData);Obtenez les valeurs réelles des données à l’aide de la
CreateEnumerableméthode.IEnumerable<float> actual = mlContext.Data.CreateEnumerable<ModelInput>(testData, true) .Select(observed => observed.TotalRentals);Obtenez les valeurs de prévision à l’aide de la
CreateEnumerableméthode.IEnumerable<float> forecast = mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true) .Select(prediction => prediction.ForecastedRentals[0]);Calculez la différence entre les valeurs réelles et les valeurs de prévision, communément appelées erreur.
var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);Mesurez les performances en calculant les valeurs d’erreur moyenne absolue et d’erreur moyenne moyenne racine.
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 ErrorPour évaluer les performances, les métriques suivantes sont utilisées :
- Erreur absolue moyenne : mesure la proximité des prédictions à la valeur réelle. Cette valeur est comprise entre 0 et infini. Plus près de 0, plus la qualité du modèle est meilleure.
- Erreur carrée moyenne racine : récapitule l’erreur dans le modèle. Cette valeur est comprise entre 0 et infini. Plus près de 0, plus la qualité du modèle est meilleure.
Affichez les métriques dans la console.
Console.WriteLine("Evaluation Metrics"); Console.WriteLine("---------------------"); Console.WriteLine($"Mean Absolute Error: {MAE:F3}"); Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");Appelez la
Evaluateméthode ci-dessous en appelant laFit()méthode.Evaluate(secondYearData, forecaster, mlContext);
Enregistrer le modèle
Si vous êtes satisfait de votre modèle, enregistrez-le pour une utilisation ultérieure dans d’autres applications.
Sous la
Evaluate()méthode, créez unTimeSeriesPredictionEngine.TimeSeriesPredictionEngineest une méthode pratique pour effectuer des prédictions uniques.var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);Enregistrez le modèle dans un fichier appelé
MLModel.zipcomme spécifié par la variable précédemment définiemodelPath. Utilisez laCheckpointméthode pour enregistrer le modèle.forecastEngine.CheckPoint(mlContext, modelPath);
Utiliser le modèle pour prévoir la demande
Sous la
Evaluateméthode, créez une méthode utilitaire appeléeForecast.void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext) { }À l’intérieur de la
Forecastméthode, utilisez laPredictméthode pour prévoir les locations pour les sept prochains jours.ModelOutput forecast = forecaster.Predict();Aligner les valeurs réelles et de prévision pendant sept périodes.
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"; });Effectuez une itération dans la sortie de prévision et affichez-la sur la console.
Console.WriteLine("Rental Forecast"); Console.WriteLine("---------------------"); foreach (var prediction in forecastOutput) { Console.WriteLine(prediction); }
Exécuter l’application
Sous l’appel de la
Checkpoint()méthode, appelez laForecastméthode.Forecast(secondYearData, 7, forecastEngine, mlContext);Exécutez l’application. La sortie similaire à celle ci-dessous doit apparaître sur la console. Par souci de concision, la sortie a été condensée.
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
L’inspection des valeurs réelles et prévues présente les relations suivantes :
Bien que les valeurs prévues ne prédisent pas le nombre exact de locations, elles fournissent une plage de valeurs plus étroite qui permet à une opération d’optimiser leur utilisation des ressources.
Félicitations! Vous avez maintenant créé un modèle Machine Learning de série chronologique pour prévoir la demande de location de vélos.
Vous trouverez le code source de ce didacticiel dans le référentiel dotnet/machinelearning-samples .