Bagikan melalui


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 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# yang memperkirakan permintaan penyewaan sepeda menggunakan algoritma analisis rangkaian waktu univariat yang dikenal sebagai Analisis Spektrum Singular. Kode untuk sampel ini dapat ditemukan di dotnet/machinelearning-samples repositori 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 penjualan hilang dan pelanggan membeli dari pesaing. Oleh karena itu, pertanyaan konstan adalah, berapa jumlah inventaris 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 Singular Spectrum Analysis (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# dengan nama "BikeDemandForecasting". Klik tombol Berikutnya.

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

  3. Menginstal paket NuGet versi Microsoft.ML

    Nota

    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, lalu cari Microsoft.ML.
    3. Centang kotak centang Sertakan prarilis.
    4. Pilih tombol Instal.
    5. Pilih tombol OK pada dialog Perubahan Pratinjau 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 .

Nota

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

Himpunan data asli berisi beberapa kolom yang sesuai dengan musiman dan cuaca. Untuk brevity 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:

TanggalSewa 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 arahan using yang ada dengan yang berikut ini:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms.TimeSeries;
    using System.Data.SqlClient;
    
  2. Buat kelas ModelInput. Di bawah kelas Program, 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 kelas ModelOutput di bawah kelas ModelInput yang baru dibuat.

    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 yang diramalkan.
    • LowerBoundRentals: Nilai minimum yang diprediksi untuk jangka waktu yang diperkirakan.
    • UpperBoundRentals: Nilai maksimum yang diprediksi untuk periode yang diperkirakan.

Menentukan jalur dan menginisialisasi variabel

  1. Di bawah ini, direktif using mendefinisikan variabel untuk menyimpan lokasi data, string koneksi, serta tempat menyimpan model yang terlatih.

    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 variabel mlContext dengan instans baru MLContext 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, untuk DBContext dalam Entity Framework.

Memuat 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 tipe Real, nilai floating-point presisi tunggal, harus dikonversi ke Real.

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

  3. Buat DatabaseSource 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 transformasi FilterRowsByColumn.

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

    Untuk tahun pertama, hanya nilai di kolom Year kurang dari 1 yang dipilih dengan mengatur parameter upperBound ke 1. Sebaliknya, untuk tahun kedua, nilai yang lebih besar dari atau sama dengan 1 dipilih dengan mengatur parameter lowerBound ke 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 parameter seriesLength. Masing-masing sampel ini dianalisis melalui jendela mingguan atau 7 hari. Saat menentukan nilai yang diperkirakan untuk periode berikutnya, nilai dari tujuh hari sebelumnya digunakan untuk membuat prediksi. Model diatur untuk memperkirakan tujuh periode ke masa depan seperti yang didefinisikan oleh parameter horizon. Karena perkiraan adalah tebakan berdasarkan informasi, 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 ditetapkan pada 95%. Tingkat keyakinan dapat ditingkatkan atau menurun sesuai. Semakin tinggi nilainya, semakin luas rentangnya antara batas atas dan bawah untuk mencapai tingkat keyakinan yang diinginkan.

  2. Gunakan metode Fit untuk melatih model dan menyesuaikan data dengan forecastingPipelineyang ditentukan sebelumnya.

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
    

Evaluasi 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. Di dalam metode Evaluate, perkirakan data tahun kedua dengan menggunakan metode Transform dengan model terlatih.

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

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

    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. Ukur performa dengan menghitung nilai Kesalahan Absolut Rata-Rata dan Kesalahan Rata-Rata Kuadrat 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 sesungguhnya. Nilai ini berkisar antara 0 dan tak terbatas. Semakin dekat ke 0, semakin baik kualitas model.
    • Kesalahan Kuadrat Rata-Rata Akar: Merangkum 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 Evaluate di bawah ini dengan memanggil metode Fit().

    Evaluate(secondYearData, forecaster, mlContext);
    

Simpan model

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

  1. Di bawah metode Evaluate() buat TimeSeriesPredictionEngine. TimeSeriesPredictionEngine adalah metode yang praktis untuk membuat prediksi tunggal.

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

    forecastEngine.CheckPoint(mlContext, modelPath);
    

Menggunakan model untuk memperkirakan permintaan

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

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

    ModelOutput forecast = forecaster.Predict();
    
  3. Ratakan 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. Telusuri output prakiraan dan tampilkan di konsol.

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

Jalankan aplikasi

  1. Di bawah ini, setelah memanggil metode Checkpoint(), selanjutnya panggil metode Forecast.

    Forecast(secondYearData, 7, forecastEngine, mlContext);
    
  2. Jalankan aplikasi. Keluaran yang mirip dengan yang di bawah ini akan muncul pada konsol. Untuk kejelasan, output telah dipadatkan.

    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 penyewaan 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 dotnet/machinelearning-samples repositori.

Langkah berikutnya