# Compute goodness of fit (gof) out of sfit-object and fitting data

75 views (last 30 days)
Rodrigo on 19 Aug 2016
Hi,
I used the Curve Fitting Toolbox to find the parameters of a parametric 3D-surface that matches measured data. After computing a possible solution for the parameters, I only saved the sfit-object, but forgot to also save the gof-struct. What I would like to do is to compute the gof-struct out of the sfit-object and the data used for fitting. Is there any MATLAB function that already does that?

Farouk Moukaddem on 25 Aug 2016
Edited: Farouk Moukaddem on 25 Aug 2016
Hi Rodrigo,
The only documented way to obtain the goodness-of-fit statistics is by explicitly passing the output parameter "gof" when calling the "fit" function.
[fitobject,gof] = fit(x,y,fitType)
As a workaround, you might be interested in the "goodnessOfFit" function that computes the goodness of fit between test and reference data. Refer to the following documentation link for more information:
Also, you might want to check the following File Exchange submission:
Best,
Farouk

Brandon Ballard on 27 Aug 2020
Edited: Brandon Ballard on 27 Aug 2020
Hi all,
A slightly longwinded approach to potentially solving this problem would be first obtaining the coefficient values and coefficient names using coeffvalues and coeffnames. For the example below the following curve cfit object was created for demonstration but it should also work for sfit with the appropriate modifications.
ft = fittype('a*x+b')
ft =
General model:
ft(a,b,x) = a*x+b
curve = cfit(ft,2,1)
curve =
General model:
curve(x) = a*x+b
Coefficients:
a = 2
b = 1
coeffnames(curve)
ans =
2×1 cell array
{'a'}
{'b'}
coeffvalues(curve)
ans =
2 1
Once the coefficient names and values are known the next step is to define the Starting Points and the fitoptions.
fo = fitoptions(ft)
fo =
Normalize: 'off'
Exclude: []
Weights: []
Method: 'NonlinearLeastSquares'
Robust: 'Off'
StartPoint: [1×0 double]
Lower: [1×0 double]
Upper: [1×0 double]
Algorithm: 'Trust-Region'
DiffMinChange: 1.0000e-08
DiffMaxChange: 0.1000
Display: 'Notify'
MaxFunEvals: 600
MaxIter: 400
TolFun: 1.0000e-06
TolX: 1.0000e-06
By changing the StartPoint of the optimisation process to the coefficient values found previously and forcing both the Maximum Number of Function Evaluations and Maximum Number of Iterations to be equal to 1.
fo.StartPoint = [2,1];
fo.MaxFunEvals = 1;
fo.MaxIter = 1;
This forces the algorithm to only evaluate the fit at the Start Point and therefore the coefficient values from the original cfit object and the cfit object obtained through the fit command below.
[fitobject,gof,output] = fit(x,y,ft,fo)
For example using the example data below results in...
x = [1:1:10];
y = curve(x); % [3,5,7,9,11,13,15,17,19,21]
fitobject =
General model:
fitobject(x) = a*x+b
Coefficients (with 95% confidence bounds):
a = 2 (2, 2)
b = 1 (1, 1)
gof =
struct with fields:
sse: 0
rsquare: 1
dfe: 8
rmse: 0
output =
struct with fields:
numobs: 10
numparam: 2
residuals: [10×1 double]
Jacobian: [10×2 double]
exitflag: 1
firstorderopt: 0
iterations: 0
funcCount: 3
cgiterations: 0
algorithm: 'trust-region-reflective'
stepsize: 1
message: 'Success. Fitting converged to a solution.'
Bear in mind that this method only works on general and nonlinear models as it makes use of the NonlinearLeastSquares fitoptions.
Using the following alternative values for the y data gives...
y = 0.5*curve(x); % [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5]
fitobject =
General model:
fitobject(x) = a*x+b
Coefficients (with 95% confidence bounds):
a = 2 (0.1118, 3.888)
b = 1 (-10.72, 12.72)
gof =
struct with fields:
sse: 442.5000
rsquare: -4.3636
dfe: 8
rmse: 7.4372
output =
struct with fields:
numobs: 10
numparam: 2
residuals: [10×1 double]
Jacobian: [10×2 double]
exitflag: 0
firstorderopt: 412.5000
iterations: 0
funcCount: 3
cgiterations: 0
algorithm: 'trust-region-reflective'
stepsize: 1
message: 'Fitting stopped because the number of iterations or function evaluations exceeded the specified maximum.'
This approach may not work for all cases so I would appreciate it if others could verify this method works for other cases. For example using other more complex models.
I used this approach for a custom curve fitting (see below), and it worked very well. It is a simple work around to obtain the goodness-of-fit statistics. Thanks for posting this!
myFit = fittype( @(a, b, c, d, e, x) a*exp(-x/b) + c*exp(-x/d)+e )