Tutorial: Memperkirakan permintaan layanan penyewaan sepeda dengan analisis rangkaian waktu dan ML.NET

Pelajari cara memperkirakan permintaan untuk layanan penyewaan sepeda menggunakan analisis rangkaian waktu univariat pada data yang disimpan dalam database SQL Server dengan ML.NET.

Dalam tutorial ini, Anda akan mempelajari cara:

  • Memahami masalahnya
  • Memuat data dari database
  • Membuat model prakiraan
  • Mengevaluasi model prakiraan
  • Menyimpan model prakiraan
  • Menggunakan model prakiraan

Prasyarat

Gambaran umum sampel prakiraan rangkaian waktu

Sampel ini adalah aplikasi konsol C# .NET Core yang memperkirakan permintaan penyewaan sepeda menggunakan algoritma analisis rangkaian waktu univariat yang dikenal sebagai Analisis Spektrum Tunggal. Kode untuk sampel ini dapat ditemukan di repositori dotnet/machinelearning-samples di GitHub.

Memahami masalahnya

Untuk menjalankan operasi yang efisien, manajemen inventaris memainkan peran kunci. Memiliki terlalu banyak produk dalam stok berarti produk yang tidak terjual duduk di rak tidak menghasilkan pendapatan apa pun. Memiliki terlalu sedikit produk menyebabkan kehilangan penjualan dan pelanggan yang membeli dari pesaing. Oleh karena itu, pertanyaan konstan adalah, berapa jumlah inventori optimal yang harus ditangani? Analisis rangkaian waktu membantu memberikan jawaban atas pertanyaan-pertanyaan ini dengan melihat data historis, mengidentifikasi pola, dan menggunakan informasi ini untuk memperkirakan nilai beberapa waktu di masa mendatang.

Teknik untuk menganalisis data yang digunakan dalam tutorial ini adalah analisis rangkaian waktu univariat. Analisis rangkaian waktu Univariat melihat satu pengamatan numerik selama periode waktu tertentu pada interval tertentu seperti penjualan bulanan.

Algoritma yang digunakan dalam tutorial ini adalah Analisis Spektrum Tunggal (SSA). SSA bekerja dengan menguraikan rangkaian waktu menjadi satu set komponen utama. Komponen-komponen ini dapat ditafsirkan sebagai bagian dari sinyal yang sesuai dengan tren, kebisingan, musiman, dan banyak faktor lainnya. Kemudian, komponen-komponen ini direkonstruksi dan digunakan untuk memperkirakan nilai beberapa waktu di masa depan.

Membuat aplikasi konsol

  1. Buat Aplikasi Konsol C# yang disebut "BikeDemandForecasting". Klik tombol Berikutnya.

  2. Pilih .NET 6 sebagai kerangka kerja yang akan digunakan. Klik tombol Buat.

  3. Menginstal paket NuGet versi Microsoft.ML

    Catatan

    Sampel ini menggunakan versi stabil terbaru dari paket NuGet yang disebutkan kecuali dinyatakan lain.

    1. Di Penjelajah Solusi, klik kanan proyek Anda dan pilih Kelola Paket NuGet.
    2. Pilih "nuget.org" sebagai Sumber paket, pilih tab Telusuri , cari Microsoft.ML.
    3. Centang kotak sertakan prarilis .
    4. Pilih tombol Instal.
    5. Pilih tombol OK pada dialog Pratinjau Perubahan lalu pilih tombol Saya Terima pada dialog Penerimaan Lisensi jika Anda setuju dengan ketentuan lisensi untuk paket yang tercantum.
    6. Ulangi langkah-langkah ini untuk System.Data.SqlClient dan Microsoft.ML.TimeSeries.

Menyiapkan dan memahami data

  1. Buat direktori yang disebut Data.
  2. Unduh file database DailyDemand.mdf dan simpan ke direktori Data.

Catatan

Data yang digunakan dalam tutorial ini berasal dari Himpunan Data Berbagi Sepeda UCI. Fanaee-T, Hadi, dan Gama, Joao, 'Pelabelan peristiwa menggabungkan detektor ansambel dan pengetahuan latar belakang', Kemajuan dalam Kecerdasan Buatan (2013): pp. 1-15, Springer Berlin Heidelberg, Web Link.

Himpunan data asli berisi beberapa kolom yang sesuai dengan musiman dan cuaca. Untuk kemudahan dan karena algoritma yang digunakan dalam tutorial ini hanya memerlukan nilai dari satu kolom numerik, himpunan data asli telah dikondensasikan untuk hanya menyertakan kolom berikut:

  • dteday: Tanggal pengamatan.
  • tahun: Tahun pengamatan yang dikodekan (0=2011, 1=2012).
  • cnt: Jumlah total penyewaan sepeda untuk hari itu.

