Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fit and compare multiple sigmoid curves in R

I would like to fit multiple curves at once, and compare them statistically, in terms of their 3 estimated parameters – asymptote, slope and x0. Here is an idealized image of the data to be modeled: enter image description here

Most searchable pages turn up methods to fit a single curve, as seen here: http://kyrcha.info/2012/07/08/tutorials-fitting-a-sigmoid-function-in-r/ and here http://rstudio-pubs-static.s3.amazonaws.com/7812_5327615eb0044cf29420b955ddaa6173.html

In my case, I would like to test (statistically) the effect of changing variable levels on the three parameters of the sigmoid. That is, when I’m fitting this model:

model <- nls(y ~ asym / (1 + exp( -slope * (x – x0) ) ), start = c(…), data = my_data)

I would like to add interactions of two factors (say, “factorA”, and “factorB”) with each of the asym, slope and x0 terms, the way we can do with lm() or glm(), as in the following:

model_int <- nls(y ~ asym*factorA / (1 + exp( -(slope*factorA) * (x – (x0*factorA) ) ), start = c(…), data = my_data)

That way, I can see if those three parameters are statistically different across the different levels of factorA (and potentially multiple other factors, as you can see from the image). For example, we can see that "Condition" has an effect on the asymptote of the curves.

I have done this previously with dummy coding each level of each interacting variable, but that is not a way to directly test these variables, and is rather verbose as models go. It looks like this:

model_dummy <- nls(y ~ (asym+ asym.L1 * is.L1 + asym.l2*is.L2) / 
(1 + exp( -slope * (x – (x0 + x0.L1 * is.L1 + x0.L2 * is.L2) ) ) ), 
start = c(…), data = my_data)

As you might guess, this method has obvious drawbacks in terms of tidyness and lack of interpretability.

Does anybody know how to fit a set of sigmoids where the parameters interact with variables in the data set to produce curves of slightly different shapes?

like image 268
Matt74 Avatar asked Feb 03 '17 01:02

Matt74


1 Answers

Well, I'm not sure if this is what are you looking for but this example from nls function may helps you:

> head(muscle)
   Strip Conc Length
3    S01    1   15.8
4    S01    2   20.8
5    S01    3   22.6
6    S01    4   23.8
9    S02    1   20.6
10   S02    2   26.8
# get some initial values
musc.1 <- nls(Length ~ cbind(1, exp(-Conc/th)), muscle,
              start = list(th = 1), algorithm = "plinear")
summary(musc.1)

# and now with factor Strip
b <- coef(musc.1)
musc.2 <- nls(Length ~ a[Strip] + b[Strip]*exp(-Conc/th), muscle,
              start = list(a = rep(b[2], 21), b = rep(b[3], 21), th = b[1]))
summary(musc.2)

So in your case it will be something like this:

fit <- nls(y ~ asym[Factor]/ (1 + exp(-slope[Factor]*(x –x0[Factor]))), start = c(…), data = my_data)

Hope this helps

like image 100
Adela Avatar answered Nov 03 '22 11:11

Adela