rnls

Fitting exponential decline using nls() either fails or give wrong fit


I am trying to fit very simple exponential decay using R. However, I have a problem achieving that task using R.

koff_dat <- tribble(
  ~incu_time, ~perc_binding,
  179.20634920634922, 3.94736842105263,
  120.47619047619048, 10.197368421052616,
  91.11111111111111,  18.09210526315789,
  60.95238095238095,  35.526315789473685,
  45.87301587301587,  31.25,
  30.793650793650798, 55.921052631578945, 
  16.50793650793652,  68.75,
  0.6349206349206398, 99.34210526315789
)


fit2 <- nls(perc_binding ~ exp(-k*incu_time), 
            data = koff_dat, 
            start = list(k = 0.001))

plot(koff_dat$incu_time, koff_dat$perc_binding)
lines(koff_dat$incu_time, predict(fit2))

enter image description here

As you can tell from there the fit is very off for k. pleas advise


Solution

  • 1) The model needs a multiplying constant: A * exp(-k * incu_time). Using the plinear algorithm which will add a multiplying constant without needing another starting value. We have also added an automatic starting value for k but the one in the question would also work.

    (continued after graph)

    k.start <- -coef(lm(log(perc_binding) ~ incu_time, koff_dat))[[2]]
    
    fit3 <- nls(perc_binding ~ cbind(A = exp(-k*incu_time)), 
                data = koff_dat, start = list(k = k.start), alg = "plinear")
    
    plot(koff_dat)
    lines(fitted(fit3) ~ incu_time, koff_dat)
    

    screenshot

    2) drc Also the drc package has such a model. No starting values are needed.

    library(drc)
    
    fit4 <- drm(perc_binding ~ incu_time, data = koff_dat, fct = EXD.2())
    

    Its e parameter is the reciprocal of k

    coef(fit3)
    ##          k     .lin.A 
    ##  0.0197362 98.6532169 
    
    c(1/coef(fit4)[2], coef(fit4)[1])
    ## e:(Intercept) d:(Intercept) 
    ##    0.01973619   98.65319125 
    

    3) units A way to resolve this while using the model in the question without any modification is change the units used in koff_data. This gives a fit which is visually very similar to the graph above.

    koff_dat2 <- transform(koff_dat, perc_binding = perc_binding  / 100)
    fit5 <- nls(perc_binding ~ exp(-k*incu_time), data = koff_dat2, 
      start = list(k = 0.001))
    
    plot(koff_dat2)
    lines(fitted(fit5) ~ incu_time, koff_dat2)