Megosztás a következőn keresztül:


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

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

Ebben az oktatóanyagban a következőket sajátíthatja el:

  • 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#-konzolalkalmazás , amely a kerékpárkölcsönzések iránti keresletet egy nem változó idősorozat-elemzési algoritmus, az úgynevezett Singular Spectrum Analysis használatával jelzi előre. 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ásához a leltárkezelés kulcsfontosságú szerepet játszik. Ha túl sok termék van raktáron, az azt jelenti, hogy a polcokon ülő eladatlan termékek nem termelnek bevételt. Ha túl kevés termék van, akkor elvesznek az értékesítések és a versenytársaktól vásárolt ügyfelek. 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 és az adatok felhasználásával az értékek jövőbeli előrejelzéséhez.

Az ebben 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 vesz igénybe adott időközönként, például havi értékesítések során.

Az oktatóanyagban használt algoritmus a Singular Spectrum Analysis (SSA). Az SSA úgy működik, hogy egy idősort fő összetevők készletére 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 szolgálnak 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 8-at a használni kívánt keretrendszerként. Kattintson a Létrehozás gombra.

  3. A Microsoft.ML verziójú NuGet-csomag 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őben kattintson a jobb gombbal a projektre, és válassza a 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, keresse meg Microsoft.ML.
    3. Jelölje be az Include prerelease (Előzetes befoglalás) jelölőnégyzetet.
    4. Válassza a Telepítés gombot.
    5. Kattintson az OK gombra a Változá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 az adatkönyvtárba .

Megjegyzés:

Az oktatóanyagban használt adatok az UCI Bike Sharing Datasetből származnak. Hadi Fanaee-T és João Gama, "Eseménycímkézés együttes detektorok és háttértudás kombinálásával", Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg, Weblink.

Az eredeti adatkészlet több, a szezonalitásnak és az időjárásnak megfelelő oszlopot tartalmaz. A rövidség kedvéért, és mivel 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.
  • év: 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ábbi adatok mintája:

RentalDate Év 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 Program.cs fájlt, és cserélje le a meglévő using irányelveket a következőre:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    using System.Data.SqlClient;
    
  2. Osztály létrehozása ModelInput . Program Az 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; }
    }
    

    Az 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; }
    }
    

    Az 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. using Az irányelvek alatt változókat határozunk meg az adatok helyének, a kapcsolati sztringnek é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 az elérési utak meghatározása után a következő sor hozzáadásával.

    MLContext mlContext = new MLContext();
    

    Az MLContext osztály az összes ML.NET művelet kiindulópontja, és az mlContext inicializálása ú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 .

Töltse be az adatokat

  1. Olyan rekordokat hoz létre DatabaseLoader , amelyek betöltik a rekordokat ModelInput.

    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 legyen Single. Ezért az adatbázisból érkező numerikus értékeket, amelyek nem Real típusúak, az egyszeres pontosságú lebegőpontos értékké kell Real-re konvertálni.

    Year Az TotalRental oszlopok mind egész típusúak az adatbázisban. CAST A beépített függvény használatával mindkettőt a rendszer a következőre Realöntötte: .

  3. Hozzon létre egy kapcsolatot DatabaseSource az adatbázissal, és hajtsa végre a lekérdezést.

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

    IDataView dataView = loader.Load(dbSource);
    
  5. Az adathalmaz két évnyi adatot tartalmaz. A betanításhoz csak az első év adatai használhatók, a második év pedig a tényleges értékek összehasonlítására szolgál a modell által előállított előrejelzéssel. 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 választja ki a lowerBound paraméter 1 értékre állításával.

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

  1. Definiáljon egy folyamatot, amely a SsaForecastingEstimatort használja az idősoros adathalmaz értékeinek előrejelzéséhez.

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

    Az forecastingPipeline első évben 365 adatpontot vesz fel, és a paraméter által megadott 30 napos (havi) időközökre osztja az idősor adathalmazát seriesLength . Ezeket a mintákat hetente vagy 7 napos időszakon keresztül elemzik. 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 megalapozott becslés, nem mindig 100% pontos. Ezért érdemes ismerni az értékek tartományát a felső és az alsó határ által meghatározott legjobb és legrosszabb forgatókönyvekben. Ebben az esetben az alsó és a felső határ megbízhatósági szintje 95%. A megbízhatósági szint ennek megfelelően növelhető vagy csökkenthető. Minél magasabb 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. Ezzel a Fit módszerrel betanítsa a modellt, és illeszkedjen az adatokhoz a korábban definiálthoz forecastingPipeline.

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
    

A modell kiértékelése

Értékelje ki, hogy a modell milyen jól teljesít 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 új segédprogrammetódust Evaluate a Program.cs fájl alján.

    Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
    {
    
    }
    
  2. A metóduson Evaluate belül a betanított modellel előre jelezheti a második év adatait.Transform

    IDataView predictions = model.Transform(testData);
    
  3. A metódus használatával 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 módszerrel.

    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 általában hibaként nevezünk.

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

    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 következő metrikákat használja a rendszer:

    • Átlagos abszolút hiba: Azt méri, hogy az előrejelzések milyen közel állnak a tényleges értékhez. Ez az érték 0 és végtelen közötti. Minél közelebb van a 0-hoz, annál jobb a modell minősége.
    • Négyzetes középérték hiba: A modell hibájának összegzése. Ez az érték 0 és végtelen közötti. 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 az egyszeri előrejelzések készítésére.

    var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
    
  2. Mentse a modellt a korábban definiált MLModel.zip változó által megadott fájlbamodelPath. A metódus használatával Checkpoint mentse a modellt.

    forecastEngine.CheckPoint(mlContext, modelPath);
    

Igény előrejelzése a modell használatával

  1. Evaluate A metódus alatt hozzon létre egy új, úgynevezett segédprogrammetódustForecast.

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

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

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

Az alkalmazás futtatása

  1. Az alábbiakban a metódus meghívása Checkpoint() hívja meg a metódust Forecast .

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. Indítsa el 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, hogy egy művelet optimalizálja az erőforrások használatát.

Gratulálok! 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