2

I am working with a data set that is comprised of three columns: patient ID (ID), TIME, and cervical dilation (CD). I apologize in advance for being unable to share my data, as it is confidential, but I have included a sample table below. Each patient CD was recorded in time as they progressed through labor. Time is measured in hours and CD can be 1-10cm. The number of time points/CD scores vary from patient to patient. In this model t is set in reverse, where 10 cm (fully dilated) is set as t=0 for all patients. This is done so that all patients can be aligned at time of full dilation. My dataset has no NA's and all patients have 2 or more time points.

ID TIME CD
1 0 10
1 3 8
1 6 5
2 0 10
2 1 9
2 4 7
2 9 4

I know for this problem I need to use nonlinear mixed effects model. I know from literature that the function that defines this biological process is modeled best as a biexponential function of the form CD= Cexp(-At)+(10-C)exp(-Lt), where A is the active labor rate [cm/hour], L is the latent labor rate [cm/hour], C is the diameter of the cervix [cm] at the point where the patient transitions from latent to active labor, and t is time in hours.

I have tried using both nlmer() and nlme() to fit this data, and I have used both the self-start biexponential function SSbiexp() as well as created my own function and its deriv(). Each parameter C, A, and L should have a random effect based on ID. Previous work has shown that C~4.98cm, A~0.41cm/hr, and L~0.07cm/hr. When using the SSbiexp(), there is a term for the second exponential component that is labeled here as C2, but should be the same as the (10-C) component of my self-made biexponential function.

When using nlme() with SSbiexp() I receive the error: Singularity in backsolve at level 0, block 1

nlme_ssbiexp<- nlme(CD~SSbiexp(TIME, C, A, C2, L),
                  data= df,
                  fixed = C+A+C2+L ~1, 
                  random= C+A+C2+L ~1|ID, 
                  start= c(C=4.98, A=0.41, C2= 5.02, L=0.07))

When using nlme() with my self-made biexp function I receive the error: Maximum number of iterations (maxIter = 50) reached without convergence

start<- c(C=4.98, A=0.41, L=0.07)
biexp<- ~ C*exp(-A*t) + (10-C)*exp(-L*t)
nfun <- deriv(biexp, namevec=c("C", "A", "L"),
              function.arg=c("t","C", "A", "L"))
nlme_my_biexp<- nlme(CD~nfun(TIME, C, A, L),
                  data= df,
                  fixed = C+A+L ~1, 
                  random= C+A+L ~1|ID, 
                  start= c(C=4.98, A=0.41, L= 0.07))

When using nlmer() with SSbiexp() I receive an error: Error in devfun(rho$pp$theta) : Downdated VtV is not positive definite

nlmer_ssbiexp<-nlmer(CD~SSbiexp(TIME, C, A, C2, L)~(C|PTID)+(A|PTID)+(C2|PTID)+(L|PTID),
                   data=df,
                   start= c(T1= 4.98, R1=0.41, T2=5.02, R2=0.07))

When using nlmer() with my self-made biexp function I receive the error: Error in devfun(rho$pp$theta) : prss{Update} failed to converge in 'maxit' iterations

  start<- c(C=4.98, A=0.41, L=0.07)
  biexp<- ~ C*exp(-A*t) + (10-C)*exp(-L*t)
  nfun <- deriv(biexp, namevec=c("C", "A", "L"),
                function.arg=c("t","C", "A", "L"))
  nlmer.fit.fun <- nlmer(CD ~ nfun(TIME, C, A, L) ~ (C|ID)+(A|ID)+(L|ID),
                          data = df,
                          start = start)

I had some success using the last combination of nlmer() and my self-made biexp fucntion, but only when I reduced my random effects to only including (C|ID).

start<- c(C=4.98, A=0.41, L=0.07)
  biexp<- ~ C*exp(-A*t) + (10-C)*exp(-L*t)
  nfun <- deriv(biexp, namevec=c("C", "A", "L"),
                function.arg=c("t","C", "A", "L"))
  nlmer.fit.fun <- nlmer(CD ~ nfun(TIME, C, A, L) ~ (C|ID),
                          data = df,
                          start = start)

