/// <summary>
 /// Get the best estimated y for the current value.
 /// </summary>
 public double Y()
 {
     if (_model == null)
     {
         Estimate();
     }
     return(_model.Y(_x[SelfIndex]));
 }
        private void Estimate()
        {
            for (int iter = 0; iter < LoessConfiguration.T; iter++)
            {
                _model = Regression();

                // calculate the errors
                var errors    = new double[NeighborsX.Length];
                var absErrors = new double[NeighborsX.Length];
                for (int i = 0; i < NeighborsX.Length; i++)
                {
                    double error = NeighborsY[i] - _model.Y(NeighborsX[i]);
                    errors[i]    = error;
                    absErrors[i] = Math.Abs(error);
                }

                Array.Sort(absErrors);

                double median = absErrors[absErrors.Length / 2];
                if (median == 0) // a very subtle bug! sometimes, when the input data is very clean, so that the median could be 0!
                {
                    median = double.Epsilon;
                }

                // calculate the gain for new weights. the outliers will get much less weight
                var deltas = new double[errors.Length];
                for (int i = 0; i < errors.Length; i++)
                {
                    deltas[i] = WeightMethod.BisquareWeight(errors[i] / 6.0 / median);
                }

                // update new weights.
                for (int i = 0; i < Weights.Length; i++)
                {
                    Weights[i] *= deltas[i];
                }
            }
        }