Visualizing bivariate shrinkage
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Inspired by this post about visualizing shrinkage on Coppelia, and this thread about visualizing mixed models on Stack Exchange, I started thinking about how to visualize shrinkage in more than one dimension. One might find themselves in this situation with a varying slope, varying intercept hierarichical (mixed effects) model, a model with two varying intercepts, etc. Then I found a great bivariate shrinkage plot in Doug Bates’ lme4 book, Figure 3.8.
Here is a snippet to reproduce a similar bivariate shrinkage plot in ggplot2, adding a color coded probability density surface and contours for the estimated multivariate normal distribution of random effects, using the same sleep study data that Bates used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | ## 2d shrikage for random slope, random intercept model library(lme4) library(ggplot2) library(grid) library(mvtnorm) library(reshape2) library(ellipse) # fit models m0 <- lm(Reaction ~ Days * Subject, data=sleepstudy) m1 <- lmer(Reaction ~ Days + (Days | Subject), sleepstudy) # extract fixed effect estimates intercepts <- grepl("Days", names(coef(m0))) == FALSE m0_intercepts <- coef(m0)[intercepts] m0_intercepts[-1] <- m0_intercepts[-1] + m0_intercepts[1] slopes <- !intercepts m0_slopes <- coef(m0)[slopes] m0_slopes[-1] <- m0_slopes[-1] + m0_slopes[1] # extract random effect estimates m1_intercepts <- coef(m1)$Subject[, 1] m1_slopes <- coef(m1)$Subject[, 2] d <- data.frame(interceptF = m0_intercepts, slopeF = m0_slopes, interceptR = m1_intercepts, slopeR = m1_slopes ) # 95% bivariate normal ellipse for random effects df_ell <- data.frame(ellipse(VarCorr(m1)$Subject, centre=fixef(m1))) names(df_ell) <- c("intercept", "slope") # bivariate normal density surface lo <- 200 # length.out of x and y grid xvals <- seq(from = min(df_ell$intercept) - .1 * abs(min(df_ell$intercept)), to = max(df_ell$intercept) + .05 * abs(max(df_ell$intercept)), length.out = lo) yvals <- seq(from = min(df_ell$slope) - .4 * abs(min(df_ell$slope)), to = max(df_ell$slope) + .1 * abs(max(df_ell$slope)), length.out = lo) z <- matrix(0, lo, lo) for (i in 1:lo) { x = xvals y = yvals[i] z[,i] = dmvnorm(cbind(x,y), mean = fixef(m1), sigma = VarCorr(m1)$Subject) } mv_ranef <- melt(z) names(mv_ranef) <- c("x", "y", "z") mv_ranef$x <- xvals[mv_ranef$x] mv_ranef$y <- yvals[mv_ranef$y] p <- ggplot(d) + geom_raster(aes(x=x, y=y, fill=z), data=mv_ranef) + scale_fill_gradient(low="white", high="red") + guides(fill=FALSE) + geom_path(data=df_ell, aes(x=intercept, y=slope), size=.5) + geom_contour(aes(x=x, y=y, z=z), data=mv_ranef, size=.1, color="black") + geom_segment(aes(x=interceptF, y=slopeF, xend=interceptR, yend=slopeR), arrow = arrow(length = unit(0.3, "cm")), alpha=.7) + xlab("Estimated intercepts") + ylab("Estimated slopes") + theme(legend.position="none") + ggtitle("Bivariate shrinkage plot") + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) p |
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.