Share via


Zelfstudie: Vraag naar fietsverhuur voorspellen met tijdreeksanalyse en ML.NET

Meer informatie over het voorspellen van de vraag naar een fietsverhuurservice met behulp van een univariate tijdreeksanalyse op gegevens die zijn opgeslagen in een SQL Server-database met ML.NET.

In deze zelfstudie leert u het volgende:

  • Inzicht in het probleem
  • Gegevens laden uit een database
  • Een prognosemodel maken
  • Prognosemodel evalueren
  • Een prognosemodel opslaan
  • Een prognosemodel gebruiken

Vereisten

Voorbeeld van tijdreeksprognose

Dit voorbeeld is een C# .NET Core-consoletoepassing die de vraag naar fietsverhuur voorspelt met behulp van een univariate tijdreeksanalyse-algoritme dat bekend staat als Singular Spectrum Analysis. De code voor dit voorbeeld vindt u in de opslagplaats dotnet/machinelearning-samples op GitHub.

Inzicht in het probleem

Om een efficiënte bewerking uit te voeren, speelt voorraadbeheer een belangrijke rol. Als er te veel van een product op voorraad is, betekent dit dat onverkochte producten in de schappen geen omzet genereren. Als u te weinig producten hebt, leidt dit tot verloren verkoop en aankopen van klanten bij concurrenten. Daarom is de constante vraag, wat is de optimale hoeveelheid voorraad om bij de hand te houden? Tijdreeksanalyse biedt een antwoord op deze vragen door naar historische gegevens te kijken, patronen te identificeren en deze informatie te gebruiken om waarden enige tijd in de toekomst te voorspellen.

De techniek voor het analyseren van gegevens die in deze zelfstudie worden gebruikt, is een univariate tijdreeksanalyse. Bij een niet-variabele tijdreeksanalyse wordt gekeken naar één numerieke waarneming gedurende een bepaalde periode, zoals de maandelijkse verkoop.

Het algoritme dat in deze zelfstudie wordt gebruikt, is Singular Spectrum Analysis (SSA). SSA werkt door een tijdreeks op te splitsen in een set principal-onderdelen. Deze onderdelen kunnen worden geïnterpreteerd als de onderdelen van een signaal die overeenkomen met trends, ruis, seizoensgebondenheid en vele andere factoren. Vervolgens worden deze onderdelen gereconstrueerd en gebruikt om in de toekomst waarden te voorspellen.

Consoletoepassing maken

  1. Maak een C# -consoletoepassing met de naam BikeDemandForecasting. Klik op de knop Next

  2. Kies .NET 6 als het framework dat u wilt gebruiken. Klik op de knop Maken.

  3. NuGet-pakket Microsoft.ML versie installeren

    Notitie

    In dit voorbeeld wordt de meest recente stabiele versie van de genoemde NuGet-pakketten gebruikt, tenzij anders vermeld.

    1. Klik in Solution Explorer met de rechtermuisknop op uw project en selecteer NuGet-pakketten beheren.
    2. Kies 'nuget.org' als pakketbron, selecteer het tabblad Bladeren en zoek naar Microsoft.ML.
    3. Schakel het selectievakje Voorlopige versie opnemen in.
    4. Selecteer de knop Installeren .
    5. Selecteer de knop OK in het dialoogvenster Voorbeeld van wijzigingen en selecteer vervolgens de knop Ik ga akkoord in het dialoogvenster Licentie-acceptatie als u akkoord gaat met de licentievoorwaarden voor de vermelde pakketten.
    6. Herhaal deze stappen voor System.Data.SqlClient en Microsoft.ML.TimeSeries.

De gegevens voorbereiden en begrijpen

  1. Maak een map met de naam Gegevens.
  2. Download het databasebestand DailyDemand.mdf en sla het op in de map Data.

Notitie

De gegevens die in deze zelfstudie worden gebruikt, zijn afkomstig van de UCI Bike Sharing Dataset. 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.

De oorspronkelijke gegevensset bevat verschillende kolommen die overeenkomen met seizoensgebondenheid en weer. Voor de beknoptheid en omdat voor het algoritme dat in deze zelfstudie wordt gebruikt, alleen de waarden uit één numerieke kolom zijn vereist, is de oorspronkelijke gegevensset ingekort om alleen de volgende kolommen op te nemen:

  • dteday: de datum van de waarneming.
  • year: Het gecodeerde jaar van de waarneming (0=2011, 1=2012).
  • cnt: Het totale aantal fietsverhuur voor die dag.

De oorspronkelijke gegevensset is toegewezen aan een databasetabel met het volgende schema in een SQL Server database.

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