I have tried increasing maxit and MaxIter, but both continued to fail to converge. I have been unable to find any solutions on Stack Overflow that help fixed these issues, though I have seen them discussed in several threads. I have also tried flipping the time scale so that t=0 is not always associated with CD=10, but it did not change my issues. I am new to R, so I am hoping someone that is an expert in nlmer() or nlme() might know fixes for these error messages.

Ben Bolker- if you are reading this- I would really love to talk with you!

DC22
  • 23
  • 3
  • 2
    We understand that you cannot share medical data, but the sample data set is too small. The usual approach is then to generate artificial data: Use the biexp function, add some effects for the treatments plus some random error with `rnorm`. – tpetzoldt Feb 23 '22 at 07:10
  • 2
    If you want to fit a biexponential model, you need sufficient data to do so. I would expect you need 10 to 20 time points over a sufficiently long period. You say "My dataset has no NA's and all patients have 2 or more time points." What proportion of patients have more than 10 time points? Not getting a successful fit with random effects on `A` and `L` is a hint at insufficient data coverage for too many patients. You should start with using `nlsList` and check for how many patients you can get successful fits and how much variation is in the parameters. ... – Roland Feb 23 '22 at 07:33
  • 1
    ... You can pass an `nlsList` object to `nlme`, which is what I usually do. – Roland Feb 23 '22 at 07:33
  • I agree with @Roland's comments but there is a little bit of a chicken-and-egg problem here in that the individual `nlsList` fits will be even more fragile than the mixed model (because information isn't shared across patients). The other thing to try when starting out is to plot the estimated curve for your starting parameter values against the data, to see if the starting point is as sensible as you think it is. – Ben Bolker Feb 23 '22 at 14:46
  • Also, if you know that C2 is 10-C you should (?) be able to use that directly in the `nlme`/`nlmer` fit ... – Ben Bolker Feb 23 '22 at 14:48

1 Answers1

2

Here's how far I've gotten:

  • the exponential rates are supposed to be specified as logs of the rates (to make sure that the rates themselves stay positive, i.e. that we have exponential decay curves rather than growth curves)
  • I simplified the model significantly, taking out the random effects in T1 and T2.
nlmer.ssbiexp<- nlmer(CD~SSbiexp(TIME, T1, R1, T2, R2)~
                        (R1|ID) + (R2|ID),
                      data=df,
                      start= c(T1= 4.98, R1=log(0.41), T2=5.25, R2=log(0.07)))

At this point I would try:

  • specifying T2 as 10-T1 to simplify the model (not sure if this will actually work)
  • seeing if you can build back to more complex versions of the model that actually work
Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • Thank you! I will try this today, and report back with any solutions that work. – DC22 Feb 24 '22 at 17:11
  • Specifying the `T2` as `10-T1` did not work with the SSbiexp function, but another user pointed out to me that the SSbiexp function was of the form: T1*exp(-exp(R1)*t) + T2*exp(-exp(R2)*t), which makes sense with your log() adjustments to the rate, so I.... – DC22 Feb 24 '22 at 19:07
  • .... implemented that into my self-made function. With this change I was able to add in a random effect for (C|ID)! `biexp<- ~ C*exp(-exp(A)*t) + (10-C)*exp(-exp(L)*t)` with `nfun <- deriv(biexp, namevec=c("C", "A", "L"), function.arg=c("t","C", "A", "L"))` and finally using `nlmer.mybiexp.BB.4<- nlmer(CD~nfun(TIME, C, A, L)~ (A|ID)+(L|ID)+(C|ID), data=df, start=c(C=4.98, A=log(0.41), L=log(0.07)))` – DC22 Feb 24 '22 at 19:09
  • if you have a solution that goes beyond mine it would be good to post it as an answer (comments are hard to read and ephemeral) – Ben Bolker Feb 24 '22 at 23:38