예제 #1
0
        private void updateSeasonalAndTrend(bool useResidualWeights)
        {
            double[] data     = this.fDecomposition.fData;
            double[] trend    = this.fDecomposition.fTrend;
            double[] weights  = this.fDecomposition.fWeights;
            double[] seasonal = this.fDecomposition.fSeasonal;
            for (int i = 0; (i < data.Length); i++)
            {
                seasonal[i] = this.fExtendedSeasonal[this.fPeriodLength + i] - this.fDeSeasonalized[i];
                trend[i]    = data[i] - seasonal[i];
            }

            //  dumpDebugData("seasonal", seasonal);
            //  dumpDebugData("trend0", trend);
            double[] residualWeights = useResidualWeights ? weights : null;

            this.fLoessSmootherFactory.Data            = trend;
            this.fLoessSmootherFactory.ExternalWeights = residualWeights;
            LoessSmoother trendSmoother = this.fLoessSmootherFactory.build();

            //System.arraycopy(trendSmoother.smooth(), 0, trend, 0, trend.Length);
            //  dumpDebugData("trend", trend);

            var sss = trendSmoother.smooth();

            for (int i = 0; i < trend.Length; i++)
            {
                trend[i] = sss[i];
            }
        }
예제 #2
0
        private void smoothOneSubSeries(double[] weights, double[] rawData, double[] smoothedData)
        {
            int cycleLength = rawData.Length;

            //  Smooth the cyclic sub-series with LOESS and then extrapolate one place beyond each end.
            this.fLoessSmootherFactory.Data            = rawData;
            this.fLoessSmootherFactory.ExternalWeights = weights;
            LoessSmoother smoother = this.fLoessSmootherFactory.build();

            //Copy, shifting by 1 to leave room for the extrapolated point at the beginning.
            // System.arraycopy(smoother.smooth(), 0, smoothedData, this.fNumPeriodsToExtrapolateBackward, cycleLength);

            var ss = smoother.smooth();

            for (int i = 0; i < cycleLength; i++)
            {
                smoothedData[this.fNumPeriodsToExtrapolateBackward + i] = ss[i];
            }


            LoessInterpolator interpolator = smoother.Interpolator;

            //  Extrapolate from the leftmost "width" points to the "-1" position
            int left  = 0;
            int right = (left + (this.fWidth - 1));

            right = Math.Min(right, (cycleLength - 1));

            int leftValue = this.fNumPeriodsToExtrapolateBackward;

            for (int i = 1; (i <= this.fNumPeriodsToExtrapolateBackward); i++)
            {
                double ys = interpolator.smoothOnePoint((i * -1), left, right);
                //
                smoothedData[(leftValue - i)] = ys == 0 ? smoothedData[leftValue] : ys;
            }

            //  Extrapolate from the rightmost "width" points to the "length" position (one past the array end).
            right = (cycleLength - 1);
            left  = ((right - this.fWidth) + 1);
            left  = Math.Max(0, left);

            int rightValue = (this.fNumPeriodsToExtrapolateBackward + right);

            for (int i = 1; (i <= this.fNumPeriodsToExtrapolateForward); i++)
            {
                Double ys = interpolator.smoothOnePoint((right + i), left, right);
                //smoothedData[(rightValue + i)] = (ys == null);
                smoothedData[rightValue + i] = ys == 0 ? smoothedData[rightValue] : ys;
            }
        }
예제 #3
0
        public void smoothSeasonal(int width, bool restoreEndPoints)
        {
            //  Ensure that LOESS smoother width is odd and >= 3.
            width = Math.Max(3, width);
            if (width % 2 == 0)
            {
                width++;
            }

            //  Quadratic smoothing of the seasonal component.
            //  Do NOT perform linear interpolation between smoothed points - the quadratic spline can accommodate
            //  sharp changes and linear interpolation would cut off peaks/valleys.
            LoessBuilder builder = new LoessBuilder();

            builder.Width  = width;
            builder.Degree = 2;
            builder.Jump   = 1;
            builder.Data   = this.fSeasonal;

            LoessSmoother seasonalSmoother = builder.build();

            double[] smoothedSeasonal = seasonalSmoother.smooth();

            //  TODO: Calculate the variance reduction in smoothing the seasonal.
            //  Update the seasonal with the smoothed values.
            //  TODO: This is not very good - it causes discontinuities a the endpoints.
            //        Better to transition to linear in the last half-smoother width.
            //  Restore the end-point values as the smoother will tend to over-modify these.
            double s0 = this.fSeasonal[0];
            double sN = this.fSeasonal[(this.fSeasonal.Length - 1)];

            //System.arraycopy(smoothedSeasonal, 0, this.fSeasonal, 0, smoothedSeasonal.Length)
            this.fSeasonal = new double[smoothedSeasonal.Length];
            for (int i = 0; i < smoothedSeasonal.Length; i++)
            {
                this.fSeasonal[i] = smoothedSeasonal[i];
            }


            if (restoreEndPoints)
            {
                this.fSeasonal[0] = s0;
                this.fSeasonal[this.fSeasonal.Length - 1] = sN;
            }

            for (int i = 0; (i < smoothedSeasonal.Length); i++)
            {
                fResiduals[i] = fData[i] - fTrend[i] - fSeasonal[i];
            }
        }
예제 #4
0
        private void removeSeasonality()
        {
            //
            double[] pass1 = this.fExtendedSeasonal.MA(this.fPeriodLength);
            //  data.length + periodLength + 1
            double[] pass2 = pass1.MA(this.fPeriodLength);
            //  data.length + 2
            double[] pass3 = pass2.MA(3);
            //
            this.fLowpassLoessFactory.Data = pass3;
            LoessSmoother lowPassLoess = this.fLowpassLoessFactory.build();

            this.fDeSeasonalized = lowPassLoess.smooth();
            //  dumpDebugData("lowpass", fDeSeasonalized);
        }