Kurz: Prognóza poptávky po půjčovně kol s analýzou časových řad a ML.NET

Naučte se předpovídat poptávku po službě půjčování kol pomocí analýzy časových řad bez proměnných na data uložená v SQL Server databázi s ML.NET.

V tomto kurzu se naučíte:

  • Pochopení problému
  • Načtení dat z databáze
  • Vytvoření modelu prognózování
  • Vyhodnocení modelu prognózování
  • Uložení modelu prognózování
  • Použití modelu prognózování

Požadavky

Přehled ukázky prognózování časových řad

Tato ukázka je konzolová aplikace pro C# .NET Core , která předpovídá poptávku po půjčovnách kol pomocí algoritmu analýzy jednorozměrné časové řady známého jako Singular Spectrum Analysis. Kód pro tuto ukázku najdete v úložišti dotnet/machinelearning-samples na GitHubu.

Pochopení problému

Aby bylo možné provádět efektivní operaci, hraje klíčovou roli správa inventáře. Příliš mnoho produktu na skladě znamená, že neprodané produkty, které jsou na regálech, negenerují žádné výnosy. Příliš málo produktů vede ke ztrátě prodeje a zákazníkům, kteří nakupují od konkurence. Konstantní otázkou proto je, jaké je optimální množství zásob, které je třeba mít po ruce? Analýza časových řad pomáhá poskytnout odpověď na tyto otázky tím, že se podívá na historická data, identifikuje vzory a pomocí těchto informací předpovídá hodnoty někdy v budoucnu.

Technika pro analýzu dat použitá v tomto kurzu je analýza časových řad bez přípony. Analýza jednorozměrných časových řad se dívá na jedno číselné pozorování v určitém časovém období v určitých intervalech, jako je například měsíční prodej.

V tomto kurzu se používá algoritmus SSA (Singular Spectrum Analysis). SSA funguje tak, že časovou řadu rozloží do sady hlavních součástí. Tyto komponenty lze interpretovat jako části signálu, které odpovídají trendům, šumu, sezónnosti a mnoha dalším faktorům. Pak se tyto komponenty rekonstruují a použijí se k předpovídání hodnot někdy v budoucnu.

Vytvoření konzolové aplikace

  1. Vytvořte konzolovou aplikaci c# s názvem BikeDemandForecasting. Klikněte na tlačítko Další .

  2. Jako architekturu, kterou chcete použít, zvolte .NET 6. Klikněte na tlačítko Vytvořit.

  3. Instalace balíčku NuGet Microsoft.ML verze

    Poznámka

    Tato ukázka používá nejnovější stabilní verzi uvedených balíčků NuGet, pokud není uvedeno jinak.

    1. V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Spravovat balíčky NuGet.
    2. Jako zdroj balíčku zvolte "nuget.org", vyberte kartu Procházet a vyhledejteMicrosoft.ML.
    3. Zaškrtněte políčko Zahrnout předběžné verze .
    4. Vyberte tlačítko Nainstalovat .
    5. Pokud souhlasíte s licenčními podmínkami pro uvedené balíčky, vyberte tlačítko OK v dialogovém okně Náhled změn a pak v dialogovém okně Souhlas s licencí vyberte tlačítko Přijmout .
    6. Tento postup opakujte pro System.Data.SqlClient a Microsoft.ML.TimeSeries.

Příprava dat a jejich pochopení

  1. Vytvořte adresář s názvem Data.
  2. Stáhněte si soubor databáze DailyDemand.mdf a uložte ho do adresáře Data.

Poznámka

Data použitá v tomto kurzu pocházejí z datové sady sdílení kol UCI. Fanaee-T, Hadi a Gama, Joao, 'Event labeling combining ensemble detectors and background knowledge', Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg, Web Link.

Původní datová sada obsahuje několik sloupců odpovídajících sezónnosti a počasí. Kvůli stručnosti a vzhledem k tomu, že algoritmus použitý v tomto kurzu vyžaduje pouze hodnoty z jednoho číselného sloupce, byla původní datová sada zhuštěna tak, aby zahrnovala pouze následující sloupce:

  • dteday: Datum pozorování.
  • year: Kódovaný rok pozorování (0=2011, 1=2012).
  • cnt: Celkový počet zapůjčení kol pro daný den.

