Oktatóanyag: Kerékpárkölcsönzési szolgáltatási igények előrejelzése idősorozat-elemzéssel és ML.NET

Megtudhatja, hogyan jelezheti előre a kerékpárkölcsönző szolgáltatás iránti keresletet egyváltozós idősor-elemzéssel egy SQL Server adatbázisban tárolt adatokon ML.NET.

Eben az oktatóanyagban az alábbiakkal fog megismerkedni:

  • A probléma ismertetése
  • Adatok betöltése adatbázisból
  • Előrejelzési modell létrehozása
  • Előrejelzési modell kiértékelése
  • Előrejelzési modell mentése
  • Előrejelzési modell használata

Előfeltételek

Idősor-előrejelzési minta áttekintése

Ez a minta egy C# .NET Core-konzolalkalmazás , amely a Singular Spectrum Analysis nevű egyváltozós idősorozat-elemzési algoritmussal előrejelzi a kerékpárkölcsönzések iránti keresletet. A minta kódja a GitHub dotnet/machinelearning-samples adattárában található.

A probléma ismertetése

A hatékony művelet végrehajtása érdekében a készletkezelés kulcsfontosságú szerepet játszik. Ha túl sok termék van raktáron, az azt jelenti, hogy a polcokon ülő el nem adott termékek nem termelnek bevételt. Ha túl kevés termék van, akkor elvesznek az értékesítések, és az ügyfelek a versenytársaktól vásárolnak. Ezért az állandó kérdés az, hogy mi az optimális készletmennyiség, amelyet kézben kell tartani? Az idősorozat-elemzés segít választ adni ezekre a kérdésekre az előzményadatok megtekintésével, a minták azonosításával, valamint az adatok felhasználásával az értékek jövőbeli előrejelzésére.

Az oktatóanyagban használt adatok elemzésének technikája egyváltozós idősoros elemzés. Az egyváltozós idősoros elemzés egyetlen numerikus megfigyelést vizsgál egy adott időszak alatt, meghatározott időközönként, például havi értékesítések esetén.

Az oktatóanyagban használt algoritmus a Singular Spectrum Analysis (SSA). Az SSA úgy működik, hogy egy idősort fő összetevőkből álló készletbe bont. Ezek az összetevők a trendeknek, a zajnak, a szezonalitásnak és sok más tényezőnek megfelelő jel részeiként értelmezhetők. Ezután ezeket az összetevőket rekonstruáljuk, és az értékek előrejelzésére használjuk a jövőben.

Konzolalkalmazás létrehozása

  1. Hozzon létre egy "BikeDemandForecasting" nevű C#- konzolalkalmazást . Kattintson a Tovább gombra.

  2. Válassza a .NET 6-ot a használni kívánt keretrendszerként. Kattintson a Létrehozás gombra.

  3. A NuGet-csomag Microsoft.ML verziójának telepítése

    Megjegyzés

    Ez a minta az említett NuGet-csomagok legújabb stabil verzióját használja, hacsak másként nem rendelkezik.

    1. A Megoldáskezelő kattintson a jobb gombbal a projektre, és válassza a Manage NuGet Packages (NuGet-csomagok kezelése) lehetőséget.
    2. Válassza a "nuget.org" lehetőséget a Csomag forrásaként, válassza a Tallózás lapot, és keresse meg a Microsoft.ML.
    3. Jelölje be az Előzetes verzió belefoglalása jelölőnégyzetet.
    4. Válassza a Telepítés gombot.
    5. Válassza az OK gombot a Módosítások előnézete párbeszédpanelen, majd válassza az Elfogadom gombot a Licenc elfogadása párbeszédpanelen, ha elfogadja a felsorolt csomagok licencfeltételét.
    6. Ismételje meg ezeket a lépéseket a System.Data.SqlClient és a Microsoft.ML.TimeSeries esetében.

Az adatok előkészítése és értelmezése

  1. Hozzon létre egy Data nevű könyvtárat.
  2. Töltse le a DailyDemand.mdf adatbázisfájlt , és mentse a Data könyvtárba.

Megjegyzés

Az oktatóanyagban használt adatok az UCI Bike Sharing Datasetből származnak. Fanaee-T, Hadi, and Gama, Joao, "Event labeling combining combining ensemble detectors and background knowledge", Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg, Web Link.

Az eredeti adatkészlet több, szezonalitásnak és időjárásnak megfelelő oszlopot tartalmaz. A rövidség kedvéért, és mivel az ebben az oktatóanyagban használt algoritmus csak egyetlen numerikus oszlop értékeit igényli, az eredeti adatkészletet úgy tömörítettük, hogy csak a következő oszlopokat tartalmazza:

  • dteday: A megfigyelés dátuma.
  • year: A megfigyelés kódolt éve (0=2011, 1=2012).
  • cnt: Az adott napra vonatkozó kerékpárkölcsönzések teljes száma.

