public static string Fit(Altaxo.Gui.Graph.Gdi.Viewing.IGraphController ctrl, int order, double fitCurveXmin, double fitCurveXmax, bool showFormulaOnGraph) { string error; double[] xarr, yarr; error = GetActivePlotPoints(ctrl, out xarr, out yarr); int numberOfDataPoints = xarr.Length; if (null != error) return error; string[] plotNames = GetActivePlotName(ctrl); int numberOfParameter = order + 1; double[] parameter = new double[numberOfParameter]; LinearFitBySvd fit = new LinearFitBySvd( xarr, yarr, null, numberOfDataPoints, order + 1, new FunctionBaseEvaluator(EvaluatePolynomialBase), 1E-5); // Output of results Current.Console.WriteLine(""); Current.Console.WriteLine("---- " + DateTime.Now.ToString() + " -----------------------"); Current.Console.WriteLine("Polynomial regression of order {0} of {1} over {2}", order, plotNames[1], plotNames[0]); Current.Console.WriteLine( "Name Value Error F-Value Prob>F"); for (int i = 0; i < fit.Parameter.Length; i++) Current.Console.WriteLine("A{0,-3} {1,20} {2,20} {3,20} {4,20}", i, fit.Parameter[i], fit.StandardErrorOfParameter(i), fit.TofParameter(i), 1 - FDistribution.CDF(fit.TofParameter(i), numberOfParameter, numberOfDataPoints - 1) ); Current.Console.WriteLine("R²: {0}, Adjusted R²: {1}", fit.RSquared, fit.AdjustedRSquared); Current.Console.WriteLine("------------------------------------------------------------"); Current.Console.WriteLine("Source of Degrees of"); Current.Console.WriteLine("variation freedom Sum of Squares Mean Square F0 P value"); double regressionmeansquare = fit.RegressionCorrectedSumOfSquares / numberOfParameter; double residualmeansquare = fit.ResidualSumOfSquares / (numberOfDataPoints - numberOfParameter - 1); Current.Console.WriteLine("Regression {0,10} {1,20} {2,20} {3,20} {4,20}", numberOfParameter, fit.RegressionCorrectedSumOfSquares, fit.RegressionCorrectedSumOfSquares / numberOfParameter, regressionmeansquare / residualmeansquare, 1 - FDistribution.CDF(regressionmeansquare / residualmeansquare, numberOfParameter, numberOfDataPoints - 1) ); Current.Console.WriteLine("Residual {0,10} {1,20} {2,20}", numberOfDataPoints - 1 - numberOfParameter, fit.ResidualSumOfSquares, residualmeansquare ); Current.Console.WriteLine("Total {0,10} {1,20}", numberOfDataPoints - 1, fit.TotalCorrectedSumOfSquares ); Current.Console.WriteLine("------------------------------------------------------------"); // add the fit curve to the graph IScalarFunctionDD plotfunction = new PolynomialFunction(fit.Parameter); XYFunctionPlotItem fittedCurve = new XYFunctionPlotItem(new XYFunctionPlotData(plotfunction), new G2DPlotStyleCollection(LineScatterPlotStyleKind.Line, ctrl.Doc.GetPropertyContext())); var xylayer = ctrl.ActiveLayer as XYPlotLayer; if (null != xylayer) xylayer.PlotItems.Add(fittedCurve); return null; }
/// <summary> /// Fits data provided as xcolumn and ycolumn with a polynomial base. Here special measures are taken (scaling of the x-variable) in order /// to keep the precision high. /// </summary> /// <param name="order">The order of the fit (1:linear, 2:quadratic, etc.)</param> /// <param name="xValues">The array of x-values. The values of the array are destroyed (altered) during the evaluation!</param> /// <param name="yValues">The array of y-values.</param> /// <param name="errorValues">The column of errorValues. If null, errorValues are set to 1 for each element.</param> /// <param name="count">Number of values to use (array[0] ... array[count-1].</param> /// <returns>The fit.</returns> public static LinearFitBySvd FitPolymomialDestructive(int order, double[] xValues, double[] yValues, double[] errorValues, int count) { if (!(xValues != null)) { throw new ArgumentNullException(nameof(xValues)); } if (!(yValues != null)) { throw new ArgumentNullException(nameof(yValues)); } if (!(count > 0)) { throw new ArgumentOutOfRangeException(nameof(count), "must be >0"); } if (!(count <= xValues.Length)) { throw new ArgumentOutOfRangeException(nameof(count), "exceeds capacity of array " + nameof(xValues)); } if (!(count <= yValues.Length)) { throw new ArgumentOutOfRangeException(nameof(count), "exceeds capacity of array " + nameof(yValues)); } if (null != errorValues && !(count <= errorValues.Length)) { throw new ArgumentOutOfRangeException(nameof(count), "exceeds capacity of array " + nameof(errorValues)); } double[] xarr = xValues; double[] yarr = yValues; double[] earr = errorValues; if (null == earr) { earr = new double[count]; VectorMath.FillWith(earr, 1); } int numberOfDataPoints = count; // we scale the x-values in order to keep the Condition number reasonable var xmin = Altaxo.Calc.LinearAlgebra.VectorMath.Min(xarr, 0, numberOfDataPoints); var xmax = Altaxo.Calc.LinearAlgebra.VectorMath.Max(xarr, 0, numberOfDataPoints); double xscale = Math.Max(-xmin, xmax); double xinvscale = 1 / xscale; if (0 == xscale) { xscale = xinvscale = 1; } for (int i = 0; i < numberOfDataPoints; ++i) { xarr[i] *= xinvscale; } var fit = new LinearFitBySvd( xarr, yarr, earr, numberOfDataPoints, order + 1, new FunctionBaseEvaluator(GetPolynomialFunctionBase(order)), 1E-15); // rescale parameter of fit in order to account for rescaled x variable for (int i = 0; i <= order; ++i) { fit._parameter[i] *= RMath.Pow(xinvscale, i); for (int j = 0; j <= order; ++j) { fit._covarianceMatrix[i][j] *= RMath.Pow(xinvscale, i + j); } } return(fit); }
/// <summary> /// Fits data provided as xcolumn and ycolumn with a polynomial base. /// </summary> /// <param name="order">The order of the fit (1:linear, 2:quadratic, etc.)</param> /// <param name="xcolumn">The column of x-values.</param> /// <param name="ycolumn">The column of y-values.</param> /// <returns>The fit.</returns> public static LinearFitBySvd Fit(int order, Altaxo.Data.DataColumn xcolumn, Altaxo.Data.DataColumn ycolumn) { if (!(xcolumn is Altaxo.Data.INumericColumn)) throw new ArgumentException("The x-column must be numeric", "xcolumn"); if (!(ycolumn is Altaxo.Data.INumericColumn)) throw new ArgumentException("The y-column must be numeric", "ycolumn"); int firstIndex = 0; int count = Math.Min(xcolumn.Count, ycolumn.Count); double[] xarr = new double[count]; double[] yarr = new double[count]; double[] earr = new double[count]; Altaxo.Data.INumericColumn xcol = (Altaxo.Data.INumericColumn)xcolumn; Altaxo.Data.INumericColumn ycol = (Altaxo.Data.INumericColumn)ycolumn; int numberOfDataPoints = 0; int endIndex = firstIndex + count; for (int i = firstIndex; i < endIndex; i++) { double x = xcol[i]; double y = ycol[i]; if (double.IsNaN(x) || double.IsNaN(y)) continue; xarr[numberOfDataPoints] = x; yarr[numberOfDataPoints] = y; earr[numberOfDataPoints] = 1; numberOfDataPoints++; } LinearFitBySvd fit = new LinearFitBySvd( xarr, yarr, earr, numberOfDataPoints, order + 1, new FunctionBaseEvaluator(EvaluatePolynomialBase), 1E-5); return fit; }