#-*- R -*-# Chapter 8   Non-linear Modelslibrary(MASS)library(nls)postscript(file="ch08.ps", width=8, height=6, pointsize=9)options(width=65, digits=5)# 8.1 An introductory exampledata(wtloss)attach(wtloss)# alter margin 4; others are defaultoldpar <- par(mar=c(5.1, 4.1, 4.1, 4.1))plot(Days, Weight, type="p", ylab="Weight (kg)")Wt.lbs <- pretty(range(Weight*2.205))axis(side=4, at=Wt.lbs/2.205, lab=Wt.lbs, srt=90)mtext("Weight (lb)", side=4, line=3)par(oldpar) # restore settingsdetach()# 8.2  Fitting non-linear regression modelswtloss.st <- c(b0=90, b1=95, th=120)wtloss.fm <- nls(Weight ~ b0 + b1*2^(-Days/th),   data = wtloss, start = wtloss.st, trace = T)wtloss.fmexpn <- function(b0, b1, th, x){    temp <- 2^(-x/th)    model.func <- b0 + b1 * temp    Z <- cbind(1, temp, (b1 * x * temp * log(2))/th^2)    dimnames(Z) <- list(NULL, c("b0","b1","th"))    attr(model.func, "gradient") <- Z    model.func}wtloss.gr <- nls(Weight ~ expn(b0, b1, th, Days),   data = wtloss, start = wtloss.st, trace = T)## R needs a different syntax hereexpn1 <- deriv(y ~ b0 + b1 * 2^(-x/th), c("b0", "b1", "th"),               c("b0", "b1", "th", "x"))expn1negexp <- selfStart(model = ~ b0 + b1*exp(-x/th),    initial = negexp.SSival, parameters = c("b0", "b1", "th"),    template = function(x, b0, b1, th) {})wtloss.ss <- nls(Weight ~ negexp(Days, B0, B1, theta),                 data=wtloss, trace = T)# 8.3  Non-linear fitted model objects and method functionssummary(wtloss.gr)deviance(wtloss.gr)vcov(wtloss.gr)data(muscle)A <- model.matrix(~ Strip - 1, data=muscle)rats.nls1 <- nls(log(Length) ~ cbind(A, rho^Conc),   data = muscle, start = c(rho=0.1), algorithm="plinear")B <- coef(rats.nls1)Bst <- list(alpha = B[2:22], beta = B[23], rho = B[1])rats.nls2 <- nls(log(Length) ~ alpha[Strip] + beta*rho^Conc,                  data = muscle, start = st)attach(muscle)Muscle <- expand.grid(Conc = sort(unique(Conc)),                     Strip = levels(Strip))Muscle$Yhat <- predict(rats.nls2, Muscle)Muscle$logLength <- as.numeric(rep(NA, nrow(Muscle)))ind <- match(paste(Strip, Conc),            paste(Muscle$Strip, Muscle$Conc))Muscle$logLength[ind] <- log(Length)detach()if(F) { # no Trellisxyplot(Yhat ~ Conc | Strip, Muscle, as.table = T,  ylim = range(c(Muscle$Yhat, Muscle$logLength), na.rm=T),  subscripts = T, xlab = "Calcium Chloride concentration (mM)",  ylab = "log(Length in mm)", panel =  function(x, y, subscripts, ...) {     lines(spline(x, y))     panel.xyplot(x, Muscle$logLength[subscripts], ...)  })}if(F) { ## prior to 1.1.0coplot(seq(0.8, 4, len=126) ~ Conc | Strip, Muscle, show.given=FALSE,       xlab = "Calcium Chloride concentration (mM)",       ylab = "log(Length in mm)", panel = function(x, y, ...) {           ind <- round(1+125*(y-0.8)/3.2)           lines(spline(x, Muscle$Yhat[ind]))           points(x, Muscle$logLength[ind])       })}## from 1.1.0coplot(Yhat ~ Conc | Strip, Muscle, show.given=FALSE,       xlab = "Calcium Chloride concentration (mM)",       ylab = "log(Length in mm)", subscripts = TRUE,       panel = function(x, y, subscripts, ...) {           points(x, y)           lines(spline(x, Muscle$Yhat[subscripts]))       })# 8.5  Confidence intervals for parametersexpn2 <- deriv(~b0 + b1*((w0 - b0)/b1)^(x/d0),        c("b0","b1","d0"), function(b0, b1, d0, x, w0) {})wtloss.init <- function(obj, w0) {  p <- coef(obj)  d0 <-  - log((w0 - p["b0"])/p["b1"])/log(2) * p["th"]  c(p[c("b0", "b1")], d0 = as.vector(d0))}out <- NULLw0s <- c(110, 100, 90)for(w0 in w0s) {    fm <- nls(Weight ~ expn2(b0, b1, d0, Days, w0),              wtloss, start = wtloss.init(wtloss.gr, w0))    out <- rbind(out, c(coef(fm)["d0"], confint(fm, "d0")))  }dimnames(out)[[1]] <- paste(w0s,"kg:")outdata(stormer)attach(stormer)fm0 <- lm(Wt*Time ~ Viscosity + Time - 1,  data=stormer)b0 <- coef(fm0)names(b0) <- c("b1", "b2")b0storm.fm <- nls(Time ~ b1*Viscosity/(Wt-b2), data=stormer, start=b0,          trace=T)bc <- coef(storm.fm)se <- sqrt(diag(vcov(storm.fm)))dv <- deviance(storm.fm)par(pty = "s")b1 <- bc[1] + seq(-3*se[1], 3*se[1], length = 51)b2 <- bc[2] + seq(-3*se[2], 3*se[2], length = 51)bv <- expand.grid(b1, b2)ssq <- function(b)      sum((Time - b[1] * Viscosity/(Wt-b[2]))^2)dbetas <- apply(bv, 1, ssq)cc <- matrix(Time - rep(bv[,1],rep(23, 2601)) *      Viscosity/(Wt - rep(bv[,2], rep(23, 2601))), 23)dbetas <- matrix(drop(rep(1, 23) %*% cc^2), 51)fstat <- matrix( ((dbetas - dv)/2) / (dv/21), 51, 51)qf(0.95, 2, 21)plot(b1, b2, type="n")lev <- c(1, 2, 5, 7, 10, 15, 20)contour(b1, b2, fstat, levels=lev, labex=0.75, lty=2, add=T)contour(b1, b2, fstat, levels=qf(0.95,2,21), add=T, labex=0)text(31.6, 0.3, labels="95% CR", adj=0, cex=0.75)points(bc[1], bc[2], pch=3, mkh=0.1)detach()library(boot)storm.fm <- nls(Time ~ b*Viscosity/(Wt - c), stormer,                start = c(b=29.401, c=2.2183))summary(storm.fm)$parameterst <- cbind(stormer, fit=fitted(storm.fm))storm.bf <- function(rs, i) {#  st <- st                              # for S-PLUS 5.x  st$Time <-  st$fit + rs[i]  coef(nls(Time ~ (b * Viscosity)/(Wt - c), st,           start = coef(storm.fm)))}rs <- scale(resid(storm.fm), scale = F) # remove the meanstorm.boot <- boot(rs, storm.bf, R = 4999) # pretty slowstorm.bootboot.ci(storm.boot, index=1,        type=c("norm", "basic", "perc", "bca"))boot.ci(storm.boot, index=2,        type=c("norm", "basic", "perc", "bca"))# 8.5  Assessing the linear approximationopar <- par(pty="m", mfrow=c(1,3))plot(profile(update(wtloss.gr, trace=F)))par(opar)# 8.6  Constrained non-linear regressiondata(whiteside)attach(whiteside)Gas <- Gas[Insul=="Before"]Temp <- -Temp[Insul=="Before"]#nnls.fit(cbind(1, -1, Temp), Gas)# can use box-constrained optimizerfn <- function(par) sum((Gas - par[1] - par[2]*Temp)^2)optim(rep(0,2), fn, lower=0, method="L-BFGS-B")$parrm(Gas, Temp)detach()data(wtloss)attach(wtloss)optim(c(90,95,120),      function(x) sum((Weight-x[1]-x[2]*2^(-Days/x[3]))^2),      lower=rep(0,3), method="L-BFGS-B")$pardetach()if(F) { # have none of thesewtloss.r <- function(x, Weight, Days)    Weight - x[1] - x[2] * 2^(-Days/x[3])wtloss.rg <- function(x, Weight, Days){    temp <- 2^(-Days/x[3])    -cbind(1, temp, x[2]*Days*temp*log(2)/x[3]^2)}wtloss.nl <- nlregb(nrow(wtloss), c(90, 95, 120),   wtloss.r,  wtloss.rg, lower = rep(0,3),   Weight = wtloss$Weight, Days = wtloss$Days)vcov1 <- function(object){   gr <- object$jacobian   df <- length(object$resid) - length(object$param)   sum(object$resid^2)/df * solve(t(gr) %*% gr)}sqrt(diag(vcov1(wtloss.nl)))sqrt(diag(vcov.nlregb(wtloss.nl, method="Fisher")))sqrt(diag(vcov.nlregb(wtloss.nl, method="observed")))sqrt(diag(vcov.nlregb(wtloss.nl, method="Huber")))wtloss.nl0 <-  nlregb(nrow(wtloss), c(90,95,120),    wtloss.r, lower = rep(0,3),    Weight = wtloss$Weight, Days = wtloss$Days)sqrt(diag(vcov.nlregb(wtloss.nl0)))}# 8.7  General optimization and maximum likelihood estimationdata(geyser)attach(geyser)truehist(waiting, xlim=c(35,110), ymax=0.04, h=5)width.SJ(waiting)wait.dns <- density(waiting, n=200, width=10.24)lines(wait.dns, lty=2)if(F) { # have none of theselmix2 <- deriv3(     ~ -log(p*dnorm((x-u1)/s1)/s1 + (1-p)*dnorm((x-u2)/s2)/s2),     c("p", "u1", "s1", "u2", "s2"),     function(x, p, u1, s1, u2, s2) NULL)p0 <- c(p=mean(waiting < 70), u1=50, s1=5, u2=80, s2=5)p0tr.ms <- function(info, theta, grad, scale, flags, fit.pars){    cat(round(info[3], 3), ":", signif(theta), "\n")    invisible()}wait.mix2 <- ms(~ lmix2(waiting, p, u1, s1, u2, s2),   start=p0, data = geyser, trace = tr.ms)dmix2 <- function(x, p, u1, s1, u2, s2)            p * dnorm(x, u1, s1) + (1-p) * dnorm(x, u2, s2)cf <- coef(wait.mix2)attach(structure(as.list(cf), names = names(cf)))wait.fdns <- list(x = wait.dns$x,                  y = dmix2(wait.dns$x, p, u1, s1, u2, s2))lines(wait.fdns)par(usr = c(0,1,0,1))legend(0.1, 0.9, c("Normal mixture", "Nonparametric"),    lty = c(1,2), bty = "n")pmix2 <- deriv(~ p*pnorm((x-u1)/s1) + (1-p)*pnorm((x-u2)/s2),               "x", function(x, p, u1, s1, u2, s2) {})pr0 <- (seq(along = waiting) - 0.5)/length(waiting)x0 <- x1 <- as.vector(sort(waiting)) ; del <- 1; i <- 0while((i <- 1 + 1) < 10 && abs(del) > 0.0005) {    pr <- pmix2(x0, p, u1, s1, u2, s2)    del <- (pr - pr0)/attr(pr, "gradient")    x0 <- x0 - 0.5*del    cat(format(del <- max(abs(del))), "\n")}detach()par(pty = "s")plot(x0, x1, xlim = range(x0, x1), ylim = range(x0, x1),    xlab = "Model quantiles", ylab = "Waiting time")abline(0,1)par(pty = "m")vmat <- summary(wait.mix2)$Informationcbind(coef(wait.mix2), sqrt(diag(vmat)))lmix2r <- deriv3(     ~ -log((exp(a+b*y)*dnorm((x-u1)/s1)/s1 +             dnorm((x-u2)/s2)/s2) / (1+exp(a+b*y)) ),     c("a", "b", "u1", "s1", "u2", "s2"),     function(x, y, a, b, u1, s1, u2, s2) NULL)p1 <- wait.mix2$partmp <- as.vector(p1[1])p2 <- c(a=log(tmp/(1-tmp)), b=0, p1[-1])wait.mix2r <- ms(~ lmix2r(waiting[-1], duration[-299], a, b, u1, s1, u2, s2),                 start = p2, data = geyser, trace = tr.ms)grid <- expand.grid(x=seq(1.5, 5.5, 0.1), y=seq(40, 110, 0.5))grid$z <- exp(-lmix2r(grid$y, grid$x, 16.14, -5.74, 55.14, 5.663, 81.09, 6.838))levelplot(z ~ x*y, grid, colorkey=F, at = seq(0, 0.075, 0.001),          panel= function(...) {            panel.levelplot(...)            points(duration[-299], waiting[-1])          }, xlab="previous duration", ylab="wait",   col.regions = rev(trellis.par.get("regions")$col))}mix.f <- function(p){   e <- p[1]*dnorm((waiting-p[2])/p[3])/p[3] +        (1-p[1])*dnorm((waiting-p[4])/p[5])/p[5]   if(any(e <= 0)) Inf else -sum(log(e))}waiting.init <- c(mean(waiting < 70), 50, 5, 80, 5)nlm(mix.f, waiting.init, print.level=1)mix.obj <- function(p, x){   e <- p[1]*dnorm((x-p[2])/p[3])/p[3] +        (1-p[1])*dnorm((x-p[4])/p[5])/p[5]   if(any(e <= 0)) Inf else -sum(log(e))}optim(waiting.init, mix.obj, x = waiting)optim(waiting.init, mix.obj, method="BFGS", x = waiting)mix.nl0 <- optim(waiting.init, mix.obj, method="L-BFGS-B",                 lower = c(0, -Inf, 0, -Inf, 0),                 upper = c(1, rep(Inf, 4)), x = waiting)# mix.nl0 <- nlminb(waiting.init,  mix.obj,#    scale = c(10, rep(1,4)), lower = c(0, -Inf, 0, -Inf, 0),#    upper = c(1, rep(Inf, 4)), x = waiting)if(F) {lmix2a <- deriv(     ~ -log(p*dnorm((x-u1)/s1)/s1 + (1-p)*dnorm((x-u2)/s2)/s2),     c("p", "u1", "s1", "u2", "s2"),     function(x, p, u1, s1, u2, s2) NULL)mix.gr <- function(p, x){   u1 <- p[2]; s1 <- p[3]; u2 <- p[4]; s2 <- p[5]; p <- p[1]   e <- lmix2a(x, p, u1, s1, u2, s2)   rep(1, length(x)) %*% attr(e, "gradient")}mix.nl1 <- nlminb(waiting.init, mix.obj, mix.gr,   scale = c(10, rep(1,4)), lower = c(0, -Inf, 0, -Inf, 0),   upper = c(1, rep(Inf, 4)), x = waiting)mix.grh <- function(p, x){   e <- lmix2(x, p[1], p[2], p[3], p[4], p[5])   g <- attr(e, "gradient")   g <- rep(1, length(x)) %*% g   H <- apply(attr(e, "hessian"), c(2,3), sum)   list(gradient=g, hessian=H[row(H) <= col(H)])}mix.nl2 <- nlminb(waiting.init, mix.obj, mix.grh, T,   scale = c(10, rep(1,4)), lower = c(0, -Inf, 0, -Inf, 0),   upper = c(1, rep(Inf, 4)), x = waiting)sqrt(diag(vcov.nlminb(mix.nl0)))sqrt(diag(vcov.nlminb(mix.nl1)))sqrt(diag(vcov.nlminb(mix.nl2)))}detach(geyser)AIDSfit <- function(y, z, start=rep(mean(y), ncol(z)), ...){  deviance <- function(beta, y, z) {      mu <- z %*% beta      2 * sum(mu - y - y*log(mu/y)) }  grad <- function(beta, y, z) {      mu <- z %*% beta      2 * t(1 - y/mu) %*% z }  optim(start, deviance, grad, lower = 0, y = y, z = z,        method="L-BFGS-B", ...)}Y <- scan(n=13)12 14 33 50 67 74 123 141 165 204 253 246 240library(nnet) # for class.inds <- seq(0, 13.999, 0.01); tint <- 1:14X <- expand.grid(s, tint)Z <- matrix(pweibull(pmax(X[,2] - X[,1],0), 2.5, 10),length(s))Z <- Z[,2:14] - Z[,1:13]Z <- t(Z) %*% class.ind(factor(floor(s/2))) * 0.01round(AIDSfit(Y, Z)$par)rm(s, X, Y, Z)# 8.8 Non-linear mixed effects modelslibrary(nlme)options(contrasts = c("contr.treatment", "contr.poly"))data(Sitka)sitka.nlme <- nlme(size ~ A + B * (1 - exp(-(Time-100)/C)),   fixed = list(A ~ treat, B ~ treat, C ~ 1),   random =   A + B ~ 1 | tree, data = Sitka,   start  = list(fixed = c(2, 0, 4, 0, 80)),   method = "ML", verbose = T)summary(sitka.nlme)sitka.nlme2 <- update(sitka.nlme,    fixed = list(A ~ 1, B ~ 1, C ~ 1),    start = list(fixed=c(2.4, 3.6, 82)))summary(sitka.nlme2)anova(sitka.nlme2, sitka.nlme)sitka.nlme3 <- update(sitka.nlme,                       corr = corCAR1(0.95, ~Time | tree))summary(sitka.nlme3)Fpl <- deriv(~ A + (B-A)/(1 + exp((log(d) - ld50)/th)),   c("A","B","ld50","th"), function(d, A, B, ld50, th) {})data(Rabbit)st <- coef(nls(BPchange ~ Fpl(Dose, A, B, ld50, th),          start = c(A=25, B=0, ld50=4, th=0.25),          data = Rabbit))Rc.nlme <- nlme(BPchange ~ Fpl(Dose, A, B, ld50, th),    fixed = list(A ~ 1, B ~ 1, ld50 ~ 1, th ~ 1),    random = A + ld50 ~ 1 | Animal, data = Rabbit,    subset = Treatment=="Control",    start = list(fixed=st))Rm.nlme <- update(Rc.nlme, subset = Treatment=="MDL")Rc.nlmeRm.nlmeoptions(contrasts=c("contr.treatment", "contr.poly"))c1 <- c(28, 1.6, 4.1, 0.27, 0)R.nlme1 <- nlme(BPchange ~ Fpl(Dose, A, B, ld50, th),                fixed = list(A ~ Treatment, B ~ Treatment,                             ld50 ~ Treatment, th ~ Treatment),                random =  A + ld50 ~ 1 | Animal/Run, data = Rabbit,                start = list(fixed=c1[c(1,5,2,5,3,5,4,5)]))summary(R.nlme1)R.nlme2 <- update(R.nlme1,     fixed = list(A ~ 1, B ~ 1, ld50 ~ Treatment, th ~ 1),     start = list(fixed=c1[c(1:3,5,4)]))anova(R.nlme2, R.nlme1)summary(R.nlme2)if(require(lattice)) {trellis.device(postscript, file="ch08b.ps", width=8, height=6, pointsize=9)print(xyplot(BPchange ~ log(Dose) | Animal * Treatment, Rabbit,   xlab = "log(Dose) of Phenylbiguanide",   ylab = "Change in blood pressure (mm Hg)",   subscripts = T, aspect = "xy", panel =      function(x, y, subscripts) {         panel.grid()         panel.xyplot(x, y)         sp <- spline(x, fitted(R.nlme2)[subscripts])         panel.xyplot(sp$x, sp$y, type="l")      }))} else {coplot(BPchange ~ log(Dose) | Animal * Treatment, Rabbit,       show.given=FALSE,       xlab = "log(Dose) of Phenylbiguanide",       ylab = "Change in blood pressure (mm Hg)",       subscripts = TRUE,       panel = function(x, y, subscripts, ...) {           points(x, y)           lines(spline(x, fitted(R.nlme2)[subscripts]))       })}# End of ch08