Himpunan data asli dipetakan ke tabel database dengan skema berikut dalam database SQL Server.

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

Berikut ini adalah sampel data:

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

Membuat kelas input dan output

  1. Buka file Program.cs dan ganti pernyataan yang ada using dengan yang berikut ini:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    using System.Data.SqlClient;
    
  2. Buat ModelInput kelas . Di bawah Program kelas , tambahkan kode berikut.

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

    Kelas ModelInput berisi kolom berikut:

    • RentalDate: Tanggal pengamatan.
    • Tahun: Tahun pengamatan yang dikodekan (0=2011, 1=2012).
    • TotalRentals: Jumlah total penyewaan sepeda untuk hari itu.
  3. Buat ModelOutput kelas di bawah kelas yang baru dibuat ModelInput .

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

    Kelas ModelOutput berisi kolom berikut:

    • ForecastedRentals: Nilai yang diprediksi untuk periode prakiraan.
    • LowerBoundRentals: Nilai minimum yang diprediksi untuk periode yang diperkirakan.
    • UpperBoundRentals: Nilai maksimum yang diprediksi untuk periode prakiraan.

Menentukan jalur dan menginisialisasi variabel

  1. Di bawah pernyataan penggunaan menentukan variabel untuk menyimpan lokasi data, string koneksi, dan tempat menyimpan model terlatih Anda.

    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. Inisialisasi mlContext variabel dengan instans MLContext baru dengan menambahkan baris berikut setelah menentukan jalur.

    MLContext mlContext = new MLContext();
    

    Kelas MLContext adalah titik awal untuk semua operasi ML.NET, dan menginisialisasi mlContext membuat lingkungan ML.NET baru yang dapat dibagikan di seluruh objek alur kerja pembuatan model. Ini mirip, secara konseptual, ke DBContext dalam Kerangka Kerja Entitas.

Muat data

  1. Buat DatabaseLoader yang memuat rekaman jenis ModelInput.

    DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();
    
  2. Tentukan kueri untuk memuat data dari database.

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

    algoritma ML.NET mengharapkan data berjenis Single. Oleh karena itu, nilai numerik yang berasal dari database yang bukan jenis Real, nilai floating-point presisi tunggal, harus dikonversi ke Real.

    Kolom Year dan TotalRental keduanya adalah jenis bilangan bulat dalam database. Menggunakan fungsi bawaan CAST , keduanya ditransmisikan ke Real.

  3. DatabaseSource Buat untuk menyambungkan ke database dan menjalankan kueri.

    DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance,
                                    connectionString,
                                    query);
    
  4. Muat data ke dalam IDataView.

    IDataView dataView = loader.Load(dbSource);
    
  5. Himpunan data berisi data senilai dua tahun. Hanya data dari tahun pertama yang digunakan untuk pelatihan, tahun kedua diadakan untuk membandingkan nilai aktual dengan perkiraan yang dihasilkan oleh model. Filter data menggunakan FilterRowsByColumn transformasi.

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

    Untuk tahun pertama, hanya nilai dalam Year kolom kurang dari 1 yang dipilih dengan mengatur parameter ke upperBound 1. Sebaliknya, untuk tahun kedua, nilai yang lebih besar dari atau sama dengan 1 dipilih dengan mengatur parameter ke lowerBound 1.

Menentukan alur analisis rangkaian waktu

  1. Tentukan alur yang menggunakan SsaForecastingEstimator untuk memperkirakan nilai dalam himpunan data rangkaian waktu.

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

    forecastingPipeline mengambil 365 poin data untuk tahun pertama dan sampel atau membagi himpunan data rangkaian waktu menjadi interval 30 hari (bulanan) seperti yang ditentukan oleh seriesLength parameter . Masing-masing sampel ini dianalisis melalui jendela mingguan atau 7 hari. Saat menentukan berapa nilai prakiraan untuk periode berikutnya, nilai dari tujuh hari sebelumnya digunakan untuk membuat prediksi. Model diatur ke perkiraan tujuh periode ke masa depan seperti yang horizon didefinisikan oleh parameter . Karena perkiraan adalah tebakan yang diinformasikan, itu tidak selalu 100% akurat. Oleh karena itu, ada baiknya untuk mengetahui rentang nilai dalam skenario terbaik dan terburuk seperti yang didefinisikan oleh batas atas dan bawah. Dalam hal ini, tingkat keyakinan untuk batas bawah dan atas diatur ke 95%. Tingkat keyakinan dapat ditingkatkan atau dikurangi sesuai. Semakin tinggi nilainya, semakin luas rentangnya antara batas atas dan bawah untuk mencapai tingkat keyakinan yang diinginkan.

  2. Fit Gunakan metode untuk melatih model dan menyesuaikan data dengan yang ditentukan forecastingPipelinesebelumnya.

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
    

