public StlFitStats(Decomposition stl) { int length = stl.Data.Length; // Unnecessary since STL guarantees this, so it can't be tested: // Preconditions.checkArgument(length >= 4, "STL Decomposition must have at least 4 data points"); double[] data = stl.Data; double[] trend = stl.Trend; double[] seasonal = stl.Seasonal; double[] residuals = stl.Residual; double dataSum = 0; double dataSqSum = 0; double trendSum = 0; double trendMax = -1E+100; double trendMin = 1E+100; double seasonalSum = 0; double seasonalSqSum = 0; double seasonalMax = -1E+100; double seasonalMin = 1E+100; double residualSum = 0; double residualSqSum = 0; double deSeasonalSum = 0; double deSeasonalSqSum = 0; double deTrendSum = 0; double deTrendSqSum = 0; for (int i = 0; (i < length); i++) { double d = data[i]; double t = trend[i]; double s = seasonal[i]; double r = residuals[i]; double f = d - s; double dt = d - t; dataSum = dataSum + d; dataSqSum = dataSqSum + d * d; trendSum = trendSum + t; if (t > trendMax) { trendMax = t; } if (t < trendMin) { trendMin = t; } seasonalSum = seasonalSum + s; seasonalSqSum = seasonalSqSum + s * s; if (s > seasonalMax) { seasonalMax = s; } if (s < seasonalMin) { seasonalMin = s; } residualSum = residualSum + r; residualSqSum = residualSqSum + r * r; deSeasonalSum = deSeasonalSum + f; deSeasonalSqSum = deSeasonalSqSum + f * f; deTrendSum = deTrendSum + dt; deTrendSqSum = deTrendSqSum + dt * dt; } double denom = 1.0 / length; fDataMean = dataSum * denom; fTrendMean = trendSum * denom; fSeasonalMean = seasonalSum * denom; fResidualMean = residualSum * denom; fDeSeasonalMean = deSeasonalSum * denom; fDeTrendMean = deTrendSum * denom; // The data is from a valid STL decomposition, so length = 4 at minimum. double corrBC = length / (length - 1.0); // Bessel's correction double denomBC = 1.0 / (length - 1.0); fDataVariance = dataSqSum * denomBC - fDataMean * fDataMean * corrBC; fTrendRange = trendMax - trendMin; fSeasonalVariance = seasonalSqSum * denomBC - fSeasonalMean * fSeasonalMean * corrBC; fSeasonalRange = seasonalMax - seasonalMin; fResidualVariance = residualSqSum * denomBC - fResidualMean * fResidualMean * corrBC; fDeSeasonalVariance = deSeasonalSqSum * denomBC - fDeSeasonalMean * fDeSeasonalMean * corrBC; fDeTrendVariance = deTrendSqSum * denomBC - fDeTrendMean * fDeTrendMean * corrBC; fResidualVarMLE = denom * residualSqSum; fResidualLogLikelihood = -0.5 * length * (1 + Math.Log(2 * Math.PI * fResidualVarMLE)); fSampleSize = length; }