Az eredeti adatkészlet egy adatbázistáblára van leképezve, amely az alábbi sémával rendelkezik egy SQL Server-adatbázisban.

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

Az alábbiakban az adatok egy mintáját találja:

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

Bemeneti és kimeneti osztályok létrehozása

  1. Nyissa meg a Program.cs fájlt, és cserélje le a meglévő using utasításokat a következőre:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    using System.Data.SqlClient;
    
  2. Hozza létre az ModelInput osztályt. Program A osztály alatt adja hozzá a következő kódot.

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

    A ModelInput osztály a következő oszlopokat tartalmazza:

    • RentalDate: A megfigyelés dátuma.
    • Év: A megfigyelés kódolt éve (0=2011, 1=2012).
    • TotalRentals: Az adott napra vonatkozó kerékpárkölcsönzések teljes száma.
  3. Hozzon létre ModelOutput osztályt az újonnan létrehozott ModelInput osztály alatt.

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

    A ModelOutput osztály a következő oszlopokat tartalmazza:

    • ForecastedRentals: Az előrejelzett időszak előrejelzett értékei.
    • LowerBoundRentals: Az előrejelzett időszak előrejelzett minimális értékei.
    • UpperBoundRentals: Az előrejelzett időszak előrejelzett maximális értékei.

Elérési utak definiálása és változók inicializálása

  1. A using utasítások alatt változókat definiálhat az adatok helyének, kapcsolati sztring és a betanított modell mentési helyének tárolásához.

    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. Inicializálja a mlContext változót egy új példánnyal MLContext a következő sor hozzáadásával az elérési utak definiálása után.

    MLContext mlContext = new MLContext();
    

    Az MLContext osztály minden ML.NET művelet kiindulási pontja, és az mlContext inicializálása egy új ML.NET környezetet hoz létre, amely megosztható a modelllétrehozási munkafolyamat-objektumok között. Ez fogalmilag hasonló az Entity Frameworkhez DBContext .

Az adatok betöltése

  1. Hozza létre DatabaseLoader , amely betölti a típusú ModelInputrekordokat.

    DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();
    
  2. Adja meg a lekérdezést, amely betölti az adatokat az adatbázisból.

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

    ML.NET algoritmusok elvárják, hogy az adatok típusa Single. Ezért az adatbázisból érkező numerikus értékeket, amelyek nem típusúak Real, egyetlen pontosságú lebegőpontos értéket kell konvertálni a típusra Real.

    A Year és TotalRental az oszlop egész típusú az adatbázisban. CAST A beépített függvénnyel mindkettő a következőre lesz öntöttveReal: .

  3. Hozzon létre egy elemet DatabaseSource az adatbázishoz való csatlakozáshoz és a lekérdezés végrehajtásához.

    DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance,
                                    connectionString,
                                    query);
    
  4. Töltse be az adatokat egy IDataViewfájlba.

    IDataView dataView = loader.Load(dbSource);
    
  5. Az adathalmaz két évnyi adatot tartalmaz. A betanításhoz csak az első év adatait használja a rendszer, a második évet a tényleges értékek és a modell által előállított előrejelzés összehasonlítására. Szűrje az adatokat az FilterRowsByColumn átalakítással.

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

    Az első évben csak az 1-nél kisebb oszlop értékei Year lesznek kiválasztva a upperBound paraméter 1 értékre állításával. Ezzel szemben a második évben az 1-nél nagyobb vagy azzal egyenlő értékeket a paraméter 1 értékre állításával lowerBound választja ki.

Idősor-elemzési folyamat definiálása

  1. Definiáljon egy folyamatot, amely a SsaForecastingEstimator használatával előrejelezi az idősoros adathalmaz értékeit.

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

    A forecastingPipeline az első évre 365 adatpontot vesz fel, és az idősor adathalmazát a paraméter által seriesLength megadott 30 napos (havi) intervallumokra osztja. Ezek a minták hetente vagy 7 napos időszakon keresztül lesznek elemezve. A következő időszak(ok) előrejelzett értékének meghatározásakor a rendszer az előző hét nap értékeit használja az előrejelzéshez. A modell úgy van beállítva, hogy hét időszakot jelezzen előre a jövőbe a horizon paraméter által meghatározott módon. Mivel az előrejelzés tájékozott becslés, nem mindig 100%-os pontosságú. Ezért érdemes ismerni az értékek tartományát a legjobb és legrosszabb esetben a felső és az alsó határ által meghatározottak szerint. Ebben az esetben az alsó és felső határ megbízhatósági szintje 95%-ra van állítva. A megbízhatósági szint ennek megfelelően növelhető vagy csökkenthető. Minél nagyobb az érték, annál szélesebb a tartomány a felső és az alsó határ között a kívánt megbízhatósági szint eléréséhez.

  2. Fit A metódus használatával betanítsa a modellt, és illesztse be az adatokat a korábban definiálthozforecastingPipeline.

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
    

