Didacticiel : prévoir la demande du service de location de vélos avec l’analyse de série chronologique et ML.NETTutorial: Forecast bike rental service demand with time series analysis and ML.NET

Découvrez comment prévoir la demande d’un service de location de bicyclettes à l’aide de l’analyse de série chronologique Student sur les données stockées dans une base de données SQL Server avec ML.NET.Learn how to forecast demand for a bike rental service using univariate time series analysis on data stored in a SQL Server database with ML.NET.

Dans ce tutoriel, vous allez apprendre à :In this tutorial, you learn how to:

  • Comprendre le problèmeUnderstand the problem
  • Charger des données à partir d’une base de donnéesLoad data from a database
  • Créer un modèle de prévisionCreate a forecasting model
  • Évaluer le modèle de prévisionEvaluate forecasting model
  • Enregistrer un modèle de prévisionSave a forecasting model
  • Utiliser un modèle de prévisionUse a forecasting model

PrérequisPrerequisites

  • Visual studio 2019 ou version ultérieure ou visual studio 2017 version 15,6 ou ultérieure avec la charge de travail « développement multiplateforme .net Core » installée.Visual Studio 2019 or later or Visual Studio 2017 version 15.6 or later with the ".NET Core cross-platform development" workload installed.

Vue d’ensemble de l’exemple de prévision de séries chronologiquesTime series forecasting sample overview

Cet exemple est une application console C# .net Core qui prévoit la demande de loyers de bicyclettes à l’aide d’un algorithme d’analyse de série chronologique Student appelé analyse du spectre singulier.This sample is a C# .NET Core console application that forecasts demand for bike rentals using a univariate time series analysis algorithm known as Singular Spectrum Analysis. Le code de cet exemple se trouve dans le référentiel dotnet/machinelearning-Samples sur GitHub.The code for this sample can be found on the dotnet/machinelearning-samples repository on GitHub.

Comprendre le problèmeUnderstand the problem

Pour exécuter une opération efficace, la gestion des stocks joue un rôle clé.In order to run an efficient operation, inventory management plays a key role. Le fait d’avoir une trop grande partie d’un produit en stock signifie que les produits invendus se trouvent sur les étagères qui ne génèrent aucun chiffre d’affaires.Having too much of a product in stock means unsold products sitting on the shelves not generating any revenue. Le fait d’avoir trop peu de prospects pour les ventes et les clients qui achètent des produits concurrents.Having too little product leads to lost sales and customers purchasing from competitors. Par conséquent, la question constante est, quelle est la quantité optimale d’inventaire à conserver en main ?Therefore, the constant question is, what is the optimal amount of inventory to keep on hand? L’analyse des séries chronologiques vous aide à fournir une réponse à ces questions en examinant les données d’historique, en identifiant les modèles et en utilisant ces informations pour prévoir des valeurs à un moment donné dans le futur.Time-series analysis helps provide an answer to these questions by looking at historical data, identifying patterns, and using this information to forecast values some time in the future.

La technique d’analyse des données utilisée dans ce didacticiel est l’analyse de la série chronologique Student.The technique for analyzing data used in this tutorial is univariate time-series analysis. Les analyses de série chronologique Student examinent une seule observation numérique sur une période à des intervalles spécifiques tels que les ventes mensuelles.Univariate time-series analysis takes a look at a single numerical observation over a period of time at specific intervals such as monthly sales.

L’algorithme utilisé dans ce didacticiel est l' analyse du spectre singulier (SSA).The algorithm used in this tutorial is Singular Spectrum Analysis(SSA). La SSA fonctionne en décomposant une série chronologique en un ensemble de composants principaux.SSA works by decomposing a time-series into a set of principal components. Ces composants peuvent être interprétés comme les parties d’un signal qui correspondent aux tendances, au bruit, au caractère saisonnier et à de nombreux autres facteurs.These components can be interpreted as the parts of a signal that correspond to trends, noise, seasonality, and many other factors. Ensuite, ces composants sont reconstruits et utilisés pour prévoir des valeurs à un moment donné dans le futur.Then, these components are reconstructed and used to forecast values some time in the future.

