Пример #1
0
        public void Forecast(IDataView compareAgainst, int horizon, TimeSeriesPredictionEngine <ModelInput, ModelOutput> forecaster, MLContext mlContext)
        {
            ModelOutput forecast = forecaster.Predict(horizon);

            IEnumerable <string> forecastOutput =
                mlContext.Data.CreateEnumerable <ModelInput>(compareAgainst, reuseRowObject: false)
                .Take(horizon)
                .Select((ModelInput input, int index) =>
            {
                string purchaseDate = input.Date.ToString("yyyy-MM-dd");
                float actualSales   = input.TotalSold;
                float lowerEstimate = Math.Max(0, forecast.LowerBoundTotalSold[index]);
                float estimate      = forecast.ForecastedTotalSold[index];
                float upperEstimate = forecast.UpperBoundTotalSold[index];
                return($"Date: {purchaseDate}\n" +
                       $"Actual Sales: {actualSales}\n" +
                       $"Lower Estimate: {lowerEstimate}\n" +
                       $"Forecast: {estimate}\n" +
                       $"Upper Estimate: {upperEstimate}\n");
            });

            Console.WriteLine("Purchase Forecast");
            Console.WriteLine("---------------------");
            foreach (var prediction in forecastOutput)
            {
                Console.WriteLine(prediction);
            }
        }
Пример #2
0
        static void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine <ModelInput, ModelOutput> forecaster, MLContext mlContext)
        {
            ModelOutput forecast = forecaster.Predict();
            int         i        = 0;

            IEnumerable <string> forecastOutput =
                mlContext.Data.CreateEnumerable <ModelInput>(testData, reuseRowObject: false)
                .Take(horizon)
                .Select((ModelInput rental, int index) =>
            {
                i++;

                string Date         = rental.Invoice_Date.ToShortDateString();
                float actualDays    = rental.OverDue_Days;
                float lowerEstimate = Math.Max(0, forecast.MinimumDays[index]);
                float estimate      = forecast.ForecastedDays[index];
                float upperEstimate = forecast.MaximumDays[index];
                return
                //  $"No                    : {i}\n" +
                ($"Date                  : {Date}\n" +
                 $"Actual Days           : {actualDays}\n" +
                 $"Lower Estimate Days   : {lowerEstimate}\n" +
                 $"Forecast Days         : {estimate}\n" +
                 $"Upper Estimate Days   : {upperEstimate}\n");
            });

            // Output predictions
            Console.WriteLine("Rental Forecast");
            Console.WriteLine("---------------------");
            foreach (var prediction in forecastOutput)
            {
                Console.WriteLine(prediction);
            }
        }
Пример #3
0
        /// <summary>
        /// Применение модели для прогнозирования спроса
        /// </summary>
        /// <param name="testData"></param>
        /// <param name="horizon"></param>
        /// <param name="forecaster"></param>
        /// <param name="mlContext"></param>
        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.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");
            });

            Console.WriteLine("Rental Forecast");
            Console.WriteLine("---------------------");
            foreach (var prediction in forecastOutput)
            {
                Console.WriteLine(prediction);
            }
        }
Пример #4
0
        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 passants, int index) =>
            {
                //string jour = Enum.GetName(typeof(DayOfWeek), passants.Jour);
                float semaine = passants.Semaine;
                float jour    = passants.Jour;
                //DateTime horaire = passants.Horaire;
                float actualPassants = passants.NbPassants;
                float lowerEstimate  = Math.Max(0, forecast.LowerBoundPassants[index]);
                float estimate       = forecast.ForecastedPassants[index];
                float upperEstimate  = forecast.UpperBoundPassants[index];
                return($"Date: {jour}\n" +
                       $"Actual Passants: {actualPassants}\n" +
                       $"Lower Estimate: {lowerEstimate}\n" +
                       $"Forecast: {estimate}\n" +
                       $"Upper Estimate: {upperEstimate}\n");
            });

            Console.WriteLine("Passants Forecast");
            Console.WriteLine("---------------------");
            foreach (var prediction in forecastOutput)
            {
                Console.WriteLine(prediction);
            }
        }