Hier volgt een voorbeeld van de gegevens:

RentalDate Year TotalRentals
1/1/2011 0 985
1/2/2011 0 801
1/3/2011 0 1349

Invoer- en uitvoerklassen maken

  1. Open het bestand Program.cs en vervang de bestaande using instructies door het volgende:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    using System.Data.SqlClient;
    
  2. Maak de klasse ModelInput. Voeg onder de Program klasse de volgende code toe.

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

    De ModelInput klasse bevat de volgende kolommen:

    • RentalDate: De datum van de waarneming.
    • Year: Het gecodeerde jaar van de waarneming (0=2011, 1=2012).
    • TotalRentals: Het totale aantal fietsverhuur voor die dag.
  3. Maak ModelOutput een klasse onder de zojuist gemaakte ModelInput klasse.

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

    De ModelOutput klasse bevat de volgende kolommen:

    • ForecastedRentals: de voorspelde waarden voor de voorspelde periode.
    • LowerBoundRentals: de voorspelde minimumwaarden voor de voorspelde periode.
    • UpperBoundRentals: de voorspelde maximumwaarden voor de voorspelde periode.

Paden definiëren en variabelen initialiseren

  1. Definieer onder de using-instructies variabelen voor het opslaan van de locatie van uw gegevens, connection string en waar het getrainde model moet worden opgeslagen.

    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. Initialiseer de mlContext variabele met een nieuw exemplaar van MLContext door de volgende regel toe te voegen nadat u de paden hebt gedefinieerd.

    MLContext mlContext = new MLContext();
    

    De MLContext klasse is een startpunt voor alle ML.NET bewerkingen. Als u mlContext initialiseert, wordt er een nieuwe ML.NET omgeving gemaakt die kan worden gedeeld met de werkstroomobjecten voor het maken van modellen. Het is conceptueel DBContext vergelijkbaar met in Entity Framework.

De gegevens laden

  1. Maak die DatabaseLoader records van het type ModelInputlaadt.

    DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();
    
  2. Definieer de query om de gegevens uit de database te laden.

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

    ML.NET algoritmen verwachten dat gegevens van het type Singlezijn. Daarom moeten numerieke waarden die afkomstig zijn uit de database die niet van het type Realzijn, een drijvendekommawaarde met één precisie, worden geconverteerd naar Real.

    De Year kolommen en TotalRental zijn beide typen gehele getallen in de database. Met behulp van de CAST ingebouwde functie worden ze beide cast naar Real.

  3. Maak een DatabaseSource om verbinding te maken met de database en voer de query uit.

    DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance,
                                    connectionString,
                                    query);
    
  4. Laad de gegevens in een IDataView.

    IDataView dataView = loader.Load(dbSource);
    
  5. De gegevensset bevat twee jaar aan gegevens. Alleen gegevens van het eerste jaar worden gebruikt voor de training, het tweede jaar wordt gebruikt om de werkelijke waarden te vergelijken met de prognose die door het model wordt geproduceerd. Filter de gegevens met behulp van de FilterRowsByColumn transformatie.

    IDataView firstYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", upperBound: 1);
    IDataView secondYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", lowerBound: 1);
    

    Voor het eerste jaar worden alleen de waarden in de Year kolom kleiner dan 1 geselecteerd door de upperBound parameter in te stellen op 1. Omgekeerd worden voor het tweede jaar waarden groter dan of gelijk aan 1 geselecteerd door de lowerBound parameter in te stellen op 1.

Pijplijn voor tijdreeksanalyse definiëren

  1. Definieer een pijplijn die gebruikmaakt van de SsaForecastingEstimator om waarden in een tijdreeksgegevensset te voorspellen.

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

    De forecastingPipeline neemt 365 gegevenspunten voor het eerste jaar en steekt de tijdreeksgegevensset op in intervallen van 30 dagen (maandelijks), zoals opgegeven door de seriesLength parameter. Elk van deze voorbeelden wordt geanalyseerd via een wekelijks of een periode van 7 dagen. Bij het bepalen van de voorspelde waarde voor de volgende periode(en), worden de waarden van de afgelopen zeven dagen gebruikt om een voorspelling te doen. Het model is ingesteld om zeven perioden in de toekomst te voorspellen, zoals gedefinieerd door de horizon parameter . Omdat een prognose een geïnformeerde schatting is, is deze niet altijd 100% nauwkeurig. Daarom is het goed om het bereik van waarden in de beste en slechtste scenario's te kennen, zoals gedefinieerd door de boven- en ondergrens. In dit geval wordt het betrouwbaarheidsniveau voor de onder- en bovengrens ingesteld op 95%. Het betrouwbaarheidsniveau kan dienovereenkomstig worden verhoogd of verlaagd. Hoe hoger de waarde, hoe breder het bereik is tussen de boven- en ondergrens om het gewenste betrouwbaarheidsniveau te bereiken.

  2. Gebruik de Fit methode om het model te trainen en de gegevens aan te passen aan de eerder gedefinieerde forecastingPipeline.

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
    

