Home > Mobile >  Non-linear regression, nls, in R: singular gradient
Non-linear regression, nls, in R: singular gradient

Time:11-15

I want to fit my data to a specific function that has already been optimized using Matlab.

I get the following error: 'Warning message: Computation failed in stat_smooth(): singular gradient '

Please help! Here is my R code:

tibble
       x     y     SEM
 1     1 0.0342 0.00532
 2     3 0.0502 0.00639
 3     5 0.0700 0.0118 
 4    10 0.123  0.0269 
 5    20 0.154  0.0125 
 6    30 0.203  0.0190 
 7    40 0.257  0.0255 
 8    50 0.287  0.0266 
 9    60 0.345  0.0347 
10    90 0.442  0.0398 
11   120 0.569  0.0570 
12   180 0.726  0.0406 
13   240 0.824  0.0150 
14   360 0.868  0.00821
15  1440 0.890  0.0246 

tibble %>% 
  ggplot(aes(x, y))  
  geom_point() 
  geom_errorbar(aes(ymin=y-SEM, ymax=y SEM), width=25) 
  geom_ribbon(aes(ymin = y-2.575*SEM, ymax = y 2.575*SEM), alpha = 0.1) 
  geom_smooth(method="nls", 
              formula= y ~ (1-((k2/(k2-k1))*exp(-k1*x)) ((k1/(k2-k1))*exp(-k2*x))),
              se=F,
              method.args = list(start=list(k1=0.006999, k2=849.6)))

CodePudding user response:

As it stands, nls can't decide on an optimal value of k2 because the sum of squares decreases asymptotically towards a value of about 0.0225 as k2 tends to infinity. There is therefore no finite value of k2 that minimizes the sum of squares. As k2 tends to infinity, it effectively cancels out, to leave the formula equivalent to:

y ~ 1 - exp(-k1*x)

which means that this formula will always fit the data better than the original formula for any finite value of k2.

In short, k2 is a redundant parameter that can only worsen your fit.

Your plot could therefore be made like this:

ggplot(df, aes(x, y))  
  geom_point()  
  geom_errorbar(aes(ymin = y - SEM, ymax = y   SEM), width = 25)  
  geom_ribbon(aes(ymin = y - 2.575 * SEM, ymax = y   2.575 * SEM), alpha = 0.1)  
  geom_smooth(method = "nls", 
              formula = y ~ 1 - exp(-k1 * x),
              se = FALSE,
              method.args = list(start = list(k1 = 0.006999)))

enter image description here

Or, as G. Grothendieck suggests, use an extra parameter to optimize the fit like this (assuming it makes physical sense in your use case)

ggplot(df, aes(x, y))  
  geom_point()  
  geom_errorbar(aes(ymin = y - SEM, ymax = y   SEM), width = 25)  
  geom_ribbon(aes(ymin = y - 2.575 * SEM, ymax = y   2.575 * SEM), alpha = 0.1)  
  geom_smooth(method = "nls", 
              formula = y ~ k2 * (1 - exp(-k1 * x)),
              se = FALSE,
              method.args = list(start = list(k1 = 0.006999, k2 = 1)))

enter image description here

  • Related