Пример #5
0
        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 sale, int index) =>
            {
                string SaleDate     = sale.SalesDate.ToShortDateString();
                float actualSale    = sale.TotalSales;
                float lowerEstimate = Math.Max(0, forecast.LowerBoundSales[index]);
                float estimate      = forecast.ForecastedSales[index];
                float upperEstimate = forecast.UpperBoundSales[index];
                return($"Date: {SaleDate}\n" +
                       $"Actual Rentals: {actualSale}\n" +
                       $"Lower Estimate: {lowerEstimate}\n" +
                       $"Forecast: {estimate}\n" +
                       $"Upper Estimate: {upperEstimate}\n");
            });

            foreach (var prediction in forecastOutput)
            {
                Console.WriteLine(prediction);
            }
        }
Пример #6
0
        private static void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine <ModelInput, ModelOutput> forecaster)
        {
            var forecast = forecaster.Predict();

            // Align actual & forecast values for seven periods
            var 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}");
            });

            Console.WriteLine("Rental Forecast");
            Console.WriteLine("--------------------");
            foreach (var prediction in forecastOutput)
            {
                Console.WriteLine(prediction);
                Console.WriteLine("");
            }
        }
        static List <ModelOutputExt> Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine <ModelInput, ModelOutput> forecaster, MLContext mlContext)
        {
            ModelOutput           forecast  = forecaster.Predict();
            List <ModelOutputExt> moextList = new List <ModelOutputExt>();

            IEnumerable <ModelOutputExt> forecastOutput =
                mlContext.Data.CreateEnumerable <ModelInput>(testData, reuseRowObject: false)
                .Take(horizon)
                .Select((ModelInput sale, int index) =>
            {
                ModelOutputExt mext  = new ModelOutputExt();
                mext.ForecastedSales = (float)(Math.Max(0, Math.Round(forecast.ForecastedSales[index], 0)));
                mext.LowerBoundSales = Math.Max(0, forecast.LowerBoundSales[index]);
                mext.UpperBoundSales = forecast.UpperBoundSales[index];
                mext.SalesDate       = sale.SalesDate.ToShortDateString();
                mext.TotalSales      = sale.TotalSales;
                mext.indexX          = index;
                return(mext);
            });


            foreach (var prediction in forecastOutput)
            {
                moextList.Add(prediction);
            }
            return(moextList);
        }
Пример #8
0
        static void Forecast(IDataView data, int horizon, TimeSeriesPredictionEngine <InputModel, OutputModel> forecaster, MLContext context)
        {
            var originalData = context.Data.CreateEnumerable <InputModel>(data, false);

            var forecast = forecaster.Predict();

            var forecastOutput = context
                                 .Data
                                 .CreateEnumerable <InputModel>(data, false)
                                 .Take(horizon)
                                 .Select((InputModel sell, int index) =>
            {
                var pastYearsSells = originalData.Where(item => item.SellMonth.Equals(index + 1)).OrderBy(item => item.SellYear);

                var stringfiedPastYearsSells = pastYearsSells.Select(item => $"\t{item.SellYear} sells: {item.Value}\n");

                var month           = sell.SellMonth;
                float actualSells   = sell.Value;
                float lowerEstimate = Math.Max(0, forecast.LowerBoundSells[index]);
                float estimate      = forecast.ForecastedSells[index];
                float upperEstimate = forecast.UpperBoundSells[index];

                return($"Month: {month}\n" +
                       $"Other Year Sells:\n{string.Concat(stringfiedPastYearsSells)}\n" +
                       $"Lower Estimate: {lowerEstimate}\n" +
                       $"Forecast: {estimate}\n" +
                       $"Upper Estimate: {upperEstimate}\n");
            });

            foreach (var item in forecastOutput)
            {
                Console.WriteLine(item);
            }
        }
