Partager via


Tutoriel : Prévoir la demande de service de location de vélos avec l’analyse de série chronologique et ML.NET

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

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

  1. Créez une application console C# appelée « BikeDemandForecasting ». Cliquez sur le bouton Suivant .

  2. Choisissez .NET 8 comme framework à utiliser. Cliquez sur le bouton Créer.

  3. 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.

    1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur votre projet, puis sélectionnez Gérer les packages NuGet.
    2. Choisissez « nuget.org » comme source du package, sélectionnez l’onglet Parcourir, recherchezMicrosoft.ML.
    3. Cochez la case Inclure la préversion .
    4. Sélectionnez le bouton Installer.
    5. 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.
    6. Répétez ces étapes pour System.Data.SqlClient et Microsoft.ML.TimeSeries.

Préparer et comprendre les données

  1. Créez un répertoire appelé Données.
  2. 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

  1. Ouvrez Program.cs fichier et remplacez les directives existantes using par les éléments suivants :

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    using System.Data.SqlClient;
    
  2. Créez une ModelInput classe. En dessous de la Program classe, ajoutez le code suivant.

    public class ModelInput
    {
        public DateTime RentalDate { get; set; }
    
        public float Year { get; set; }
    
        public float TotalRentals { get; set; }
    }
    

    La ModelInput classe 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.
  3. Créez une ModelOutput classe sous la classe nouvellement créée ModelInput .

    public class ModelOutput
    {
        public float[] ForecastedRentals { get; set; }
    
        public float[] LowerBoundRentals { get; set; }
    
        public float[] UpperBoundRentals { get; set; }
    }
    

    La ModelOutput classe 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

  1. Sous les using directives, 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;";
    
  2. Initialisez la variable mlContext avec une nouvelle instance de MLContext en ajoutant la ligne suivante après avoir défini les chemins d'accès.

    MLContext mlContext = new MLContext();
    

    La MLContext classe 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, à DBContext entity Framework.

Chargement des données

  1. Créez DatabaseLoader qui charge les enregistrements de type ModelInput.

    DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();
    
  2. 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 type Real, une valeur à virgule flottante simple précision doivent être converties en Real.

    Les colonnes et Year les TotalRental types entiers sont tous deux dans la base de données. À l’aide de la CAST fonction intégrée, ils sont tous les deux castés en Real.

  3. 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);
    
  4. Chargez les données dans un IDataView.

    IDataView dataView = loader.Load(dbSource);
    
  5. 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 FilterRowsByColumn transformation.

    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 Year colonne inférieure à 1 sont sélectionnées en définissant le upperBound paramè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 le lowerBound paramètre sur 1.

Définir un pipeline d’analyse de série chronologique

  1. 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");
    

    forecastingPipeline prend 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ètre seriesLength. 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 le horizon paramè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é.

  2. Utilisez la Fit méthode pour entraîner le modèle et ajuster les données à l’élément défini forecastingPipelinepré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.

  1. Créez une méthode utilitaire appelée Evaluate en bas du fichier Program.cs .

    Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
    {
    
    }
    
  2. À l’intérieur de la Evaluate méthode, prévoyez les données de la deuxième année à l’aide de la Transform méthode avec le modèle entraîné.

    IDataView predictions = model.Transform(testData);
    
  3. Obtenez les valeurs réelles des données à l’aide de la CreateEnumerable méthode.

    IEnumerable<float> actual =
        mlContext.Data.CreateEnumerable<ModelInput>(testData, true)
            .Select(observed => observed.TotalRentals);
    
  4. Obtenez les valeurs de prévision à l’aide de la CreateEnumerable méthode.

    IEnumerable<float> forecast =
        mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true)
            .Select(prediction => prediction.ForecastedRentals[0]);
    
  5. 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);
    
  6. 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 Error
    

    Pour é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.
  7. 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");
    
  8. Appelez la Evaluate méthode ci-dessous en appelant la Fit() 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.

  1. Sous la Evaluate() méthode, créez un TimeSeriesPredictionEngine. TimeSeriesPredictionEngine est une méthode pratique pour effectuer des prédictions uniques.

    var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
    
  2. Enregistrez le modèle dans un fichier appelé MLModel.zip comme spécifié par la variable précédemment définie modelPath . Utilisez la Checkpoint méthode pour enregistrer le modèle.

    forecastEngine.CheckPoint(mlContext, modelPath);
    

Utiliser le modèle pour prévoir la demande

  1. Sous la Evaluate méthode, créez une méthode utilitaire appelée Forecast.

    void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext)
    {
    
    }
    
  2. À l’intérieur de la Forecast méthode, utilisez la Predict méthode pour prévoir les locations pour les sept prochains jours.

    ModelOutput forecast = forecaster.Predict();
    
  3. 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";
            });
    
  4. 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

  1. Sous l’appel de la Checkpoint() méthode, appelez la Forecast méthode.

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. 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 :

Comparaison réelle et prévision

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 .

Étapes suivantes