Fitting piecewise linear curves with lmer (cross-posted from the R-sig ME list - maybe this is too basic for it)
Hello
I would like to fit piecewise linear growth curves to a number of
subjects (each with a number of observations at different abscissa),
where all the slopes for a common interval (e.g, 2 <= x < 3)
presumable arise from the same normal distribution, and therefore
should be "shrunk" towards each other.  What is the best way to about
doing this in lme4?  I have a toy, cleaned up (although I am not very
good with R) example of the type of data I am looking at.
Thank you for your time
set.seed(1)
# our growth functions are piecewise linear with these breaks
breaks <- seq(0,5)
mean.slopes <- seq(5,2,-.6)

# generate the true slope parameters for 20 subjects (variance isn't
    really constant or known, just simplifying)...
true.slopes <- sapply(mean.slopes,function(x) rnorm(n=20,sd=3,mean=x))

# ...and the intercepts - they really don't come from any particular
    distribution
true.intercepts <- runif(n=20,min=30,max=50)

# generate sample data - we don't necessarily have the same number of
observations per subject
mat <- matrix(nr=20*10,nc=3)
for (i in 1:20)
{
   xs <- runif(n=10,min=0,max=6)
   slopes <- true.slopes[i,]
   ys <- true.intercepts[i] + rnorm(n=10,mean=0,sd=0.9) +
   sapply(xs, function(x) sum(slopes[1:floor(x)]) + (x - floor(x)) *
   slopes[ceiling(x)])
   id <- rep(i,10)
   mat[(1+10*(i-1)):(10*i),] <- cbind(xs,ys,id)
}
mat <- as.data.frame(mat)
names(mat) <- c("x","y","id")
# qplot(x=x,y=y,colour=as.factor(id),data=mat)

Eventually I might like to shrink the slopes for each individual
towards each other, in the sense that if for a given subject the slope
in the interval [2,3) is very small compared to the slopes of other
subjects in the same interval, then the same would hold for the slope
in [1,2), but I would like to get the basics first.
 A: Apologies for only posting code with no comments.  I wrote this but don't have time now to comment and decided it was best to save this here and comment later.
# packages needed
library(lattice)
library(latticeExtra)
library(lme4)

# make a picture of the data
mat <- mat[order(mat$id, mat$x),]
mat$id <- factor(mat$id)
plot1 <- xyplot(y~x, group=id, data=mat, type="b")
plot1

# function to set up knots
knot <- function(x, knot) {(x-knot)*(x>knot)}
knots <- function(x, knots) {
  out <- sapply(knots, function(k) knot(x, k))
  colnames(out) <- knots
  out
}

# add knots to data frame
mat$knot <- knots(mat$x, 0:5)

# piecewise curves with no random effects
m1 <- lm(y~ knot, data=mat)
summary(m1)

# get predicted values
matX <- data.frame(x=0:6)
matX$knot <- knots(matX$x, 0:5)
matX$predict <- predict(m1, newdata=matX)

# plot of data and predicted values
plot1 <- xyplot(y~x, group=id, data=mat, type="b")
plot2 <- xyplot(predict~x, data=matX, type="b", col="black", lwd=3)
plot1+plot2

# piecewise curves with random effects
m2 <- lmer(y~ knot + (knot|id), data=mat)
summary(m2)
ranef(m2)

# get predicted values
ids <- unique(mat$id)
matXid <- expand.grid(id=unique(mat$id), x=0:6)
matXid$knot <- knots(matXid$x, 0:5)
matXid$predict <- rowSums(as.matrix(coef(m2)$id[matXid$id,]) * cbind(1,matXid$knot))

# plot of data and predicted values
plot1 <- xyplot(y~x|id, data=mat, type="b", as.table=TRUE)
plot2 <- xyplot(predict~x|id, data=matXid, type="b", col="black", lwd=1)