Пример #9
0
        static void Main(string[] args)
        {
            var mlContext = new MLContext();


            int   c = 0;
            float predictedPrice = 0;

            while (c < 10)
            {
                IEnumerable <BTC_TimeSeries> data = GetTrainingData(mlContext);


                IDataView trainingData = mlContext.Data.LoadFromEnumerable <BTC_TimeSeries>(data);
                var       offset       = TimeSpan.FromSeconds(data.Last().TimeStamp);
                var       epoch        = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                DateTime  lastTime     = epoch.Add(offset).ToLocalTime();

                int seriesLength = data.Count();

                var estimator = mlContext.Forecasting.ForecastBySsa(outputColumnName: nameof(PredictedSeries.ForecastedPrice),
                                                                    inputColumnName: nameof(BTC_TimeSeries.Price),
                                                                    windowSize: 360,
                                                                    seriesLength: seriesLength,
                                                                    trainSize: seriesLength,
                                                                    horizon: 5,
                                                                    confidenceLevel: 0.95f,
                                                                    confidenceLowerBoundColumn: nameof(PredictedSeries.ConfidenceLowerBound),
                                                                    confidenceUpperBoundColumn: nameof(PredictedSeries.ConfidenceUpperBound)
                                                                    );

                Console.WriteLine("Training model");
                ITransformer forecastTransformer = estimator.Fit(trainingData);

                TimeSeriesPredictionEngine <BTC_TimeSeries, PredictedSeries> forecastEngine = forecastTransformer.CreateTimeSeriesEngine <BTC_TimeSeries, PredictedSeries>(mlContext);

                PredictedSeries predictions = forecastEngine.Predict();
                Console.WriteLine("last read time {0}: last read price {1}", lastTime, data.Last().Price);
                for (int i = 0; i < predictions.ForecastedPrice.Count(); i++)
                {
                    lastTime = lastTime.AddMinutes(15);
                    Console.WriteLine("{0} price: {1}, low: {2}, high: {3}", lastTime, predictions.ForecastedPrice[i].ToString(), predictions.ConfidenceLowerBound[i].ToString(), predictions.ConfidenceUpperBound[i].ToString());
                }

                float delta = predictedPrice - data.Last().Price;
                Console.WriteLine("Delta, {0}", delta);
                predictedPrice = predictions.ForecastedPrice[0];
                forecastEngine.CheckPoint(mlContext, "forecastmodel.zip");

                System.Threading.Thread.Sleep(300000);
                c++;
            }


            Console.Read();
        }
Пример #10
0
        static ModelOutput Forecast(IEnumerable <ModelInput> testData, int horizon, TimeSeriesPredictionEngine <ModelInput, ModelOutput> forecaster, MLContext mlContext, string value)
        {
            ModelOutput forecast = forecaster.Predict();

            IEnumerable <string> forecastOutput =
                testData.TakeLast(horizon)
                .Select((ModelInput values, int index) =>
            {
                string rentalDate = values.OpenTime.ToString();
                float actualValue;
                switch (value)
                {
                case "Close":
                    actualValue = values.Close;
                    break;

                case "High":
                    actualValue = values.High;
                    break;

                case "Low":
                    actualValue = values.Low;
                    break;

                default:
                    actualValue = values.Close;
                    break;
                }

                float lowerEstimate = forecast.LowerBoundValue[index];
                float estimate      = forecast.ForecastedValue[index];
                float upperEstimate = forecast.UpperBoundValue[index];
                return($"Date: {rentalDate}\n" +
                       $"Actual {value}: {actualValue}\n" +
                       $"Forecast: {estimate}\n");
            });

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

            return(forecast);
        }
Пример #11
0
        static void Predict()
        {
            //prediction engine based on our fitted model
            TimeSeriesPredictionEngine <BTCDataModel, PredictedSeriesDataModel> forecastEngine = forecastTransformer.CreateTimeSeriesEngine <BTCDataModel, PredictedSeriesDataModel>(mlContext);

            //call to predict the next 5 minutes
            PredictedSeriesDataModel predictions = forecastEngine.Predict();

            //write our predictions
            for (int i = 0; i < predictions.ForecastedPrice.Count(); i++)
            {
                lastTime = lastTime.AddMinutes(1);
                Console.WriteLine("{0} price: {1}, low: {2}, high: {3}, actual: {4}", lastTime, predictions.ForecastedPrice[i].ToString(), predictions.ConfidenceLowerBound[i].ToString(), predictions.ConfidenceUpperBound[i].ToString(), testingData[i].Amount);
            }


            //instead of saving, we use checkpoint. This allows us to continue training with updated data and not need to keep such a large data set
            //so we can append Jan. 2021 without having everythign before to train the model speeding up the process
            forecastEngine.CheckPoint(mlContext, fileName);
        }
Пример #12
0
        private static void Main(string[] args)
        {
            _mlContext = new MLContext();

            // Load data from db
            IDataView dataView       = LoadDataFromDB();
            var       firstYearData  = _mlContext.Data.FilterRowsByColumn(dataView, "Year", upperBound: 1);
            var       secondYearData = _mlContext.Data.FilterRowsByColumn(dataView, "Year", lowerBound: 1);

            // Create forecasting model
            var forecaster = ProcessData(firstYearData);

            // Evaluate forecasting model
            Evaluate(secondYearData, forecaster);

            // Save model to zip file
            _forecastEngine = forecaster.CreateTimeSeriesEngine <ModelInput, ModelOutput>(_mlContext);
            _forecastEngine.CheckPoint(_mlContext, modelPath);

            // Use model for forecast
            Forecast(secondYearData, 7, _forecastEngine);
        }
