I don't understand why I can't have a nls function for these data. I have tried with a lot of different start values and I have always the same error.
Here is what I have been doing:
expFct2 = function (x, a, b,c)
{
a*(1-exp(-x/b)) + c
}
vec_x <- c(77.87,87.76,68.6,66.29)
vec_y <- c(1,1,0.8,0.6)
dt <- data.frame(vec_x=vec_x,vec_y=vec_y)
ggplot(data = dt,aes(x = vec_x, y = vec_y)) + geom_point() +
geom_smooth(data=dt, method="nls", formula=y~expFct2(x, a, b, c),
se=F, start=list(a=1, b=75, c=-5)
I have always this error:
Error in method(formula, data = data, weights = weight, ...) :
singular gradient
This can be written with two linear parameters (
.lin1
and.lin2
) and one nonlinear parameter (b
) like this:where
.lin1 = a+c
and.lin2 = -a
(soa = - .lin2
andc = .lin1 + .lin2
) This lets us use"plinear"
which only requires specification of a starting value for the single nonlinear parameter (eliminating the problem of how to set the starting values for the other parameters) and which converges despite the starting value ofb=75
being far from that of the solution:Here is the result of a run from which we can see from the size of
.lin2
that the problem is badly scaled:EDIT: added sample run and comment on scaling.
I struggle to find an interpretation to your parameters: a is a slope, b the speed of convergence, and a+c the limit, but c by itself does not seem to mean much. After reparametrizing your function, the problem disappears.
However, the value of
c
looks very, very high: that is probably why the model initially failed to converge.Here is another, more reasonable parametrization of the same function.
Fitting a three-parameter nonlinear model to four data points is going to be moderately challenging in any case, although in this case the data are well behaved. Point #1 is that your starting value for your
c
parameter (-5) was way off. Drawing a picture of the curve corresponding to your starting parameters (see below) would help you understand this (so would recognizing that the curve you get will range fromc
at its minimum toc+a
at its maximum, and the range of your data is from 0.6 to 1 ...)However, even with a better starting guess I found myself fussing with control parameters (i.e.
control=nls.control(maxiter=200)
), followed by more warnings --nls
is not known for its robustness. So I tried theSSasympOff
model, which implements a self-starting version of the curve you want to fit.My advice in general is that it's easier to figure out what's going on and fix problems if you fit
nls
outside ofgeom_smooth
and construct the curve you want to add usingpredict.nls
...More generally, the way to get good starting parameters is to understand the geometry of the function you are fitting, and which parameters control which aspects of the curve. As I mentioned above,
c
is the minimum value of the shifted saturating-exponential curve,a
is the range, andb
is a scale parameter (you can see that whenx=b
, the curve is1-exp(-1)
or approximately 2/3 of the way from the minimum to the maximum). Either a bit of algebra and calculus (i.e. taking limits), or playing around with thecurve()
function, are good ways to gather this information.