Původní datová sada je v SQL Server databázi namapovaná na tabulku databáze s následujícím schématem.

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

Následuje ukázka dat:

Datum pronájmu Year (Rok) TotalRentals
1/1/2011 0 985
1/2/2011 0 801
1/3/2011 0 1349

Vytvoření vstupních a výstupních tříd

  1. Otevřete soubor Program.cs a nahraďte existující using příkazy následujícím kódem:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    using System.Data.SqlClient;
    
  2. Vytvořte třídu ModelInput. Program Pod třídu přidejte následující kód.

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

    Třída ModelInput obsahuje následující sloupce:

    • RentalDate: Datum pozorování.
    • Rok: Zakódovaný rok pozorování (0=2011, 1=2012).
    • TotalRentals: Celkový počet zapůjčení kol za daný den.
  3. Vytvořte ModelOutput třídu pod nově vytvořenou ModelInput třídou.

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

    Třída ModelOutput obsahuje následující sloupce:

    • ForecastedRentals: Předpovězené hodnoty pro předpovězené období.
    • LowerBoundRentals: Předpovězené minimální hodnoty pro předpokládané období.
    • UpperBoundRentals: Předpovězené maximální hodnoty pro předpokládané období.

Definování cest a inicializace proměnných

  1. Pod příkazy using definujte proměnné pro uložení umístění dat, připojovacího řetězce a umístění pro uložení natrénovaného modelu.

    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. Inicializujte mlContext proměnnou s novou instancí MLContext tak, že po definování cest přidáte následující řádek.

    MLContext mlContext = new MLContext();
    

    Třída MLContext je výchozím bodem pro všechny operace ML.NET a inicializace mlContext vytvoří nové prostředí ML.NET, které lze sdílet mezi objekty pracovního postupu vytváření modelu. Koncepčně DBContext je podobný jako v Entity Frameworku.

Načtení dat

  1. Vytvořte, DatabaseLoader který načte záznamy typu ModelInput.

    DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();
    
  2. Definujte dotaz, který načte data z databáze.

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

    ML.NET algoritmy očekávají, že data budou typu Single. Číselné hodnoty pocházející z databáze, které nejsou typu Real, hodnotu s plovoucí desetinou čárkou s jednoduchou přesností, je proto nutné převést na Real.

    Sloupce Year a TotalRental jsou v databázi celočíselné typy. CAST Pomocí předdefinované funkce se obě přetypují na Real.

  3. Vytvořte pro DatabaseSource připojení k databázi a spusťte dotaz.

    DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance,
                                    connectionString,
                                    query);
    
  4. Načtěte data do .IDataView

    IDataView dataView = loader.Load(dbSource);
    
  5. Datová sada obsahuje data za dva roky. Pro trénování se používají pouze data z prvního roku, druhý rok se používá k porovnání skutečných hodnot s prognózou vytvořenou modelem. Filtrování dat pomocí FilterRowsByColumn transformace

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

    Pro první rok jsou vybrány pouze hodnoty ve Year sloupci menší než 1 nastavením parametru upperBound na hodnotu 1. Naopak pro druhý rok jsou hodnoty větší nebo rovné 1 vybrány nastavením parametru lowerBound na hodnotu 1.

Definování kanálu analýzy časových řad

  1. Definujte kanál, který používá SsaForecastingEstimator k prognózování hodnot v datové sadě časové řady.

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

    Vezme forecastingPipeline 365 datových bodů pro první rok a vzorkuje nebo rozdělí datovou sadu časových řad do 30denních (měsíčních) intervalů podle parametru seriesLength . Každý z těchto vzorků se analyzuje týdenním nebo 7denním intervalem. Při určování předpokládané hodnoty pro další období se k předpovědím použijí hodnoty z předchozích sedmi dnů. Model je nastavený na prognózu sedmi období do budoucnosti, jak je definováno parametrem horizon . Vzhledem k tomu, že prognóza je informovaný odhad, není vždy 100% přesná. Proto je dobré znát rozsah hodnot v nejlepších a nejhorších scénářích definovaných horní a dolní hranicí. V tomto případě je úroveň spolehlivosti dolní a horní hranice nastavena na 95 %. Úroveň spolehlivosti lze odpovídajícím způsobem zvýšit nebo snížit. Čím vyšší je hodnota, tím širší je rozsah mezi horní a dolní hranicí, aby se dosáhlo požadované úrovně spolehlivosti.

  2. Použijte metodu Fit k trénování modelu a přizpůsobení dat dříve definovanému forecastingPipelineobjektu .

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
    

