Я только начал с 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; }
}
Но прогнозные значения возвращают странные результаты: