Прогноз SSA с ML. NET возвращает странные результаты - PullRequest
0 голосов
/ 26 февраля 2020

Я только начал с ML. NET, поэтому я попытался адаптировать учебник из Microsoft к своему коду, который должен предсказывать бронирование в будущем:

static void Main(string[] args)
{
    MLContext mlContext = new MLContext();
    ModelInput[] modelInputFirstYear = Database.Instance.GetBookingsOfYear(2018).ToArray();
    ModelInput[] modelInputSecondYear = Database.Instance.GetBookingsOfYear(2019).ToArray();
    modelInputFirstYear = FillDates(modelInputFirstYear); //FillDates fills the array on days where no bookings were made with a date and the TotalBookings = 0, so it has 365 items
    modelInputSecondYear = FillDates(modelInputSecondYear);
    IDataView firstYear = mlContext.Data.LoadFromEnumerable<ModelInput>(modelInputFirstYear);
    IDataView secondYear = mlContext.Data.LoadFromEnumerable<ModelInput>(modelInputSecondYear);

    var forecastingPipeline = mlContext.Forecasting.ForecastBySsa(
        outputColumnName: "ForecastedBookings",
        inputColumnName: "TotalBookings",
        windowSize: 7, 
        seriesLength: 30,
        trainSize: 365, 
        horizon: 7,
        confidenceLevel: 0.95f,
        confidenceLowerBoundColumn: "LowerBoundBookings",
        confidenceUpperBoundColumn: "UpperBoundBookings");

    SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYear);
    Evaluate(secondYear, forecaster, mlContext);
    var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);
    Forecast(secondYear, 7, forecastEngine, mlContext);
}

private static void Evaluate(IDataView testData, ITransformer model, MLContext mlContext)
{
    IDataView predictions = model.Transform(testData);
    IEnumerable<float> actual = mlContext.Data.CreateEnumerable<ModelInput>(testData, true).Select(observed => observed.TotalBookings);
    IEnumerable<float> forecast = mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true).Select(prediction => prediction.ForecastedBookings[0]);
    var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);
    var MAE = metrics.Average(error => Math.Abs(error));
    var RMSE = Math.Sqrt(metrics.Average(error => Math.Pow(error, 2))); 
    Console.WriteLine(" > Evaluation Metrics");
    Console.WriteLine($"     > Mean Absolute Error: {MAE:F3}");
    Console.WriteLine($"     > Root Mean Squared Error: {RMSE:F3}\n");
}

private static void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext)
{
    ModelOutput forecast = forecaster.Predict();
    IEnumerable<string> forecastOutput = mlContext.Data.CreateEnumerable<ModelInput>(testData, reuseRowObject: false)
    .Take(horizon)
    .Select((ModelInput rental, int index) =>
    {
        string rentalDate = rental.BookingDate.ToShortDateString();
        float actualRentals = rental.TotalBookings;
        float lowerEstimate = Math.Max(0, forecast.LowerBoundBookings[index]);
        float estimate = forecast.ForecastedBookings[index];
        float upperEstimate = forecast.UpperBoundBookings[index];
        return $"Date: {rentalDate}\n" +
        $"Actual Rentals: {actualRentals}\n" +
        $"Lower Estimate: {lowerEstimate}\n" +
        $"Forecast: {estimate}\n" +
        $"Upper Estimate: {upperEstimate}\n";
    });
    Console.WriteLine(" > Rental Forecast");
    Console.WriteLine("");
    foreach (var prediction in forecastOutput)
    {
        Console.WriteLine(prediction);
    }
}

ModelInput и ModelOutput Классы:

public class ModelInput 
{
    public DateTime BookingDate { get; set; }
    public float Year { get; set; }
    public float TotalBookings { get; set; }
}

public class ModelOutput
{
    public float[] ForecastedBookings { get; set; }
    public float[] LowerBoundBookings { get; set; }
    public float[] UpperBoundBookings { get; set; }
}

Но прогнозные значения возвращают странные результаты:

Output of the Application

1 Ответ

0 голосов
/ 15 апреля 2020

Две идеи:

  1. У нас были некоторые проблемы с интернационализацией, и я заметил, что вы, кажется, используете запятые для представления десятичных точек. Можете ли вы попробовать использовать данные в формате США и посмотреть, решит ли это вашу проблему?
  2. Отрицательное значение может быть неточным. Я заметил, что вы берете максимум нижней границы и 0 в своем коде, но держу пари, что если вы вернете фактическую нижнюю границу, она также будет отрицательной. Возможно, ваши данные действительно указывают на отрицательную тенденцию.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...