/// <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); }
/// <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); }
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(); }
/// <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"); }
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); }
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); }
/// <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); }