I am trying to fit some data to a function which has validity limit in them. More precisely a function with different value if t<=T and t>T.
Here is the code I have tried:
posExpDecay <- function(t,tau,max,toff){ 1+max*(1-exp(-(t-toff)/tau)) }
negExpDecay <- function(t,tau,max){ 1+max*exp(-(t)/tau) }
data<-structure(list(t = c(0.67, 1, 1.33, 1.67, 2, 4, 6, 8, 10), y = c(1.02,2.33, 3.08, 3.34, 3.41,2.50, 1.86, 1.44, 1.22)), .Names = c("t", "y"), row.names = c(13L, 17L, 21L, 25L, 29L,37L, 45L, 49L, 53L), class = "data.frame")
fit <- nls(y~ifelse(t<=tswitch,
posExpDecay(t,tau1,max1,toff),
negExpDecay(t,tau2,max2)),
data,
start=list(max1=3,tau1=0.7,max2=7,tau2=2,toff=0.1,tswitch=3))
And I get the following error:
Error in nlsModel(formula, mf, start, wts) :
singular gradient matrix at initial parameter estimates
Is this that my starting parameters are not good enough (I tried several), is my problem not well translated in R, or a fundamental mathematical error I missed?
nls(...)
uses the Gauss Newton method by default; that error message, which is quite common actually, means that the Jacobian matrix cannot be inverted.I think your problem has to do with the fact the your composite function (the RHS of your formula) is not continuous at
t=tswitch
for arbitrary values of the other parameters. To say it differently, the requirement that the function be continuous puts a constraint on the other parameters - they are not independent of each other. Also, the derivative of the composite function will never be continuous att=tswitch
- yourposExpDecay(...)
has a positive derivative for allt
, whereas yournegExpDecay(...)
has a negative derivative for allt
.I can't know if there is a theoretical reason for this functional form, but these +/- exponentials are generally modeled using the product of a positive and negative decay, as shown below.
Note: I generally use
nlsLM(...)
in theminpack.lm
package, which uses the much more robust Levenberg Marquardt algorithm. It has the same signature as thenls(...)
function in base R.As you can see this much simpler function (fewer parameters) fits reasonably well.