Solved – Compare non-linear model parameter estimates between conditions

nonlinear regressionrstatistical significance

What is the appropriate way to test for significant differences between the same parameter estimate from 2 nonlinear models? An example using R – here are 2 datasets:

library(tidyverse)
#example from ?nls
DNase1 <- subset(DNase, Run == 1)
DNase2 <- subset(DNase, Run == 2)

Both datasets can be fit with a nonlinear function using the nls() function and coefficients extracted:

   ## fit models and extract coefficients
m1 <- nls(density ~ SSlogis(log(conc), Asym, xmid, scal), DNase1)
m1_coef <- tidy(m1) %>% 
  mutate(Run = 1)

m2 <- nls(density ~ SSlogis(log(conc), Asym, xmid, scal), DNase2)
m2_coef <- tidy(m2) %>% 
  mutate(Run = 2)

pars <- rbind(m1_coef, m2_coef) %>% 
  dplyr::filter(term == "Asym")

print(pars)

For simplicity, some of the results include 2 estimates of the 'Asym' parameter, one estimate for each condition (Run 1 & 2) made by each of the 2 models:

     term Estimate Std. Error  t value     Pr(>|t|) Run
1    Asym 2.345182  0.0781541 30.00715 2.165539e-13   1
2    Asym 2.595948  0.0646589 40.14835 5.109901e-15   2

Is there a way test if the estimate for 'Asym' from Run 2 (2.345) is significantly different than the estimate from Run 1 (2.596)?

Best Answer

Create a model m12 consisting of separate parameters for each run and a model m0 where the parameters are the same for each run and then compare those two models using an F test. In R that would be done like this:

# m1 and m2 will be used to set starting values for m12 and a0
fo <- density ~ SSlogis(log(conc), Asym, xmid, scal)
m1 <- nls(fo, DNase, subset = Run == 1)
m2 <- nls(fo, DNase, subset = Run == 2)

Logis <- function(x, Asym, xmid, scal) Asym / (1 + exp((xmid - x)/ scal))

# Run 1 and Run 2 each have a separate set of parameters.
# (Run is a factor whose labels don't correspond to its levels so make it numeric.)
m12 <- nls(density ~ Logis(log(conc), Asym[Run], xmid[Run], scal[Run]),
  transform(DNase, Run = as.numeric(as.character(Run))), 
  subset = Run %in% 1:2, 
  start = as.data.frame(rbind(coef(m1), coef(m2))))

# Run 1 and Run 2 have the same set of parameters
m0 <- nls(fo, DNase, subset = Run %in% 1:2)

anova(m0, m12)

giving:

Analysis of Variance Table

Model 1: density ~ SSlogis(log(conc), Asym, xmid, scal)
Model 2: density ~ Logis(log(conc), Asym[Run], xmid[Run], scal[Run])
  Res.Df Res.Sum Sq Df   Sum Sq F value    Pr(>F)    
1     29   0.096915                                  
2     26   0.008478  3 0.088437  90.408 7.044e-14 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

If we want to test only whether Asym differs but not whether xmid and scal are the same then create a model a0 where Asym is the same but the other parameters can differ and compare it to m12.

# same Asym for Run 1 and Run 2 but other parameters separate
a0 <- nls(density ~ Logis(log(conc), Asym, xmid[Run], scal[Run]),
  transform(DNase, Run = as.numeric(as.character(Run))), 
  subset = Run %in% 1:2, 
  start = c(Asym = (coef(m1)[[1]] + coef(m2)[[1]])/2, 
    as.data.frame(rbind(coef(m1)[-1], coef(m2)[-1]))))

anova(a0, m12)

giving:

Analysis of Variance Table

Model 1: density ~ Logis(log(conc), Asym, xmid[Run], scal[Run])
Model 2: density ~ Logis(log(conc), Asym[Run], xmid[Run], scal[Run])
  Res.Df Res.Sum Sq Df    Sum Sq F value  Pr(>F)  
1     27  0.0103246                               
2     26  0.0084778  1 0.0018468  5.6639 0.02494 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1