I have an extremely basic question seeking to answer why the following function in MatLab does not properly fit the given data to a logistic curve, given the correct equation for one. The solution to this is likely quite simple, but I am entirely unfamiliar with the MatLab curve fitting toolbox. My code is as follows:
function [fitresult, gof] = createFit1(Dose, Response)
%CREATEFIT1(DOSE,RESPONSE)
% Create a fit.
%
% Data for 'untitled fit 1' fit:
% X Input : Dose
% Y Output: Response
% Output:
% fitresult : a fit object representing the fit.
% gof : structure with goodness-of fit info.
%
% See also FIT, CFIT, SFIT.
% Auto-generated by MATLAB on 08-Sep-2022 20:16:26
%% Fit: 'untitled fit 1'.
Dose = [1.6*10^4;1.84*10^4;2.08*10^4;2.32*10^4; 2.56*10^4;2.8*10^4;3.04*10^4;3.28*10^4;3.52*10^4;3.76*10^4;4*10^4;4.24*10^4]
Response = [0;0.1004;0.2830;0.4338;0.5638;0.6834;0.8030;0.8680;0.9294;0.9614;0.9978;1]
[xData, yData] = prepareCurveData( Dose, Response );
% Set up fittype and options.
ft = fittype( '1/(1+exp(-k*Dose))', 'independent', 'Dose', 'dependent', 'Response' );
opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
opts.Display = 'Off';
opts.StartPoint = 0.0755269568571602;
% Fit model to data.
[fitresult, gof] = fit( xData, yData, ft, opts );
% Plot fit with data.
figure( 'Name', 'untitled fit 1' );
h = plot( fitresult, xData, yData );
legend( h, 'Response vs. Dose', 'untitled fit 1', 'Location', 'NorthEast', 'Interpreter', 'none' );
% Label axes
xlabel( 'Dose', 'Interpreter', 'none' );
ylabel( 'Response', 'Interpreter', 'none' );
grid on
They are probably two causses of bad fitting.
First : Obviously the points are not located close to a simple logistic curve but close to a shifted logistic curve. So, it is suggested to change the model equation in your code.
Second : The non-linear regression is an iterative process requiring to set some guessed initial values of parameters. If the initial values are too far from the unknown exact values the calculus might fail to achieve a good fit.
If you don't know how to guess some initial values of the parameters better use a not iterative method which doesn't requires initial values as shown below.
Numerical example with your data :
If you want to use your non-linear regression software you can use the above good approximates of the parameters to initiate the iterative process.
An even better fitting would be obtained with a not only horizontal shift (horizontal and vertical shifts).
For information on the non-iterative method used above (linear fitting of an integral equation to which the logistic function is solution ) : https://fr.scribd.com/doc/14674814/Regressions-et-equations-integrales .
In addition : FOUR PARAMETERS LOGISTIC CURVE FITTING
I used the MATLAB curve fitting tool to do a spline smoothing fit and created a function from it. How can I access the Y fit values so I can output them to a file? Seems I am only seeing the x values, and all of the coefs from fitresult. Here is the matlab code. Thanks!
function [fitresult, gof] = createFit(Freq, AmplNew)
%CREATEFIT(FREQ,AMPLNEW)
% Create a fit.
%
% Data for 'untitled fit 1' fit:
% X Input : Freq
% Y Output: AmplNew
% Output:
% fitresult : a fit object representing the fit.
% gof : structure with goodness-of fit info.
%
%% Fit: 'untitled fit 1'.
[xData, yData] = prepareCurveData( Freq, AmplNew );
% Set up fittype and options.
ft = fittype( 'smoothingspline' );
opts = fitoptions( 'Method', 'SmoothingSpline' );
opts.SmoothingParam = 0.998;
% Fit model to data.
[fitresult, gof] = fit( xData, yData, ft, opts );
Simply use feval:
y = feval(fitresult,x);
or just use
y = fitresult(x);
I have a irregular set of data points in the form of cartesian coordinates which using the MATLAB cftool can be turned into a surface (see below).
Does anyone know a way to access the matrix of cartesian coordinates that MATLAB generates in order for it to plot this surface?
The code generated for this graph (seen below) provides no access to the any additional interpolated points which must be produced to fit the surface.
%% Fit: 'untitled fit 1'.
[xData, yData, zData] = prepareSurfaceData( x1, y1, z1 );
% Set up fittype and options.
ft = 'linearinterp';
% Fit model to data.
[fitresult, gof] = fit( [xData, yData], zData, ft, 'Normalize', 'on' );
% Plot fit with data.
figure( 'Name', 'untitled fit 1' );
h = plot( fitresult, [xData, yData], zData );
legend( h, 'untitled fit 1', 'z1 vs. x1, y1', 'Location', 'NorthEast' );
% Label axes
xlabel x1
ylabel y1
zlabel z1
grid on
Thanks in advance
As a possible workaround (potentially not very efficient) is to plot the output of the fit (fitresult) and fetch the XData, YData and ZData properties of the plotted surface.
For example, after performing a dummy fit:
hP = plot(fitresult)
yields those properties for hP:
Surface (curvefit.gui.FunctionSurface) with properties:
EdgeColor: [0 0 0]
LineStyle: '-'
FaceColor: 'flat'
FaceLighting: 'flat'
FaceAlpha: 1
XData: [51x49 double]
YData: [51x49 double]
ZData: [51x49 double]
CData: [51x49 double]
So you can retrieve them.
ALTERNATIVE
as an alternative, you could use the code generated by cftool to provide additional output arguments to the function (called createFit or somethinbg like this). Therefore, as you call the function with enough arguments you will obtain those coordinates directly.
Example:
change the header of the generated function like so:
[fitresult, gof,a,b,c] = createFit1(x, y, z)
and then in the function body:
a = xData;
b = yData;
c = zData;
then calling the function in the Command Window, for example, yields the right coordinates in a,b and c.
I need to fit a data with a nonlinear function just like this:
y=a+b*cos(c*x+d)+e*exp(f*x);
where a, b, c, d, e and f are the coefficients to be found. I have used the Custom Equation method in cftool, the result is bad, then how to adjust the StartPoint in cftool to get a better result? Otherwise, there are other ways to solve my problem? Thank so much.
Here is my data, each in 1*35:
x = [1970:2004];
y = [46808,49416,53094,57237,56677,56198,59673,61826,64158,65220,63108,60944,59543,58779,59882,60087,61825,63104,64963,66902,66443,67061,67273,67372,68679,69995,71522,73292,73932,75826,76954,78105,78439,79892,82631];
ok, Dan, here is my code about cftool, the function is generated by Custom Equation of cftool
% This file include two functions:
% 1. Main: testForFit.m
% 2. Function generated by cftool
function testForFit
clc; clear all;
x = 1970:2004;
y = [46808,49416,53094,57237,56677,56198,59673,61826,64158,65220,63108,60944,59543,58779,59882,60087,61825,63104,64963,66902,66443,67061,67273,67372,68679,69995,71522,73292,73932,75826,76954,78105,78439,79892,82631];
plot(x, y, 'or')
[fitresult, gof] = createFit(x, y)
end
function [fitresult, gof] = createFit(x, y)
%CREATEFIT(X,Y)
% Create a fit.
%
% Data for 'untitled fit 1' fit:
% X Input : x
% Y Output: y
% Output:
% fitresult : a fit object representing the fit.
% gof : structure with goodness-of fit info.
%
% See also FIT, CFIT, SFIT.
% Auto-generated by MATLAB on 04-Feb-2014 00:23:03
%% Fit: curve fitting of gived form of function.
[xData, yData] = prepareCurveData( x, y );
% Set up fittype and options.
ft = fittype( 'a+b*cos(c*x+d)+e*exp(f*x)', 'independent', 'x', 'dependent', 'y' );
% ft = fittype( 'a+e*exp(f*x)', 'independent', 'x', 'dependent', 'y' );
opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
opts.Display = 'Off';
% http://stackoverflow.com/questions/21551951/fitting-curve-with-nonlinear-function-using-cftool-in-matlab
% Firstly, give the estimation, then calculate it
% funlist={1, #(p,x) cos(p(1)*x+p(2)), #(p,x) exp(p(3)*x)};
% NLPstart = [0.605 -3159.659 0.02369];
% [cdf,abe] = fminspleas(funlist,NLPstart,x,y)
% c=cdf(1); d=cdf(2); f=cdf(3);
% a=abe(1); b=abe(2); e=abe(3);
% opts.StartPoint = [a b c d e f];
% How to give the value of StartPoint ?
opts.StartPoint = [0.957166948242946 0.485375648722841 0.8002804688888 0.141886338627215 0.421761282626275 0.915735525189067];
% opts.StartPoint = [31950 1557 0.605 -3159.659 1.183e-16 0.02369];
% Fit model to data.
[fitresult, gof] = fit( xData, yData, ft, opts );
% Plot fit with data.
figure( 'Name', 'curve fitting' );
h = plot( fitresult, xData, yData );
legend( h, 'y vs. x', 'curve fitting', 'Location', 'NorthEast' );
% Label axes
% 31950 1557 0.605 -3159.659 1.183e-16 0.02369
% title('31950+1557*cos(0.605*x-3159.659)+1.183e-16*exp(0.02369*x)')
xlabel( 'x' );
ylabel( 'y' );
grid on
% x = [1970:2004];
% y = [46808,49416,53094,57237,56677,56198,59673,61826,64158,65220,63108,60944,59543,58779,59882,60087,61825,63104,64963,66902,66443,67061,67273,67372,68679,69995,71522,73292,73932,75826,76954,78105,78439,79892,82631];
% Baidu Zhidao
% http://zhidao.baidu.com/question/198731054514100005.html?push=keyword
end
Some error will occured if the StartPoint is not proper ...
I don't have the CurveFit Toolbox, but supposedly there is a "Fit Options" button near where you select the curve type, leading to a dialog where you can select your own initial point.
I also recommend that you try FMINSPLEAS, which can take advantage of the fact that y has a linear dependence on 3 of your 6 parameters. You also only need to provide an initial guess for the nonlinear parameters NLPstart=[c,d,f]
funlist={1, #(p,x) cos(p(1)*x+p(2)), #(p,x) exp(p(3)*x)};
[cdf,abe] = fminspleas(funlist,NLPstart,x,y);
c=cdf(1); d=cdf(2); f=cdf(3);
a=abe(1); b=abe(2); e=abe(3);
I am using Matlab's curve fitting tool, cftool, to fit a set of points which I have. The problem I am facing is that the generate code function will not give me the same fit as produced in the cftool.
This is not what I want because I want to be able to retrieve the data from the residual plot. I could also just copy the function from cftool and do it manually. But I do not understand why the generated code will not just give me the same curve fit.
The cftool session file: http://dl.dropbox.com/u/20782274/test.sfit
The generated code from Matlab:
function [fitresult, gof] = createFit1(Velocity, kWhPerkm)
%CREATEFIT1(VELOCITY,KWHPERKM)
% Create a fit.
%
% Data for 'untitled fit 3' fit:
% X Input : Velocity
% Y Output: kWhPerkm
% Output:
% fitresult : a fit object representing the fit.
% gof : structure with goodness-of fit info.
%
% See also FIT, CFIT, SFIT.
% Auto-generated by MATLAB on 02-Dec-2012 16:36:19
%% Fit: 'untitled fit 3'.
[xData, yData] = prepareCurveData( Velocity, kWhPerkm );
% Set up fittype and options.
ft = fittype( 'a/(0.008*x) + c*x^2 + d*90', 'independent', 'x', 'dependent', 'y' );
opts = fitoptions( ft );
opts.DiffMaxChange = 0.01;
opts.Display = 'Off';
opts.Lower = [-Inf -Inf -Inf];
opts.MaxFunEvals = 1000;
opts.MaxIter = 1000;
opts.StartPoint = [0 0 0];
opts.Upper = [Inf Inf Inf];
% Fit model to data.
[fitresult, gof] = fit( xData, yData, ft, opts );
% Create a figure for the plots.
figure( 'Name', 'untitled fit 3' );
% Plot fit with data.
subplot( 2, 1, 1 );
plot( fitresult, xData, yData, 'predobs' );
% Label axes
xlabel( 'Velocity' );
ylabel( 'kWhPerkm' );
grid on
% Plot residuals.
subplot( 2, 1, 2 );
plot( fitresult, xData, yData, 'residuals' );
% Label axes
xlabel( 'Velocity' );
ylabel( 'kWhPerkm' );
grid on
The curve I get with the generated code:
http://i.stack.imgur.com/65d1P.jpg
The curve I need:
http://i.stack.imgur.com/p3Egp.jpg
So does anyone know what goes wrong?
-edit-
And the Velocity and WhPerkm data file: http://dl.dropbox.com/u/20782274/data.mat
RE: I want to be able to retrieve the data from the residual plot
One way to do this is:
Select "Save to Workspace..." from the Fit menu
Ensure that "Save fit output to MATLAB struct named" is checked.
Note the name of variable. By default, it is output.
Click "OK" to send data to the MATLAB workspace.
In the MATLAB workspace, the residuals will be in output.residuals. For your example, you can plot the residuals via, e.g.,
>> plot( Velocity, output.residuals, '.' )