[R] estimating the starting value within a ODE using nls and lsoda

Conti, David dconti at usc.edu
Tue Apr 6 23:33:43 CEST 2010


All-

I am interested in estimating a parameter that is the starting value for an ODE model. 

That is, in the typical combined fitting procedure using nls and lsoda (alternatively rk4), I first defined the ODE model:

minmod <- function(t, y, parms) {
	G <- y[1]
	X <- y[2]
  with(as.list(parms),{
    I_t <- approx(time, I.input, t)$y
    dG <- -1*(p1 + X)*G +p1*G_b
    dX <- -1*p2*X + p3*(I_t-I_b)
    list(c(dG, dX))
  })
}

Then I estimated the parameters of the model using nls:

fit.rk4 <- nls(noisy ~ rk4(p4, time, minmod, parms=c(p1,p2,p3))

However, my goal is to not only estimate p1, p2 and p3, but also to estimate the starting value p4 from the data.

I am currently using the following procedure using optim to accomplish this:

step 1 (define a DevFun to optimize):
DevFunc <- function(p4) {
	fit.rk4 <- nls(noisy ~ rk4(p4, time, ODE.model, params)
	r <- deviance(fit.rk4)
	r
}

step 2 (optimize with optim):
fit <- optim(inits, DevFunc, method="L-BFGS-B", hessian=T, lower=lower, upper=upper)

I have explored this via simulation and with real data and while the procedure works for most cases, there are a few cases that cause difficulty.  I think it has to do with estimating p1, p2 and p3 conditional on p4 as opposed to estimating all parameters jointly.

Does anyone know of a way in [R] to estimate the starting value jointly with the parameters within a ODE model?  I have included more detailed code below to "spin a perfect cycle" to give a better idea of what I am trying to accomplish.

Thanks in advance,
Dave

###########################################
require(odesolve)

### ODE model
minmod <- function(t, y, parms) {
	G <- y[1]
	X <- y[2]
  with(as.list(parms),{
    I_t <- approx(time, I.input, t)$y
    dG <- -1*(p1 + X)*G +p1*G_b
    dX <- -1*p2*X + p3*(I_t-I_b)
    list(c(dG, dX))
  })
}

##### simulate data
I.input <- c(5.8,7.8,11.5,10.1,9.9,9.8,12.1,10.7,11.1,11.5,11.2,10.3,171.0,179.0,145.6,147.0,105.0,20.2,15.3,14.7,12.3,10.4,7.7,7.0,7.5,4.9,5.6,5.8)
time <- c(0,1,3,4,6,7,8,10,12,14,16,19,22,23,24,25,27,40,50,60,70,80,90,100,120,140,160,180)
G_b <- 100
I_b <- 5.8
parms <- c(p1=0.012584, p2=0.037708, p3=0.000012524)
xstart <- c(G=273.92,X=0)
sim.data <- as.data.frame(rk4(y=xstart, time=time, func=minmod, parms=parms))  # note: i use rk4 because the standard software for estimating this model uses a Runge-Kutta approach
sim.data$noisy <- sim.data$G + rnorm(nrow(sim.data), mean=0, sd=0.01*sim.data$G)

###### estimation
Weight <- c(0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
xstart.est <- c(G=mean(sim.data$noisy[1:4]), X=0)

# inital fit of nls
fit.rk4 <- nls(noisy ~ rk4(xstart.est, time, minmod, c(p1=p1, p2=p2, p3=p3))[,2],
               data=sim.data,
               start=list(p1=0.025, p2=0.02, p3=0.00004),
               trace=F,
               control=list(tol=1e-4, minFactor=1/1024/1024, warnOnly=T),
               weight=(1/(G*0.015))*Weight
               )

# define deviance function to optimize               
DevFunc <- function(p4) {
	fit.rk4 <- nls(noisy ~ rk4(c(G=p4, X=0), time, minmod, c(p1=p1, p2=p2, p3=p3))[,2],
               data=sim.data,
               start=list(p1=summary(fit.rk4)$coef[1,1], p2=summary(fit.rk4)$coef[2,1], p3=summary(fit.rk4)$coef[3,1]),
               trace=F,
               control=list(tol=1e-4, minFactor=1/1024/1024, warnOnly=T),
               weight=(1/(G*0.015))*Weight
               )     
  		r <- deviance(fit.rk4)
		r
}

##### estimation via optim
inits=c(mean(sim.data$noisy[1:5]))
lower=G_b
upper=500
fit <- optim(inits, DevFunc, method="L-BFGS-B", hessian=T, lower=lower, upper=upper)

#extract p1, p2, and p3 conditional on estimated p4:
fit.rk4 <- nls(noisy ~ rk4(c(G=fit$par, X=0), time, minmod, c(p1=p1, p2=p2, p3=p3))[,2],
               data=sim.data,
               start=list(p1=summary(fit.rk4)$coef[1,1], p2=summary(fit.rk4)$coef[2,1], p3=summary(fit.rk4)$coef[3,1]),
               trace=F,
               control=list(tol=1e-4, minFactor=1/1024/1024, warnOnly=T),
               weight=(1/(G*0.015))*Weight
               )

# get all four parameters:
p <- list(p1=summary(fit.rk4)$coef[1,1], p2=summary(fit.rk4)$coef[2,1], p3=summary(fit.rk4)$coef[3,1], p4=fit$par)
p






David V. Conti, Ph.D.
Associate Professor

University of Southern California
Zilkha Neurogenetics Institute
Keck School of Medicine
Department of Preventive Medicine
Division of Biostatistics

Mailing Address:
University of Southern California
1501 San Pablo Street
ZNI 101, MC2821
Los Angeles, CA 90089-2821

Physical Address:
USC/Harlyne Norris Research Tower
1450 Biggy Street
NRT 2509L
Los Angeles, CA 90033

Tel: 323-442-3140
Fax: 323-442-2448
Email: dconti at usc.edu



More information about the R-help mailing list