Création d’une application de consoleCreate console application

  1. Créez une nouvelle application console C# .net Core appelée « BikeDemandForecasting ».Create a new C# .NET Core console application called "BikeDemandForecasting".

  2. Installer le package NuGet de la version Microsoft.mlInstall Microsoft.ML version NuGet package

    Notes

    Cet exemple utilise la dernière version stable des packages NuGet mentionnés, sauf indication contraire.This sample uses the latest stable version of the NuGet packages mentioned unless otherwise stated.

    1. Dans Explorateur de solutions, cliquez avec le bouton droit sur votre projet et sélectionnez gérer les packages NuGet.In Solution Explorer, right-click on your project and select Manage NuGet Packages.
    2. Choisissez « nuget.org » comme source du package, sélectionnez l’onglet Parcourir , puis recherchez Microsoft.ml.Choose "nuget.org" as the Package source, select the Browse tab, search for Microsoft.ML.
    3. Cochez la case inclure la version préliminaire .Check the Include prerelease checkbox.
    4. Sélectionnez le bouton Installer.Select the Install button.
    5. Cliquez sur le bouton OK dans la boîte de dialogue Aperçu des modifications, puis sur le bouton J’accepte dans la boîte de dialogue Acceptation de la licence si vous acceptez les termes du contrat de licence pour les packages répertoriés.Select the OK button on the Preview Changes dialog and then select the I Accept button on the License Acceptance dialog if you agree with the license terms for the packages listed.
    6. Répétez ces étapes pour System. Data. SqlClient et Microsoft. ml. TimeSeries.Repeat these steps for System.Data.SqlClient and Microsoft.ML.TimeSeries.

Préparer et comprendre les donnéesPrepare and understand the data

  1. Créez un répertoire nommé Data.Create a directory called Data.
  2. Téléchargez le fichier de base de données DailyDemand. mdf et enregistrez-le dans le répertoire de données .Download the DailyDemand.mdf database file and save it to the Data directory.

Notes

Les données utilisées dans ce didacticiel proviennent du jeu de données de partage de bicyclette UCI.The data used in this tutorial comes from the UCI Bike Sharing Dataset. Fanaee-T, Hadi et Gama, Joao, 'étiquetage des événements combinaison de détecteurs d’ensembles et de connaissances en arrière-plan', progression de l’intelligence artificielle (2013) : pp. 1-15, Springer Link Berlin Heidelberg, lien Web.Fanaee-T, Hadi, and Gama, Joao, 'Event labeling combining ensemble detectors and background knowledge', Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg, Web Link.

Le jeu de données d’origine contient plusieurs colonnes correspondant à caractère saisonnier et météo.The original dataset contains several columns corresponding to seasonality and weather. Par souci de concision et parce que l’algorithme utilisé dans ce didacticiel nécessite uniquement les valeurs d’une colonne numérique unique, le jeu de données d’origine a été condensé pour inclure uniquement les colonnes suivantes :For brevity and because the algorithm used in this tutorial only requires the values from a single numerical column, the original dataset has been condensed to include only the following columns:

  • dteday: date de l’observation.dteday: The date of the observation.
  • year: année encodée de l’observation (0 = 2011, 1 = 2012).year: The encoded year of the observation (0=2011, 1=2012).
  • CNT: nombre total d’loyers de bicyclettes pour ce jour-là.cnt: The total number of bike rentals for that day.

Le DataSet d’origine est mappé à une table de base de données avec le schéma suivant dans une base de données SQL Server.The original dataset is mapped to a database table with the following schema in a SQL Server database.

CREATE TABLE [Rentals] (
    [RentalDate] DATE NOT NULL,
    [Year] INT NOT NULL,
    [TotalRentals] INT NOT NULL
);

Voici un exemple de données :The following is a sample of the data:

RentalDateRentalDate YearYear TotalRentalsTotalRentals
1/1/20111/1/2011 00 985985
1/2/20111/2/2011 00 801801
1/3/20111/3/2011 00 13491349