Пример #13
0
        /// <summary>
        /// Crea el modelo y lo guarda en el path entrado
        /// </summary>
        /// <param name="mlContext">ML.NET context.</param>
        /// <param name="productId">Id of the product series to forecast.</param>
        /// <param name="dataPath">Input data file path.</param>
        private static void CreateAndSaveModelTimeSeries(MLContext mlContext, string dataPath, float id)
        {
            var productModelPath = $"product{id}_month_timeSeriesSSA.zip";

            if (File.Exists(productModelPath))
            {
                File.Delete(productModelPath);
            }
            IDataView saleDataView            = LoadData(mlContext, dataPath, id);
            var       singleProductDataSeries = mlContext.Data.CreateEnumerable <SaleData>(saleDataView, false).OrderBy(p => p.ano).ThenBy(p => p.mes);
            SaleData  lastMonthSalesData      = singleProductDataSeries.Last();

            Console.WriteLine("Creando el modelo: Time Series Model");

            const int numSeriesDataPoints = 34;
            IEstimator <ITransformer> forecastEstimator = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(ProductUnitTimeSeriesPrediction.ForecastedProductUnits),
                inputColumnName: nameof(SaleData.unidades),                                                // This is the column being forecasted.
                windowSize: 12,                                                                            // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: numSeriesDataPoints,                                                         // This parameter specifies the number of data points that are used when performing a forecast.
                trainSize: numSeriesDataPoints,                                                            // This parameter specifies the total number of data points in the input time series, starting from the beginning.
                horizon: 2,                                                                                // Indicates the number of values to forecast; 2 indicates that the next 2 months of product units will be forecasted.
                confidenceLevel: 0.95f,                                                                    // Indicates the likelihood the real observed value will fall within the specified interval bounds.
                confidenceLowerBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceLowerBound),  //This is the name of the column that will be used to store the lower interval bound for each forecasted value.
                confidenceUpperBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceUpperBound)); //This is the name of the column that will be used to store the upper interval bound for each forecasted value.

            // Fit the forecasting model to the specified product's data series.
            ITransformer forecastTransformer = forecastEstimator.Fit(saleDataView);

            // Create the forecast engine used for creating predictions.
            TimeSeriesPredictionEngine <SaleData, ProductUnitTimeSeriesPrediction> forecastEngine = forecastTransformer.CreateTimeSeriesEngine <SaleData, ProductUnitTimeSeriesPrediction>(mlContext);

            // Save the forecasting model so that it can be loaded within an end-user app.
            forecastEngine.CheckPoint(mlContext, productModelPath);
            TestPrediction(mlContext, lastMonthSalesData, productModelPath);
        }
        private static void SaveModel(MLContext context, ITransformer model)
        {
            TimeSeriesPredictionEngine <ModelInput, ModelOutput> forecastEngine = model.CreateTimeSeriesEngine <ModelInput, ModelOutput>(context);

            forecastEngine.CheckPoint(context, MODEL_PATH);
        }
Пример #15
0
        public async Task <IActionResult> GetProductUnitDemandEstimation(string productId)
        {
            // Get product history.
            var productHistory = await _queries.GetProductDataAsync(productId);

            // Supplement the history with synthetic data.
            var supplementedProductHistory       = TimeSeriesDataGenerator.SupplementData(mlContext, productHistory);
            var supplementedProductHistoryLength = supplementedProductHistory.Count(); // 36
            var supplementedProductDataView      = mlContext.Data.LoadFromEnumerable(supplementedProductHistory);

            // Create and add the forecast estimator to the pipeline.
            IEstimator <ITransformer> forecastEstimator = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(ProductUnitTimeSeriesPrediction.ForecastedProductUnits),
                inputColumnName: nameof(ProductData.units),                                                // This is the column being forecasted.
                windowSize: 12,                                                                            // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: supplementedProductHistoryLength,                                            // TODO: Need clarification on what this should be set to; assuming product series length for now.
                trainSize: supplementedProductHistoryLength,                                               // TODO: Need clarification on what this should be set to; assuming product series length for now.
                horizon: 1,                                                                                // Indicates the number of values to forecast; 1 indicates that the next month of product units will be forecasted.
                confidenceLevel: 0.95f,                                                                    // TODO: Is this the same as prediction interval, where this indicates that we are 95% confidence that the forecasted value will fall within the interval range?
                confidenceLowerBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceLowerBound),  // TODO: See above comment.
                confidenceUpperBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceUpperBound)); // TODO: See above comment.

            // Train the forecasting model for the specified product's data series.
            ITransformer forecastTransformer = forecastEstimator.Fit(supplementedProductDataView);

            // Create the forecast engine used for creating predictions.
            TimeSeriesPredictionEngine <ProductData, ProductUnitTimeSeriesPrediction> forecastEngine = forecastTransformer.CreateTimeSeriesEngine <ProductData, ProductUnitTimeSeriesPrediction>(mlContext);

            // Predict.
            var nextMonthUnitDemandEstimation = forecastEngine.Predict();

            return(Ok(nextMonthUnitDemandEstimation.ForecastedProductUnits.First()));
        }