Het model evalueren

Evalueer hoe goed het model presteert door de gegevens van het volgende jaar te voorspellen en deze te vergelijken met de werkelijke waarden.

  1. Maak een nieuwe hulpprogrammamethode met de naam Evaluate onderaan het bestand Program.cs .

    Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
    {
    
    }
    
  2. Binnen de Evaluate methode kunt u de gegevens van het tweede jaar voorspellen met behulp van de Transform methode met het getrainde model.

    IDataView predictions = model.Transform(testData);
    
  3. Haal de werkelijke waarden op uit de gegevens met behulp van de CreateEnumerable -methode.

    IEnumerable<float> actual =
        mlContext.Data.CreateEnumerable<ModelInput>(testData, true)
            .Select(observed => observed.TotalRentals);
    
  4. Haal de prognosewaarden op met behulp van de CreateEnumerable -methode.

    IEnumerable<float> forecast =
        mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true)
            .Select(prediction => prediction.ForecastedRentals[0]);
    
  5. Bereken het verschil tussen de werkelijke waarden en de prognosewaarden, ook wel de fout genoemd.

    var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);
    
  6. Meet de prestaties door de waarden Gemiddelde absolute fout en Wortel gemiddelde kwadratische fout te berekenen.

    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
    

    Voor het evalueren van de prestaties worden de volgende metrische gegevens gebruikt:

    • Gemiddelde absolute fout: meet hoe dicht voorspellingen bij de werkelijke waarde liggen. Deze waarde ligt tussen 0 en oneindig. Hoe dichter bij 0, hoe beter de kwaliteit van het model.
    • Root Mean Squared Error: geeft een overzicht van de fout in het model. Deze waarde ligt tussen 0 en oneindig. Hoe dichter bij 0, hoe beter de kwaliteit van het model.
  7. Voer de metrische gegevens uit naar de console.

    Console.WriteLine("Evaluation Metrics");
    Console.WriteLine("---------------------");
    Console.WriteLine($"Mean Absolute Error: {MAE:F3}");
    Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");
    
  8. Roep de Evaluate onderstaande methode aan en roep de methode aan Fit() .

    Evaluate(secondYearData, forecaster, mlContext);
    

Het model opslaan

Als u tevreden bent met uw model, slaat u het op voor later gebruik in andere toepassingen.

  1. Maak onder de Evaluate() methode een TimeSeriesPredictionEngine. TimeSeriesPredictionEngine is een handige methode om enkele voorspellingen te doen.

    var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
    
  2. Sla het model op in een bestand met de naam MLModel.zip zoals opgegeven door de eerder gedefinieerde modelPath variabele. Gebruik de Checkpoint methode om het model op te slaan.

    forecastEngine.CheckPoint(mlContext, modelPath);
    

Het model gebruiken om de vraag te voorspellen

  1. Maak onder de Evaluate methode een nieuwe hulpprogrammamethode met de naam Forecast.

    void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext)
    {
    
    }
    
  2. Gebruik in de Forecast methode de methode om de Predict huurperiode voor de komende zeven dagen te voorspellen.

    ModelOutput forecast = forecaster.Predict();
    
  3. Lijn de werkelijke waarden en de prognosewaarden voor zeven perioden uit.

    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. Doorloop de uitvoer van de prognose en geef deze weer op de console.

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

De toepassing uitvoeren

  1. Roep de methode aan onder het Checkpoint() aanroepen van de Forecast methode.

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. Voer de toepassing uit. Uitvoer die vergelijkbaar is met de onderstaande moet worden weergegeven op de console. Kortheidshalve is de uitvoer ingekort.

    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
    

Inspectie van de werkelijke en geraamde waarden toont de volgende relaties:

Vergelijking werkelijke versus prognose

Hoewel de voorspelde waarden niet het exacte aantal huurwoningen voorspellen, bieden ze een smaller bereik van waarden waarmee een bewerking het gebruik van resources kan optimaliseren.

Gefeliciteerd U hebt nu een machine learning-model voor tijdreeksen gebouwd om de vraag naar fietsverhuur te voorspellen.

U vindt de broncode voor deze zelfstudie in de opslagplaats dotnet/machinelearning-samples .

Volgende stappen