Mengevaluasi model

Evaluasi seberapa baik performa model dengan memperkirakan data tahun depan dan membandingkannya dengan nilai aktual.

  1. Buat metode utilitas baru yang disebut Evaluate di bagian bawah file Program.cs .

    Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
    {
    
    }
    
  2. Evaluate Di dalam metode , perkirakan data tahun kedua dengan menggunakan Transform metode dengan model terlatih.

    IDataView predictions = model.Transform(testData);
    
  3. Dapatkan nilai aktual dari data dengan menggunakan CreateEnumerable metode .

    IEnumerable<float> actual =
        mlContext.Data.CreateEnumerable<ModelInput>(testData, true)
            .Select(observed => observed.TotalRentals);
    
  4. Dapatkan nilai prakiraan dengan menggunakan CreateEnumerable metode .

    IEnumerable<float> forecast =
        mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true)
            .Select(prediction => prediction.ForecastedRentals[0]);
    
  5. Hitung perbedaan antara nilai aktual dan prakiraan, yang biasa disebut sebagai kesalahan.

    var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);
    
  6. Mengukur performa dengan menghitung nilai Kesalahan Absolut Rata-Rata dan Kesalahan Kuadrat Rata-Rata Akar.

    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
    

    Untuk mengevaluasi performa, metrik berikut digunakan:

    • Kesalahan Absolut Rata-rata: Mengukur seberapa dekat prediksi dengan nilai aktual. Nilai ini berkisar antara 0 dan tak terbatas. Semakin dekat ke 0, semakin baik kualitas model.
    • Kesalahan Kuadrat Rata-Rata Akar: Meringkas kesalahan dalam model. Nilai ini berkisar antara 0 dan tak terbatas. Semakin dekat ke 0, semakin baik kualitas model.
  7. Keluarkan metrik ke konsol.

    Console.WriteLine("Evaluation Metrics");
    Console.WriteLine("---------------------");
    Console.WriteLine($"Mean Absolute Error: {MAE:F3}");
    Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");
    
  8. Panggil metode di Evaluate bawah ini yang memanggil Fit() metode .

    Evaluate(secondYearData, forecaster, mlContext);
    

Menyimpan model

Jika Anda puas dengan model Anda, simpan untuk digunakan nanti di aplikasi lain.

  1. Evaluate() Di bawah metode membuat TimeSeriesPredictionEngine. TimeSeriesPredictionEngine adalah metode kenyamanan untuk membuat prediksi tunggal.

    var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
    
  2. Simpan model ke file yang disebut MLModel.zip sebagaimana ditentukan oleh variabel yang ditentukan modelPath sebelumnya. Checkpoint Gunakan metode untuk menyimpan model.

    forecastEngine.CheckPoint(mlContext, modelPath);
    

Menggunakan model untuk memperkirakan permintaan

  1. Evaluate Di bawah metode , buat metode utilitas baru yang disebut Forecast.

    void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext)
    {
    
    }
    
  2. Forecast Di dalam metode , gunakan Predict metode untuk memperkirakan penyewaan selama tujuh hari ke depan.

    ModelOutput forecast = forecaster.Predict();
    
  3. Sejajarkan nilai aktual dan prakiraan selama tujuh periode.

    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. Iterasi melalui output prakiraan dan tampilkan di konsol.

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

Menjalankan aplikasi

  1. Di bawah ini memanggil Checkpoint() metode memanggil Forecast metode .

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. Jalankan aplikasi. Output yang mirip dengan yang di bawah ini akan muncul di konsol. Untuk keringkasan, output telah dikondensasi.

    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
    

Inspeksi nilai aktual dan prakiraan menunjukkan hubungan berikut:

Perbandingan Aktual vs Prakiraan

Meskipun nilai yang diperkirakan tidak memprediksi jumlah sewa yang tepat, nilai tersebut memberikan rentang nilai yang lebih sempit yang memungkinkan operasi untuk mengoptimalkan penggunaan sumber daya mereka.

Selamat! Anda sekarang telah berhasil membangun model pembelajaran mesin rangkaian waktu untuk memperkirakan permintaan penyewaan sepeda.

Anda dapat menemukan kode sumber untuk tutorial ini di repositori dotnet/machinelearning-samples .

Langkah berikutnya