Ejemplo n.º 1
0
        /**
         * Compute a loess fit on the data at the original abscissae.
         *
         * @param xval the arguments for the interpolation points
         * @param yval the values for the interpolation points
         * @return values of the loess fit at corresponding original abscissae
         * @throws MathException if some of the following conditions are false:
         * <ul>
         * <li> Arguments and values are of the same size that is greater than zero</li>
         * <li> The arguments are in a strictly increasing order</li>
         * <li> All arguments and values are finite real numbers</li>
         * </ul>
         */
        public double[] Smooth(double[] xval, double[] yval, CustomCancellationToken token)
        {
            if (xval.Length != yval.Length)
            {
                throw new ArgumentException(@"Array lengths must match");
            }

            double[] unitWeights = Enumerable.Repeat(1.0, xval.Length).ToArray();

            return(Smooth(xval, yval, unitWeights, token));
        }
Ejemplo n.º 2
0
        /**
         * Compute a weighted loess fit on the data at the original abscissae.
         *
         * @param xval the arguments for the interpolation points
         * @param yval the values for the interpolation points
         * @param weights point weights: coefficients by which the robustness weight of a point is multiplied
         * @return values of the loess fit at corresponding original abscissae
         * @throws MathException if some of the following conditions are false:
         * <ul>
         * <li> Arguments and values are of the same size that is greater than zero</li>
         * <li> The arguments are in a strictly increasing order</li>
         * <li> All arguments and values are finite real numbers</li>
         * </ul>
         * @since 2.1
         */
        public double[] Smooth(double[] xval, double[] yval, double[] weights, CustomCancellationToken token)
        {
            if (xval.Length != yval.Length)
            {
                throw new ArgumentException(@"Mismatched array lengths");
            }

            int n = xval.Length;

            if (n == 0)
            {
                throw new ArgumentException(@"Must have at least one point");
            }

            CheckAllFiniteReal(xval);
            CheckAllFiniteReal(yval);
            CheckAllFiniteReal(weights);

            CheckNotDecreasing(xval);

            if (n == 1)
            {
                return(new[] { yval[0] });
            }

            if (n == 2)
            {
                return(new[] { yval[0], yval[1] });
            }

            int bandwidthInPoints = (int)(_bandwidth * n);

            if (bandwidthInPoints < 2)
            {
                throw new ArgumentException(@"Bandwidth too small");
            }

            double[] res = new double[n];

            double[] residuals       = new double[n];
            double[] sortedResiduals = new double[n];

            // Do an initial fit and 'robustnessIters' robustness iterations.
            // This is equivalent to doing 'robustnessIters+1' robustness iterations
            // starting with all robustness weights set to 1.
            double[] robustnessWeights = Enumerable.Repeat(1.0, n).ToArray();

            for (int iter = 0; iter <= _robustnessIters; ++iter)
            {
                int[] bandwidthInterval = { 0, bandwidthInPoints - 1 };
                // At each x, compute a local weighted linear regression
                for (int i = 0; i < n; ++i)
                {
                    ThreadingHelper.CheckCanceled(token);

                    double x = xval[i];

                    // Find out the interval of source points on which
                    // a regression is to be made.
                    if (i > 0)
                    {
                        UpdateBandwidthInterval(xval, weights, i, bandwidthInterval);
                    }

                    int ileft  = bandwidthInterval[0];
                    int iright = bandwidthInterval[1];

                    // Compute the point of the bandwidth interval that is
                    // farthest from x
                    int edge = xval[i] - xval[ileft] > xval[iright] - xval[i]
                        ? ileft
                        : iright;

                    // Compute a least-squares linear fit weighted by
                    // the product of robustness weights and the tricube
                    // weight function.
                    // See http://en.wikipedia.org/wiki/Linear_regression
                    // (section "Univariate linear case")
                    // and http://en.wikipedia.org/wiki/Weighted_least_squares
                    // (section "Weighted least squares")
                    double sumWeights  = 0;
                    double sumX        = 0;
                    double sumXSquared = 0;
                    double sumY        = 0;
                    double sumXy       = 0;
                    double denom       = Math.Abs(1.0 / (xval[edge] - x));
                    for (int k = ileft; k <= iright; ++k)
                    {
                        double xk   = xval[k];
                        double yk   = yval[k];
                        double dist = (k < i) ? x - xk : xk - x;
                        double w    = Tricube(dist * denom) * robustnessWeights[k] * weights[k];
                        double xkw  = xk * w;
                        sumWeights  += w;
                        sumX        += xkw;
                        sumXSquared += xk * xkw;
                        sumY        += yk * w;
                        sumXy       += yk * xkw;
                    }

                    double meanX        = sumX / sumWeights;
                    double meanY        = sumY / sumWeights;
                    double meanXy       = sumXy / sumWeights;
                    double meanXSquared = sumXSquared / sumWeights;

                    double beta;
                    if (Math.Sqrt(Math.Abs(meanXSquared - meanX * meanX)) < _accuracy)
                    {
                        beta = 0;
                    }
                    else
                    {
                        beta = (meanXy - meanX * meanY) / (meanXSquared - meanX * meanX);
                    }

                    double alpha = meanY - beta * meanX;

                    res[i]       = beta * x + alpha;
                    residuals[i] = Math.Abs(yval[i] - res[i]);
                }

                // No need to recompute the robustness weights at the last
                // iteration, they won't be needed anymore
                if (iter == _robustnessIters)
                {
                    break;
                }

                // Recompute the robustness weights.

                // Find the median residual.
                // An arraycopy and a sort are completely tractable here,
                // because the preceding loop is a lot more expensive
                Array.Copy(residuals, 0, sortedResiduals, 0, n);
                Array.Sort(sortedResiduals);
                double medianResidual = sortedResiduals[n / 2];

                if (Math.Abs(medianResidual) < _accuracy)
                {
                    break;
                }

                for (int i = 0; i < n; ++i)
                {
                    double arg = residuals[i] / (6 * medianResidual);
                    if (arg >= 1)
                    {
                        robustnessWeights[i] = 0;
                    }
                    else
                    {
                        double w = 1 - arg * arg;
                        robustnessWeights[i] = w * w;
                    }
                }
            }

            return(res);
        }