A modell értékelése

A modell teljesítményének kiértékelése a jövő évi adatok előrejelzésével és a tényleges értékekkel való összehasonlításával.

  1. Hozzon létre egy nevű Evaluate új segédprogramot a Program.cs fájl alján.

    Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
    {
    
    }
    
  2. A metóduson Evaluate belül előrejelezheti a második év adatait a metódus és a Transform betanított modell használatával.

    IDataView predictions = model.Transform(testData);
    
  3. A metódussal lekérheti az adatok tényleges értékeit CreateEnumerable .

    IEnumerable<float> actual =
        mlContext.Data.CreateEnumerable<ModelInput>(testData, true)
            .Select(observed => observed.TotalRentals);
    
  4. Az előrejelzési értékek lekérése a CreateEnumerable metódussal.

    IEnumerable<float> forecast =
        mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true)
            .Select(prediction => prediction.ForecastedRentals[0]);
    
  5. Számítsa ki a tényleges és az előrejelzési értékek közötti különbséget, amelyet gyakran hibaként neveznek.

    var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);
    
  6. A teljesítmény méréséhez számítsa ki az abszolút hiba középértékét és a gyökér középértékét négyzetes hibaértékekkel.

    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
    

    A teljesítmény kiértékeléséhez a rendszer a következő metrikákat használja:

    • Átlagos abszolút hiba: Azt méri, hogy az előrejelzések mennyire közel állnak a tényleges értékhez. Ez az érték 0 és végtelen között van. Minél közelebb van a 0-hoz, annál jobb a modell minősége.
    • Gyökér középérték négyzetes hiba: Összefoglalja a modell hibáját. Ez az érték 0 és végtelen között van. Minél közelebb van a 0-hoz, annál jobb a modell minősége.
  7. Adja ki a metrikákat a konzolon.

    Console.WriteLine("Evaluation Metrics");
    Console.WriteLine("---------------------");
    Console.WriteLine($"Mean Absolute Error: {MAE:F3}");
    Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");
    
  8. Hívja meg az Evaluate alábbi metódust a metódus meghívásához Fit() .

    Evaluate(secondYearData, forecaster, mlContext);
    

A modell mentése

Ha elégedett a modellel, mentse későbbi használatra más alkalmazásokban.

  1. Evaluate() A metódus alatt hozzon létre egy TimeSeriesPredictionEngine. TimeSeriesPredictionEngine egy egyszerű módszer, amely egyetlen előrejelzést készít.

    var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
    
  2. Mentse a modellt a korábban definiált modelPath változó által meghatározott nevű MLModel.zip fájlba. A modell mentéséhez használja a Checkpoint metódust.

    forecastEngine.CheckPoint(mlContext, modelPath);
    

A modell használata a kereslet előrejelzéséhez

  1. Evaluate A metódus alatt hozzon létre egy nevű új segédprogram-metódustForecast.

    void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext)
    {
    
    }
    
  2. A metóduson Forecast belül használja a metódust a Predict következő hét nap bérleti díjainak előrejelzéséhez.

    ModelOutput forecast = forecaster.Predict();
    
  3. A tényleges és előrejelzési értékek igazítása hét időszakra.

    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. Iterálja végig az előrejelzés kimenetét, és jelenítse meg azt a konzolon.

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

Az alkalmazás futtatása

  1. A metódus meghívása Checkpoint() alatt hívja meg a metódust Forecast .

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. Futtassa az alkalmazást. Az alábbihoz hasonló kimenetnek meg kell jelennie a konzolon. A rövidség kedvéért a kimenet kondenzálva lett.

    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 tényleges és az előrejelzett értékek vizsgálata a következő kapcsolatokat mutatja:

Tényleges és előrejelzési összehasonlítás

Bár az előrejelzett értékek nem a bérleti díjak pontos számát jelzik előre, szűkebb értéktartományt biztosítanak, amely lehetővé teszi egy művelet számára az erőforrások használatának optimalizálását.

Gratulálunk! Sikeresen létrehozott egy idősorozatos gépi tanulási modellt a kerékpárkölcsönzési igények előrejelzéséhez.

Az oktatóanyag forráskódját a dotnet/machinelearning-samples adattárban találja.

Következő lépések