Пример #16
0
        public async Task <IActionResult> GetProductUnitDemandEstimation(string productId)
        {
            // Get product history for the selected product
            var productHistory = await _queries.GetProductDataAsync(productId);

            var productDataView = mlContext.Data.LoadFromEnumerable(productHistory);

            // Create and add the forecast estimator to the pipeline.
            IEstimator <ITransformer> forecastEstimator = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(ProductUnitTimeSeriesPrediction.ForecastedProductUnits),
                inputColumnName: nameof(ProductData.units),                                                // This is the column being forecasted.
                windowSize: 12,                                                                            // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: productHistory.Count(),                                                      // This parameter specifies the number of data points that are used when performing a forecast.
                trainSize: productHistory.Count(),                                                         // This parameter specifies the total number of data points in the input time series, starting from the beginning.
                horizon: 1,                                                                                // Indicates the number of values to forecast; 1 indicates that the next month of product units will be forecasted.
                confidenceLevel: 0.95f,                                                                    // Indicates the likelihood the real observed value will fall within the specified interval bounds.
                confidenceLowerBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceLowerBound),  //This is the name of the column that will be used to store the lower interval bound for each forecasted value.
                confidenceUpperBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceUpperBound)); //This is the name of the column that will be used to store the upper interval bound for each forecasted value.

            // Train the forecasting model for the specified product's data series.
            ITransformer forecastTransformer = forecastEstimator.Fit(productDataView);

            // Create the forecast engine used for creating predictions.
            TimeSeriesPredictionEngine <ProductData, ProductUnitTimeSeriesPrediction> forecastEngine = forecastTransformer.CreateTimeSeriesEngine <ProductData, ProductUnitTimeSeriesPrediction>(mlContext);

            // Predict.
            var nextMonthUnitDemandEstimation = forecastEngine.Predict();

            return(Ok(nextMonthUnitDemandEstimation.ForecastedProductUnits.First()));
        }
        /// <summary>
        /// Build model for predicting next month's product unit sales using time series forecasting.
        /// </summary>
        /// <param name="mlContext">ML.NET context.</param>
        /// <param name="productDataSeries">ML.NET IDataView representing the loaded product data series.</param>
        /// <param name="outputModelPath">Trained model path.</param>
        private static void TrainAndSaveModel(MLContext mlContext, IDataView productDataView, string outputModelPath)
        {
            ConsoleWriteHeader("Training product forecasting Time Series model");

            var supplementedProductDataSeries       = TimeSeriesDataGenerator.SupplementData(mlContext, productDataView);
            var supplementedProductDataSeriesLength = supplementedProductDataSeries.Count(); // 36
            var supplementedProductDataView         = mlContext.Data.LoadFromEnumerable(supplementedProductDataSeries, productDataView.Schema);

            // Create and add the forecast estimator to the pipeline.
            IEstimator <ITransformer> forecastEstimator = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(ProductUnitTimeSeriesPrediction.ForecastedProductUnits),
                inputColumnName: nameof(ProductData.units),                                                // This is the column being forecasted.
                windowSize: 12,                                                                            // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: supplementedProductDataSeriesLength,                                         // TODO: Need clarification on what this should be set to; assuming product series length for now.
                trainSize: supplementedProductDataSeriesLength,                                            // TODO: Need clarification on what this should be set to; assuming product series length for now.
                horizon: 2,                                                                                // Indicates the number of values to forecast; 2 indicates that the next 2 months of product units will be forecasted.
                confidenceLevel: 0.95f,                                                                    // TODO: Is this the same as prediction interval, where this indicates that we are 95% confidence that the forecasted value will fall within the interval range?
                confidenceLowerBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceLowerBound),  // TODO: See above comment.
                confidenceUpperBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceUpperBound)); // TODO: See above comment.

            // Train the forecasting model for the specified product's data series.
            ITransformer forecastTransformer = forecastEstimator.Fit(supplementedProductDataView);

            // Create the forecast engine used for creating predictions.
            TimeSeriesPredictionEngine <ProductData, ProductUnitTimeSeriesPrediction> forecastEngine = forecastTransformer.CreateTimeSeriesEngine <ProductData, ProductUnitTimeSeriesPrediction>(mlContext);

            // Save the forecasting model so that it can be loaded within an end-user app.
            forecastEngine.CheckPoint(mlContext, outputModelPath);
        }
        /// <summary>
        /// Predict samples using saved model.
        /// </summary>
        /// <param name="mlContext">ML.NET context.</param>
        /// <param name="lastMonthProductData">The last month of product data in the monthly data series.</param>
        /// <param name="outputModelPath">Model file path</param>
        private static void TestPrediction(MLContext mlContext, ProductData lastMonthProductData, string outputModelPath)
        {
            ConsoleWriteHeader("Testing product unit sales forecast Time Series model");

            // Load the forecast engine that has been previously saved.
            ITransformer forecaster;

            using (var file = File.OpenRead(outputModelPath))
            {
                forecaster = mlContext.Model.Load(file, out DataViewSchema schema);
            }

            // We must create a new prediction engine from the persisted model.
            TimeSeriesPredictionEngine <ProductData, ProductUnitTimeSeriesPrediction> forecastEngine = forecaster.CreateTimeSeriesEngine <ProductData, ProductUnitTimeSeriesPrediction>(mlContext);

            // Get the prediction; this will include the forecasted product units sold for the next 2 months since this the time period specified in the `horizon` parameter when the forecast estimator was originally created.
            Console.WriteLine("\n** Original prediction **");
            ProductUnitTimeSeriesPrediction originalSalesPrediction = forecastEngine.Predict();

            // Compare the units of the first forecasted month to the actual units sold for the next month.
            var predictionMonth = lastMonthProductData.month == 12 ? 1 : lastMonthProductData.month + 1;
            var predictionYear  = predictionMonth < lastMonthProductData.month ? lastMonthProductData.year + 1 : lastMonthProductData.year;

            Console.WriteLine($"Product: {lastMonthProductData.productId}, Month: {predictionMonth}, Year: {predictionYear} " +
                              $"- Real Value (units): {lastMonthProductData.next}, Forecasted (units): {originalSalesPrediction.ForecastedProductUnits[0]}");

            // Get the first forecasted month's confidence interval bounds.
            Console.WriteLine($"Confidence interval: [{originalSalesPrediction.ConfidenceLowerBound[0]} - {originalSalesPrediction.ConfidenceUpperBound[0]}]\n");

            // Get the units of the second forecasted month.
            Console.WriteLine($"Product: {lastMonthProductData.productId}, Month: {lastMonthProductData.month + 2}, Year: {lastMonthProductData.year}, " +
                              $"Forecasted (units): {originalSalesPrediction.ForecastedProductUnits[1]}");

            // Get the second forecasted month's confidence interval bounds.
            Console.WriteLine($"Confidence interval: [{originalSalesPrediction.ConfidenceLowerBound[1]} - {originalSalesPrediction.ConfidenceUpperBound[1]}]\n");

            // Update the forecasting model with the next month's actual product data to get an updated prediction; this time, only forecast product sales for 1 month ahead.
            Console.WriteLine("** Updated prediction **");
            ProductData newProductData = SampleProductData.MonthlyData.Where(p => p.productId == lastMonthProductData.productId).Single();
            ProductUnitTimeSeriesPrediction updatedSalesPrediction = forecastEngine.Predict(newProductData, horizon: 1);

            // Save the updated forecasting model.
            forecastEngine.CheckPoint(mlContext, outputModelPath);

            // Get the units of the updated forecast.
            predictionMonth = lastMonthProductData.month >= 11 ? (lastMonthProductData.month + 2) % 12 : lastMonthProductData.month + 2;
            predictionYear  = predictionMonth < lastMonthProductData.month ? lastMonthProductData.year + 1 : lastMonthProductData.year;
            Console.WriteLine($"Product: {lastMonthProductData.productId}, Month: {predictionMonth}, Year: {predictionYear}, " +
                              $"Forecasted (units): {updatedSalesPrediction.ForecastedProductUnits[0]}");

            // Get the updated forecast's confidence interval bounds.
            Console.WriteLine($"Confidence interval: [{updatedSalesPrediction.ConfidenceLowerBound[0]} - {updatedSalesPrediction.ConfidenceUpperBound[0]}]\n");
        }
 /// <summary>
 /// Forecasts a number of values
 /// </summary>
 /// <param name="context">The common context for all ML.NET operations.</param>
 /// <param name="trainer">A trainer to retrieve the transformer.</param>
 public Forecaster(MLContext context, Trainer trainer)
 {
     timeSeriesPredictionEngine = trainer.Transformer.CreateTimeSeriesEngine <ModelInput, ModelOutput>(context);
 }
        public IEnumerable <RatioAnalysis> Predict(IEnumerable <RatioAnalysis> data)
        {
            var mlContext = new MLContext(seed: 1);

            IEstimator <ITransformer> costofgoodsForcaster = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(RatioAnalysisPrediction.Forecasted),
                inputColumnName: nameof(RatioAnalysis.CostOfGoods),                                // This is the column being forecasted.
                windowSize: 12,                                                                    // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: data.Count(),                                                        // This parameter specifies the number of data points that are used when performing a forecast.
                trainSize: data.Count(),                                                           // This parameter specifies the total number of data points in the input time series, starting from the beginning.
                horizon: 3,                                                                        // Indicates the number of values to forecast; 3 indicates that the next 3 months of product units will be forecasted.
                confidenceLevel: 0.75f,                                                            // Indicates the likelihood the real observed value will fall within the specified interval bounds.
                confidenceLowerBoundColumn: nameof(RatioAnalysisPrediction.ConfidenceLowerBound),  //This is the name of the column that will be used to store the lower interval bound for each forecasted value.
                confidenceUpperBoundColumn: nameof(RatioAnalysisPrediction.ConfidenceUpperBound)); //This is the name of the column that will be used to store the upper interval bound for each forecasted value.

            IEstimator <ITransformer> inventoryForcaster = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(RatioAnalysisPrediction.Forecasted),
                inputColumnName: nameof(RatioAnalysis.Inventory),                                  // This is the column being forecasted.
                windowSize: 12,                                                                    // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: data.Count(),                                                        // This parameter specifies the number of data points that are used when performing a forecast.
                trainSize: data.Count(),                                                           // This parameter specifies the total number of data points in the input time series, starting from the beginning.
                horizon: 3,                                                                        // Indicates the number of values to forecast; 3 indicates that the next 3 months of product units will be forecasted.
                confidenceLevel: 0.75f,                                                            // Indicates the likelihood the real observed value will fall within the specified interval bounds.
                confidenceLowerBoundColumn: nameof(RatioAnalysisPrediction.ConfidenceLowerBound),  //This is the name of the column that will be used to store the lower interval bound for each forecasted value.
                confidenceUpperBoundColumn: nameof(RatioAnalysisPrediction.ConfidenceUpperBound)); //This is the name of the column that will be used to store the upper interval bound for each forecasted value.

            IEstimator <ITransformer> turnoverForcaster = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(RatioAnalysisPrediction.Forecasted),
                inputColumnName: nameof(RatioAnalysis.Turnover),                                   // This is the column being forecasted.
                windowSize: 12,                                                                    // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: data.Count(),                                                        // This parameter specifies the number of data points that are used when performing a forecast.
                trainSize: data.Count(),                                                           // This parameter specifies the total number of data points in the input time series, starting from the beginning.
                horizon: 3,                                                                        // Indicates the number of values to forecast; 3 indicates that the next 3 months of product units will be forecasted.
                confidenceLevel: 0.75f,                                                            // Indicates the likelihood the real observed value will fall within the specified interval bounds.
                confidenceLowerBoundColumn: nameof(RatioAnalysisPrediction.ConfidenceLowerBound),  //This is the name of the column that will be used to store the lower interval bound for each forecasted value.
                confidenceUpperBoundColumn: nameof(RatioAnalysisPrediction.ConfidenceUpperBound)); //This is the name of the column that will be used to store the upper interval bound for each forecasted value.

            // Fit the forecasting model to the specified product's data series.
            ITransformer costofgoodsTransformer = costofgoodsForcaster.Fit(mlContext.Data.LoadFromEnumerable(data));
            ITransformer inventoryTransformer   = inventoryForcaster.Fit(mlContext.Data.LoadFromEnumerable(data));
            ITransformer turnoverTransformer    = turnoverForcaster.Fit(mlContext.Data.LoadFromEnumerable(data));

            // Create the forecast engine used for creating predictions.
            TimeSeriesPredictionEngine <RatioAnalysis, RatioAnalysisPrediction> inventoryEngine  = inventoryTransformer.CreateTimeSeriesEngine <RatioAnalysis, RatioAnalysisPrediction>(mlContext);
            TimeSeriesPredictionEngine <RatioAnalysis, RatioAnalysisPrediction> turneroverEngine = turnoverTransformer.CreateTimeSeriesEngine <RatioAnalysis, RatioAnalysisPrediction>(mlContext);
            TimeSeriesPredictionEngine <RatioAnalysis, RatioAnalysisPrediction> costofgoodEngine = costofgoodsTransformer.CreateTimeSeriesEngine <RatioAnalysis, RatioAnalysisPrediction>(mlContext);

            // Get the prediction; this will include the forecasted turnover for the next 3 months since this
            //the time period specified in the `horizon` parameter when the forecast estimator was originally created.
            var turnoverPrediction  = turneroverEngine.Predict();
            var costPrediction      = costofgoodEngine.Predict();
            var inventoryPrediction = inventoryEngine.Predict();

            var last   = data.Last();
            var retVal = data.ToList();

            for (int i = 0; i < turnoverPrediction.Forecasted.Count(); i++)
            {
                retVal.Add(new RatioAnalysis
                {
                    Date             = last.Date.AddMonths(i + 1),
                    CostOfGoods      = costPrediction.Forecasted[i],
                    CostOfGoodsDelta = costPrediction.ConfidenceUpperBound[i] - costPrediction.Forecasted[i],
                    Inventory        = inventoryPrediction.Forecasted[i],
                    InventoryDelta   = inventoryPrediction.ConfidenceUpperBound[i] - inventoryPrediction.Forecasted[i],
                    Turnover         = turnoverPrediction.Forecasted[i],
                    TurnoverDelta    = turnoverPrediction.ConfidenceUpperBound[i] - turnoverPrediction.Forecasted[i]
                });
            }

            return(retVal);
        }
        /// <summary>
        /// Build model for predicting next month's product unit sales using time series forecasting.
        /// </summary>
        /// <param name="mlContext">ML.NET context.</param>
        /// <param name="productDataSeries">ML.NET IDataView representing the loaded product data series.</param>
        /// <param name="outputModelPath">Model path.</param>
        private static void FitAndSaveModel(MLContext mlContext, IDataView productDataSeries, string outputModelPath)
        {
            ConsoleWriteHeader("Fitting product forecasting Time Series model");

            const int numSeriesDataPoints = 34; //The underlying data has a total of 34 months worth of data for each product

            // Create and add the forecast estimator to the pipeline.
            IEstimator <ITransformer> forecastEstimator = mlContext.Forecasting.ForecastBySsa(
                outputColumnName: nameof(ProductUnitTimeSeriesPrediction.ForecastedProductUnits),
                inputColumnName: nameof(ProductData.units),                                                // This is the column being forecasted.
                windowSize: 12,                                                                            // Window size is set to the time period represented in the product data cycle; our product cycle is based on 12 months, so this is set to a factor of 12, e.g. 3.
                seriesLength: numSeriesDataPoints,                                                         // This parameter specifies the number of data points that are used when performing a forecast.
                trainSize: numSeriesDataPoints,                                                            // This parameter specifies the total number of data points in the input time series, starting from the beginning.
                horizon: 2,                                                                                // Indicates the number of values to forecast; 2 indicates that the next 2 months of product units will be forecasted.
                confidenceLevel: 0.95f,                                                                    // Indicates the likelihood the real observed value will fall within the specified interval bounds.
                confidenceLowerBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceLowerBound),  //This is the name of the column that will be used to store the lower interval bound for each forecasted value.
                confidenceUpperBoundColumn: nameof(ProductUnitTimeSeriesPrediction.ConfidenceUpperBound)); //This is the name of the column that will be used to store the upper interval bound for each forecasted value.

            // Fit the forecasting model to the specified product's data series.
            ITransformer forecastTransformer = forecastEstimator.Fit(productDataSeries);

            // Create the forecast engine used for creating predictions.
            TimeSeriesPredictionEngine <ProductData, ProductUnitTimeSeriesPrediction> forecastEngine = forecastTransformer.CreateTimeSeriesEngine <ProductData, ProductUnitTimeSeriesPrediction>(mlContext);

            // Save the forecasting model so that it can be loaded within an end-user app.
            forecastEngine.CheckPoint(mlContext, outputModelPath);
        }