Créer des classes d’entrée et de sortieCreate input and output classes

  1. Ouvrez le fichier Program.cs et remplacez les using instructions existantes par ce qui suit :Open Program.cs file and replace the existing using statements with the following:

    using System;
    using System.Collections.Generic;
    using System.Data.SqlClient;
    using System.IO;
    using System.Linq;
    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    
  2. Créez la classe ModelInput.Create ModelInput class. Sous la Program classe, ajoutez le code suivant.Below the Program class, add the following code.

    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 :The ModelInput class contains the following columns:

    • RentalDate: date de l’observation.RentalDate: The date of the observation.
    • Year: année encodée de l’observation (0 = 2011, 1 = 2012).Year: The encoded year of the observation (0=2011, 1=2012).
    • TotalRentals: nombre total de loyers de vélo pour ce jour-là.TotalRentals: The total number of bike rentals for that day.
  3. Créez ModelOutput la classe sous la classe nouvellement créée ModelInput .Create ModelOutput class below the newly created ModelInput class.

    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 :The ModelOutput class contains the following columns:

    • ForecastedRentals: valeurs prédites pour la période prévue.ForecastedRentals: The predicted values for the forecasted period.
    • LowerBoundRentals: valeurs minimales prédites pour la période prévue.LowerBoundRentals: The predicted minimum values for the forecasted period.
    • UpperBoundRentals: valeurs maximales prédites pour la période prévue.UpperBoundRentals: The predicted maximum values for the forecasted period.

Définir des chemins d’accès et initialiser des variablesDefine paths and initialize variables

  1. À l’intérieur de la Main méthode, définissez des variables pour stocker l’emplacement de vos données, la chaîne de connexion et l’emplacement où enregistrer le modèle formé.Inside the Main method, define variables to store the location of your data, connection string, and where to save the trained model.

    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 mlContext variable avec une nouvelle instance de MLContext en ajoutant la ligne suivante à la Main méthode.Initialize the mlContext variable with a new instance of MLContext by adding the following line to the Main method.

    MLContext mlContext = new MLContext();
    

    La MLContext classe est un point de départ pour toutes les opérations ml.net et l’initialisation de mlContext crée un nouvel environnement ml.net qui peut être partagé entre les objets de flux de travail de création de modèle.The MLContext class is a starting point for all ML.NET operations, and initializing mlContext creates a new ML.NET environment that can be shared across the model creation workflow objects. Sur le plan conceptuel, elle est similaire à DBContext dans Entity Framework.It's similar, conceptually, to DBContext in Entity Framework.

Chargement des donnéesLoad the data

  1. Créer DatabaseLoader qui charge les enregistrements de type ModelInput .Create DatabaseLoader that loads records of 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.Define the query to load the data from the database.

    string query = "SELECT RentalDate, CAST(Year as REAL) as Year, CAST(TotalRentals as REAL) as TotalRentals FROM Rentals";
    

    Les algorithmes ML.NET attendent que les données soient de type Single .ML.NET algorithms expect data to be of 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 .Therefore, numerical values coming from the database that are not of type Real, a single-precision floating-point value, have to be converted to Real.

    Les Year TotalRental colonnes et sont toutes deux des types entiers dans la base de données.The Year and TotalRental columns are both integer types in the database. À l’aide de la CAST fonction intégrée, elles sont toutes deux converties en Real .Using the CAST built-in function, they are both cast to Real.

  3. Créez un DatabaseSource pour vous connecter à la base de données et exécuter la requête.Create a DatabaseSource to connect to the database and execute the query.

    DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance,
                                    connectionString,
                                    query);
    
  4. Chargez les données dans un IDataView.Load the data into an IDataView.

    IDataView dataView = loader.Load(dbSource);
    
  5. Le jeu de données contient deux années de données.The dataset contains two years worth of data. Seules les données de la première année sont utilisées pour l’apprentissage, la deuxième année est conservée pour comparer les valeurs réelles par rapport aux prévisions produites par le modèle.Only data from the first year is used for training, the second year is held out to compare the actual values against the forecast produced by the model. Filtrer les données à l’aide de la FilterRowsByColumn transformation.Filter the data using the FilterRowsByColumn transform.

    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 affectant la valeur upperBound 1 au paramètre.For the first year, only the values in the Year column less than 1 are selected by setting the upperBound parameter to 1. À l’inverse, pour la deuxième année, les valeurs supérieures ou égales à 1 sont sélectionnées en affectant la valeur lowerBound 1 au paramètre.Conversely, for the second year, values greater than or equal to 1 are selected by setting the lowerBound parameter to 1.

