private LoessModel train(double[] xvals, double[] yvals, double xStep, int[] ascendingOrder,
bool computeFitted = true)
{
if (xvals.Length != yvals.Length)
{
throw new ApplicationException(string.Format("Loess expects the abscissa and ordinate arrays to be of the same Size, but got {0} abscisssae and {1} ordinatae", xvals.Length, yvals.Length));
}
int n = xvals.Length;
if (n <= 1)
{
return new LoessModel(xvals, yvals, new double[] { yvals[0] }, null, ascendingOrder, null);
}
checkAllFiniteReal(xvals, true);
checkAllFiniteReal(yvals, false);
checkIncreasing(xvals);
int bandwidthInPoints = (int)Math.Ceiling(bandwidth * n);
int leastBandwithInPoints = 1 + polynomialDegree;
if (bandwidthInPoints < leastBandwithInPoints)
{
throw new ApplicationException(string.Format(
"the bandwidth must be large enough to accomodate at least {0} points. There are {1} data points, and bandwidth must be at least {2} but it is only {3}",
leastBandwithInPoints, n, (double)leastBandwithInPoints / n, bandwidth
));
}
double[] fitted = null;
double[] residuals = null;
double[] robustnessWeights = null;
if (robustnessIters > 0) { computeFitted = true; } // override computeFitted
if (computeFitted || robustnessIters > 0) { fitted = 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.
if (robustnessIters > 0)
{
residuals = new double[n];
robustnessWeights = new double[n];
for (int i = 0; i < robustnessWeights.Length; i++) robustnessWeights[i] = 1;
}
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)
{
double x = xvals[i];
// Find out the interval of source points on which
// a regression is to be made.
if (i > 0)
{
var newBandwidthInterval = updateBandwidthInterval(x, xvals, bandwidthInterval);
if (newBandwidthInterval != null) { bandwidthInterval = newBandwidthInterval; }
}
// Linear regression to get the coeeficients
if (computeFitted || robustnessIters > 0)
{
double[] coefficients = computeCoefficients(x, xvals, yvals, robustnessWeights, bandwidthInterval);
fitted[i] = predict(x, coefficients);
}
if (robustnessIters > 0) { residuals[i] = Math.Abs(yvals[i] - fitted[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.
double medianResidual = Utilities.Median(residuals); // Find the median residual
if (medianResidual == 0) { break; }
for (int i = 0; i < n; ++i)
{
double arg = residuals[i] / (6 * medianResidual);
robustnessWeights[i] = (arg >= 1) ? 0 : Math.Pow(1 - arg * arg, 2);
}
}
List<LoessInterval> intervals = computeIntervals(xvals, xStep, bandwidthInPoints);
return new LoessModel(xvals, yvals, fitted, robustnessWeights, ascendingOrder, intervals);
}