public IList <double> Execute(IList <double> source) { var count = source.Count; if (count == 0) { return(new double[0]); } var res = new double[count]; var context = Context; Contract.Assert(context != null); var size = count / 2; var data = source.Take(size).Select(PredictionData.MakePredictionData); var ml = new MLContext(); var dataView = ml.Data.LoadFromEnumerable(data); const string outputColumnName = "Prediction"; const string inputColumnName = "Value"; var args = new SsaChangePointDetector.Arguments() { Source = inputColumnName, Name = outputColumnName, Confidence = Confidence, // The confidence for spike detection in the range [0, 100] ChangeHistoryLength = size / 4, // The length of the sliding window on p-values for computing the martingale score. TrainingWindowSize = size / 2, // The number of points from the beginning of the sequence used for training. SeasonalWindowSize = size / 8, // An upper bound on the largest relevant seasonality in the input time - series." }; // Train the change point detector. ITransformer model = new SsaChangePointEstimator(ml, args).Fit(dataView); // Create a prediction engine from the model for feeding new data. var engine = model.CreateTimeSeriesPredictionFunction <PredictionData, ChangePointPrediction>(ml); for (var i = size; i < count; i++) { var prediction = engine.Predict(PredictionData.MakePredictionData(source[i])); res[i] = prediction.Prediction[OutputNumber]; } return(res); }
// This example shows change point detection as above, but demonstrates how to train a model // that can run predictions on streaming data, and how to persist the trained model and then re-load it. public static void SsaChangePointDetectorPrediction() { // Create a new ML context, for ML.NET operations. It can be used for exception tracking and logging, // as well as the source of randomness. var ml = new MLContext(); // Generate sample series data with a recurring pattern const int SeasonalitySize = 5; const int TrainingSeasons = 3; const int TrainingSize = SeasonalitySize * TrainingSeasons; var data = new List <SsaChangePointData>(); for (int i = 0; i < TrainingSeasons; i++) { for (int j = 0; j < SeasonalitySize; j++) { data.Add(new SsaChangePointData(j)); } } // Convert data to IDataView. var dataView = ml.CreateStreamingDataView(data); // Setup SsaChangePointDetector arguments var inputColumnName = nameof(SsaChangePointData.Value); var outputColumnName = nameof(ChangePointPrediction.Prediction); var args = new SsaChangePointDetector.Arguments() { Source = inputColumnName, Name = outputColumnName, Confidence = 95, // The confidence for spike detection in the range [0, 100] ChangeHistoryLength = 8, // The length of the window for detecting a change in trend; shorter windows are more sensitive to spikes. TrainingWindowSize = TrainingSize, // The number of points from the beginning of the sequence used for training. SeasonalWindowSize = SeasonalitySize + 1 // An upper bound on the largest relevant seasonality in the input time series." }; // Train the change point detector. ITransformer model = new SsaChangePointEstimator(ml, args).Fit(dataView); // Create a prediction engine from the model for feeding new data. var engine = model.CreateTimeSeriesPredictionFunction <SsaChangePointData, ChangePointPrediction>(ml); // Start streaming new data points with no change point to the prediction engine. Console.WriteLine($"Output from ChangePoint predictions on new data:"); Console.WriteLine("Data\tAlert\tScore\tP-Value\tMartingale value"); ChangePointPrediction prediction = null; for (int i = 0; i < 5; i++) { var value = i; prediction = engine.Predict(new SsaChangePointData(value)); Console.WriteLine("{0}\t{1}\t{2:0.00}\t{3:0.00}\t{4:0.00}", value, prediction.Prediction[0], prediction.Prediction[1], prediction.Prediction[2], prediction.Prediction[3]); } // Now stream data points that reflect a change in trend. for (int i = 0; i < 5; i++) { var value = (i + 1) * 100; prediction = engine.Predict(new SsaChangePointData(value)); Console.WriteLine("{0}\t{1}\t{2:0.00}\t{3:0.00}\t{4:0.00}", value, prediction.Prediction[0], prediction.Prediction[1], prediction.Prediction[2], prediction.Prediction[3]); } // Now we demonstrate saving and loading the model. // Save the model that exists within the prediction engine. // The engine has been updating this model with every new data point. var modelPath = "model.zip"; engine.CheckPoint(ml, modelPath); // Load the model. using (var file = File.OpenRead(modelPath)) model = TransformerChain.LoadFrom(ml, file); // We must create a new prediction engine from the persisted model. engine = model.CreateTimeSeriesPredictionFunction <SsaChangePointData, ChangePointPrediction>(ml); // Run predictions on the loaded model. for (int i = 0; i < 5; i++) { var value = (i + 1) * 100; prediction = engine.Predict(new SsaChangePointData(value)); Console.WriteLine("{0}\t{1}\t{2:0.00}\t{3:0.00}\t{4:0.00}", value, prediction.Prediction[0], prediction.Prediction[1], prediction.Prediction[2], prediction.Prediction[3]); } // Output from ChangePoint predictions on new data: // Data Alert Score P-Value Martingale value // 0 0 - 1.01 0.50 0.00 // 1 0 - 0.24 0.22 0.00 // 2 0 - 0.31 0.30 0.00 // 3 0 0.44 0.01 0.00 // 4 0 2.16 0.00 0.24 // 100 0 86.23 0.00 2076098.24 // 200 0 171.38 0.00 809668524.21 // 300 1 256.83 0.01 22130423541.93 <-- alert is on, note that delay is expected // 400 0 326.55 0.04 241162710263.29 // 500 0 364.82 0.08 597660527041.45 <-- saved to disk // 100 0 - 58.58 0.15 1096021098844.34 <-- loaded from disk and running new predictions // 200 0 - 41.24 0.20 97579154688.98 // 300 0 - 30.61 0.24 95319753.87 // 400 0 58.87 0.38 14.24 // 500 0 219.28 0.36 0.05 }