Définir le pipeline d’analyse de série chronologiqueDefine time series analysis pipeline

  1. Définissez un pipeline qui utilise SsaForecastingEstimator pour prévoir des valeurs dans un jeu de données de série chronologique.Define a pipeline that uses the SsaForecastingEstimator to forecast values in a time-series dataset.

    var forecastingPipeline = mlContext.Forecasting.ForecastBySsa(
        outputColumnName: "ForecastedRentals",
        inputColumnName: "TotalRentals",
        windowSize: 7,
        seriesLength: 30,
        trainSize: 365,
        horizon: 7,
        confidenceLevel: 0.95f,
        confidenceLowerBoundColumn: "LowerBoundRentals",
        confidenceUpperBoundColumn: "UpperBoundRentals");
    

    Le forecastingPipeline prend 365 points de données pour la première année et échantillonne ou divise le jeu de données de série chronologique en intervalles de 30 jours (mensuels), comme spécifié par le seriesLength paramètre.The forecastingPipeline takes 365 data points for the first year and samples or splits the time-series dataset into 30-day (monthly) intervals as specified by the seriesLength parameter. Chacun de ces exemples est analysé par une fenêtre hebdomadaire ou de 7 jours.Each of these samples is analyzed through weekly or a 7-day window. Lors de la détermination de 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.When determining what the forecasted value for the next period(s) is, the values from previous seven days are used to make a prediction. Le modèle est défini pour prévoir sept périodes dans le futur, comme défini par le horizon paramètre.The model is set to forecast seven periods into the future as defined by the horizon parameter. Comme une prévision est une estimation réfléchie, elle n’est pas toujours de 100% précise.Because a forecast is an informed guess, it's not always 100% accurate. Par conséquent, il est bon de connaître la plage de valeurs dans les scénarios les plus perversaux et les plus pessimistes, comme défini par les limites supérieure et inférieure.Therefore, it's good to know the range of values in the best and worst-case scenarios as defined by the upper and lower bounds. Dans ce cas, le niveau de confiance pour les limites inférieure et supérieure est défini sur 95%.In this case, the level of confidence for the lower and upper bounds is set to 95%. Le niveau de confiance peut être augmenté ou réduit en conséquence.The confidence level can be increased or decreased accordingly. Plus la valeur est élevée, plus la plage est large entre les limites supérieure et inférieure pour atteindre le niveau de confiance souhaité.The higher the value, the wider the range is between the upper and lower bounds to achieve the desired level of confidence.

  2. Utilisez la Fit méthode pour former le modèle et ajuster les données au précédemment défini forecastingPipeline .Use the Fit method to train the model and fit the data to the previously defined forecastingPipeline.

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
    

Évaluer le modèleEvaluate the model

Évaluez le comportement du modèle en prévoyant les données de l’année suivante et en les comparant aux valeurs réelles.Evaluate how well the model performs by forecasting next year's data and comparing it against the actual values.

  1. Sous la Main méthode, créez une nouvelle méthode utilitaire appelée Evaluate .Below the Main method, create a new utility method called Evaluate.

    static void Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
    {
    
    }
    
  2. À l’intérieur de la Evaluate méthode, planifiez les données de la deuxième année à l’aide de la Transform méthode avec le modèle formé.Inside the Evaluate method, forecast the second year's data by using the Transform method with the trained model.

    IDataView predictions = model.Transform(testData);
    
  3. Récupérez les valeurs réelles à partir des données à l’aide de la CreateEnumerable méthode.Get the actual values from the data by using the CreateEnumerable method.

    IEnumerable<float> actual =
        mlContext.Data.CreateEnumerable<ModelInput>(testData, true)
            .Select(observed => observed.TotalRentals);
    
  4. Récupérez les valeurs de prévision à l’aide de la CreateEnumerable méthode.Get the forecast values by using the CreateEnumerable method.

    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 ».Calculate the difference between the actual and forecast values, commonly referred to as the error.

    var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);
    
  6. Mesurez les performances en calculant les valeurs d’erreur absolue moyenne et quadratique moyenne.Measure performance by computing the Mean Absolute Error and Root Mean Squared Error values.

    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 :To evaluate performance, the following metrics are used:

    • Erreur absolue moyenne: mesure la manière dont les prédictions sont fermées à la valeur réelle.Mean Absolute Error: Measures how close predictions are to the actual value. Cette valeur est comprise entre 0 et l’infini.This value ranges between 0 and infinity. Plus la valeur est proche de 0, meilleure est la qualité du modèle.The closer to 0, the better the quality of the model.
    • Erreur du carré moyen racine: résume l’erreur dans le modèle.Root Mean Squared Error: Summarizes the error in the model. Cette valeur est comprise entre 0 et l’infini.This value ranges between 0 and infinity. Plus la valeur est proche de 0, meilleure est la qualité du modèle.The closer to 0, the better the quality of the model.
  7. Sortie des mesures vers la console.Output the metrics to the console.

    Console.WriteLine("Evaluation Metrics");
    Console.WriteLine("---------------------");
    Console.WriteLine($"Mean Absolute Error: {MAE:F3}");
    Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");
    
  8. Utilisez la Evaluate méthode à l’intérieur de la Main méthode.Use the Evaluate method inside the Main method.

    Evaluate(secondYearData, forecaster, mlContext);
    

