17 using System.Collections.Generic;
19 using MathNet.Numerics;
20 using MathNet.Numerics.LinearAlgebra.Double;
21 using MathNet.Numerics.LinearRegression;
36 private List<double> _residuals;
37 private readonly
bool _intercept;
38 private bool _loggedOnceInMovingAverageStep;
39 private bool _loggedOnceInAutoRegressiveStep;
46 private readonly
int _diffOrder;
51 private readonly
int _arOrder;
56 private readonly
int _maOrder;
82 public override bool IsReady => _rollingData.IsReady;
119 bool intercept =
true
123 if (arOrder < 0 || maOrder < 0)
125 throw new ArgumentException(
"AR/MA orders cannot be negative.");
130 throw new ArgumentException(
"arOrder (p) must be greater than zero for all " +
131 "currently available fitting methods.");
134 if (period < Math.Max(arOrder, maOrder))
136 throw new ArgumentException(
"Period must exceed both arOrder and maOrder");
141 _diffOrder = diffOrder;
144 _intercept = intercept;
167 : this($
"ARIMA(({arOrder}, {diffOrder}, {maOrder}), {period}, {intercept})", arOrder, diffOrder, maOrder,
178 _rollingData.Reset();
188 _rollingData.Add((
double)input.
Value);
189 if (_rollingData.IsReady)
191 var arrayData = _rollingData.ToArray();
192 double[] diffHeads =
default;
193 arrayData = _diffOrder > 0 ?
DifferenceSeries(_diffOrder, arrayData, out diffHeads) : arrayData;
195 TwoStepFit(arrayData);
199 for (var i = 0; i < _arOrder; i++)
207 for (var i = 0; i < _maOrder; i++)
209 summants +=
MaParameters[i] * _residuals[_maOrder + i + 1];
217 var dataCast = arrayData.ToList();
218 dataCast.Insert(0, summants);
222 return (decimal)summants;
238 private void TwoStepFit(
double[] series)
240 _residuals =
new List<double>();
243 var lags = _arOrder > 0 ?
LaggedSeries(_arOrder, series) : new[] {series};
245 AutoRegressiveStep(lags, series, errorAr);
252 MovingAverageStep(lags, series, errorMa);
261 private void MovingAverageStep(
double[][] lags,
double[] data,
double errorMa)
263 var appendedData =
new List<double[]>();
264 var laggedErrors =
LaggedSeries(_maOrder, _residuals.ToArray());
265 for (var i = 0; i < laggedErrors.Length; i++)
267 var doubles = lags[i].ToList();
268 doubles.AddRange(laggedErrors[i]);
269 appendedData.Add(doubles.ToArray());
272 double[] maFits =
default;
277 maFits = Fit.MultiDim(appendedData.ToArray(), data.Skip(_maOrder).ToArray(),
278 method: DirectRegressionMethod.NormalEquations, intercept: _intercept);
282 if (!_loggedOnceInMovingAverageStep)
284 Logging.Log.Error($
"AutoRegressiveIntegratedMovingAverage.MovingAverageStep(): {ex.Message}");
285 _loggedOnceInMovingAverageStep =
true;
296 var size = appendedData.ToArray()[0].Length + (_intercept ? 1 : 0);
297 maFits =
new double[size];
302 maFits = Fit.MultiDim(appendedData.ToArray(), data.Skip(_maOrder).ToArray(),
303 method: DirectRegressionMethod.NormalEquations, intercept: _intercept);
306 for (var i = _maOrder; i < data.Length; i++)
308 var paramVector = _intercept
309 ? Vector.Build.Dense(maFits.Skip(1).ToArray())
310 : Vector.Build.Dense(maFits);
311 var residual = data[i] - Vector.Build.Dense(appendedData[i - _maOrder]).DotProduct(paramVector);
312 errorMa += Math.Pow(residual, 2);
318 MaResidualError = errorMa / (data.Length - Math.Max(_arOrder, _maOrder) - 1);
324 MaResidualError = errorMa / (data.Length - Math.Max(_arOrder, _maOrder) - 1);
337 private void AutoRegressiveStep(
double[][] lags,
double[] data,
double errorAr)
345 arFits = Fit.MultiDim(lags, data.Skip(_arOrder).ToArray(),
346 method: DirectRegressionMethod.NormalEquations);
350 if (!_loggedOnceInAutoRegressiveStep)
352 Logging.Log.Error($
"AutoRegressiveIntegratedMovingAverage.AutoRegressiveStep(): {ex.Message}");
353 _loggedOnceInAutoRegressiveStep =
true;
362 var size = lags.ToArray()[0].Length;
363 arFits =
new double[size];
369 arFits = Fit.MultiDim(lags, data.Skip(_arOrder).ToArray(),
370 method: DirectRegressionMethod.NormalEquations);
373 var fittedVec = Vector.Build.Dense(arFits);
375 for (var i = 0; i < data.Length; i++)
383 var residual = data[i] - Vector.Build.Dense(lags[i - _arOrder]).DotProduct(fittedVec);
384 errorAr += Math.Pow(residual, 2);
385 _residuals.Add(residual);