Vyhodnocení modelu

Vyhodnoťte, jak dobře model funguje, tím, že předpovíte data na příští rok a porovnáte je se skutečnými hodnotami.

  1. Vytvořte novou metodu nástroje s názvem Evaluate v dolní části souboru Program.cs .

    Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
    {
    
    }
    
  2. V rámci Evaluate metody předpovídáte data druhého roku pomocí Transform metody s natrénovaným modelem.

    IDataView predictions = model.Transform(testData);
    
  3. Pomocí metody získejte skutečné hodnoty z dat CreateEnumerable .

    IEnumerable<float> actual =
        mlContext.Data.CreateEnumerable<ModelInput>(testData, true)
            .Select(observed => observed.TotalRentals);
    
  4. Pomocí metody získejte hodnoty prognózy CreateEnumerable .

    IEnumerable<float> forecast =
        mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true)
            .Select(prediction => prediction.ForecastedRentals[0]);
    
  5. Vypočítejte rozdíl mezi skutečnými a předpokládanými hodnotami, běžně označovaný jako chyba.

    var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);
    
  6. Změřte výkon výpočtem hodnot Střední absolutní chyba a Odmocněná střední kvadratická chyba.

    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
    

    K vyhodnocení výkonu se používají následující metriky:

    • Střední absolutní chyba: Měří, jak blízko jsou predikce ke skutečné hodnotě. Tato hodnota se pohybuje mezi 0 a nekonečnem. Čím blíže k 0, tím lepší je kvalita modelu.
    • Kořenová střední kvadratická chyba: Shrnuje chybu v modelu. Tato hodnota se pohybuje mezi 0 a nekonečnem. Čím blíže k 0, tím lepší je kvalita modelu.
  7. Vypíše metriky do konzoly.

    Console.WriteLine("Evaluation Metrics");
    Console.WriteLine("---------------------");
    Console.WriteLine($"Mean Absolute Error: {MAE:F3}");
    Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");
    
  8. Zavolejte metodu Evaluate níže, která volá metodu Fit() .

    Evaluate(secondYearData, forecaster, mlContext);
    

Uložení modelu

Pokud jste s modelem spokojení, uložte si ho pro pozdější použití v jiných aplikacích.

  1. Pod metodou Evaluate() vytvořte TimeSeriesPredictionEngine. TimeSeriesPredictionEngine je pohodlná metoda pro vytváření jednoduchých předpovědí.

    var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
    
  2. Uložte model do souboru s názvem MLModel.zip určeným dříve definovanou modelPath proměnnou. Checkpoint K uložení modelu použijte metodu .

    forecastEngine.CheckPoint(mlContext, modelPath);
    

Použití modelu k předpovídání poptávky

  1. Pod metodou Evaluate vytvořte novou metodu nástroje s názvem Forecast.

    void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext)
    {
    
    }
    
  2. V rámci Forecast metody použijte metodu Predict k předpovídání výpůjčky na příštích sedm dnů.

    ModelOutput forecast = forecaster.Predict();
    
  3. Zarovnejte skutečné hodnoty a hodnoty prognózy pro sedm období.

    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. Iterujte výstup prognózy a zobrazte ho v konzole.

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

Spuštění aplikace

  1. Pod voláním Checkpoint() metody volejte metodu Forecast .

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. Spusťte aplikaci. Na konzole by se měl zobrazit výstup podobný následujícímu. Pro stručnost byl výstup zhuštěný.

    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
    

Kontrola skutečných a předpokládaných hodnot ukazuje následující relace:

Porovnání skutečných a prognóz

I když prognózované hodnoty nepředpovívají přesný počet výpůjčků, poskytují užší rozsah hodnot, který operaci umožňuje optimalizovat využití prostředků.

Gratulujeme! Nyní jste úspěšně vytvořili model strojového učení časových řad, který předpovídá poptávku po půjčování kol.

Zdrojový kód pro tento kurz najdete v úložišti dotnet/machinelearning-samples .

Další kroky