Enregistrer le modèleSave the model

Si vous êtes satisfait de votre modèle, enregistrez-le pour une utilisation ultérieure dans d’autres applications.If you're satisfied with your model, save it for later use in other applications.

  1. Dans la Main méthode, créez un TimeSeriesPredictionEngine .In the Main method, create a TimeSeriesPredictionEngine. TimeSeriesPredictionEngine est une méthode pratique pour effectuer des prédictions uniques.TimeSeriesPredictionEngine is a convenience method to make single predictions.

    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 .Save the model to a file called MLModel.zip as specified by the previously defined modelPath variable. Utilisez la Checkpoint méthode pour enregistrer le modèle.Use the Checkpoint method to save the model.

    forecastEngine.CheckPoint(mlContext, modelPath);
    

Utiliser le modèle pour prévoir la demandeUse the model to forecast demand

  1. Sous la Evaluate méthode, créez une nouvelle méthode utilitaire appelée Forecast .Below the Evaluate method, create a new utility method called Forecast.

    static 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 loyers des sept prochains jours.Inside the Forecast method, use the Predict method to forecast rentals for the next seven days.

    ModelOutput forecast = forecaster.Predict();
    
  3. Alignez les valeurs réelles et les prévisions sur sept périodes.Align the actual and forecast values for seven periods.

    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. Itérez au sein de la sortie de la prévision et affichez-la sur la console.Iterate through the forecast output and display it on the console.

    Console.WriteLine("Rental Forecast");
    Console.WriteLine("---------------------");
    foreach (var prediction in forecastOutput)
    {
        Console.WriteLine(prediction);
    }
    

Exécution de l'applicationRun the application

  1. À l’intérieur de la Main méthode, appelez la Forecast méthode.Inside the Main method, call the Forecast method.

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. Exécutez l'application.Run the application. Une sortie semblable à celle ci-dessous doit apparaître sur la console.Output similar to that below should appear on the console. Par souci de concision, la sortie a été condensée.For brevity, the output has been condensed.

    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 montre les relations suivantes :Inspection of the actual and forecasted values shows the following relationships:

Comparaison entre les prévisions et les prévisions réelles

Bien que les valeurs prévues ne prédisent pas le nombre exact de loyers, elles fournissent une plage de valeurs plus étroite qui permet à une opération d’optimiser son utilisation des ressources.While the forecasted values are not predicting the exact number of rentals, they provide a more narrow range of values that allows an operation to optimize their use of resources.

Félicitations !Congratulations! Vous avez maintenant créé avec succès une série chronologique Machine Learning modèle pour prévoir la demande de location de bicyclette.You've now successfully built a time series machine learning model to forecast bike rental demand.

Vous pouvez trouver le code source de ce didacticiel dans le référentiel dotnet/machinelearning-Samples .You can find the source code for this tutorial at the dotnet/machinelearning-samples repository.

Étapes suivantesNext steps