在R中,使用qqmath或dotplot绘制来自lmer(lme4包)的随机效果:如何使它看起来很花哨?

时间:2012-12-12 20:20:21

标签: r ggplot2 lme4 lmer random-effects

qqmath函数使用lmer软件包的输出产生很好的随机效应图。也就是说,qqmath非常适合绘制层次模型中的截距及其在点估计周围的误差。下面使用名为Dyestuff的lme4包中的内置数据,给出了lmer和qqmath函数的一个示例。代码将使用ggmath函数生成分层模型和一个漂亮的图。

library("lme4")
data(package = "lme4")

# Dyestuff 
# a balanced one-way classiï¬cation of Yield 
# from samples produced from six Batches

summary(Dyestuff)             

# Batch is an example of a random effect
# Fit 1-way random effects linear model
fit1 <- lmer(Yield ~ 1 + (1|Batch), Dyestuff) 
summary(fit1)
coef(fit1) #intercept for each level in Batch 

# qqplot of the random effects with their variances
qqmath(ranef(fit1, postVar = TRUE), strip = FALSE)$Batch

最后一行代码产生了每个截距的非常好的图,每个估计周围都有误差。但格式化qqmath函数似乎非常困难,而且我一直在努力格式化情节。我想出了一些我无法回答的问题,我认为如果他们使用lmer / qqmath组合,其他人也可以从中受益:

  1. 有没有办法获取上面的qqmath函数并添加一些 选项,例如,使某些点为空而不是填充,或者 不同颜色的不同点?例如,您是否可以填充Batch变量的A,B和C的点,但其余的点是否为空?
  2. 是否可以为每个点添加轴标签(可能沿着 例如,顶部或右侧y轴?
  3. 我的数据接近45个截距,因此可以添加 标签之间的间距使它们不会相互碰撞? 主要是,我有兴趣区分/标记点之间的点 图表,在ggmath函数中似乎很麻烦/不可能。
  4. 到目前为止,在qqmath函数中添加任何其他选项会产生错误,如果它是标准图,我就不会出错。所以我很茫然。

    另外,如果你觉得有一个更好的包装/功能来绘制来自lmer输出的拦截,我很乐意听到它! (例如,你能用dotplot做点1-3吗?)

    感谢。

    编辑:如果可以合理格式化,我也会接受替代的dotplot。我只是喜欢ggmath情节的外观,所以我开始提出一个问题。

4 个答案:

答案 0 :(得分:38)

Didzis的答案很棒!只是把它包起来,我把它放到它自己的函数中,它的行为很像qqmath.ranef.mer()dotplot.ranef.mer()。除了Didzis的答案,它还处理具有多个相关随机效应的模型(如qqmath()dotplot())。与qqmath()的比较:

require(lme4)                            ## for lmer(), sleepstudy
require(lattice)                         ## for dotplot()
fit <- lmer(Reaction ~ Days + (Days|Subject), sleepstudy)
ggCaterpillar(ranef(fit, condVar=TRUE))  ## using ggplot2
qqmath(ranef(fit, condVar=TRUE))         ## for comparison

enter image description here

dotplot()的比较:

ggCaterpillar(ranef(fit, condVar=TRUE), QQ=FALSE)
dotplot(ranef(fit, condVar=TRUE))

enter image description here

有时,为随机效应设置不同的比例可能是有用的 - dotplot()强制执行。当我试图放松这个时,我不得不改变刻面(见answer)。

ggCaterpillar(ranef(fit, condVar=TRUE), QQ=FALSE, likeDotplot=FALSE)

enter image description here

## re = object of class ranef.mer
ggCaterpillar <- function(re, QQ=TRUE, likeDotplot=TRUE) {
    require(ggplot2)
    f <- function(x) {
        pv   <- attr(x, "postVar")
        cols <- 1:(dim(pv)[1])
        se   <- unlist(lapply(cols, function(i) sqrt(pv[i, i, ])))
        ord  <- unlist(lapply(x, order)) + rep((0:(ncol(x) - 1)) * nrow(x), each=nrow(x))
        pDf  <- data.frame(y=unlist(x)[ord],
                           ci=1.96*se[ord],
                           nQQ=rep(qnorm(ppoints(nrow(x))), ncol(x)),
                           ID=factor(rep(rownames(x), ncol(x))[ord], levels=rownames(x)[ord]),
                           ind=gl(ncol(x), nrow(x), labels=names(x)))

        if(QQ) {  ## normal QQ-plot
            p <- ggplot(pDf, aes(nQQ, y))
            p <- p + facet_wrap(~ ind, scales="free")
            p <- p + xlab("Standard normal quantiles") + ylab("Random effect quantiles")
        } else {  ## caterpillar dotplot
            p <- ggplot(pDf, aes(ID, y)) + coord_flip()
            if(likeDotplot) {  ## imitate dotplot() -> same scales for random effects
                p <- p + facet_wrap(~ ind)
            } else {           ## different scales for random effects
                p <- p + facet_grid(ind ~ ., scales="free_y")
            }
            p <- p + xlab("Levels") + ylab("Random effects")
        }

        p <- p + theme(legend.position="none")
        p <- p + geom_hline(yintercept=0)
        p <- p + geom_errorbar(aes(ymin=y-ci, ymax=y+ci), width=0, colour="black")
        p <- p + geom_point(aes(size=1.2), colour="blue") 
        return(p)
    }

    lapply(re, f)
}

答案 1 :(得分:36)

一种可能性是使用库ggplot2绘制类似的图形,然后您可以调整绘图的外观。

首先,ranef对象保存为randoms。然后截距的方差保存在对象qq中。

randoms<-ranef(fit1, postVar = TRUE)
qq <- attr(ranef(fit1, postVar = TRUE)[[1]], "postVar")

对象rand.interc只包含具有关卡名称的随机拦截。

rand.interc<-randoms$Batch

所有对象都放在一个数据框中。对于错误间隔,sd.interc计算为2倍平方根方差。

df<-data.frame(Intercepts=randoms$Batch[,1],
              sd.interc=2*sqrt(qq[,,1:length(qq)]),
              lev.names=rownames(rand.interc))

如果您需要根据值在图中排序拦截,则应重新排序lev.names。如果拦截应按级别名称排序,则可以跳过此行。

df$lev.names<-factor(df$lev.names,levels=df$lev.names[order(df$Intercepts)])

此代码生成绘图。现在,根据因子水平,点数将相差shape

library(ggplot2)
p <- ggplot(df,aes(lev.names,Intercepts,shape=lev.names))

#Added horizontal line at y=0, error bars to points and points with size two
p <- p + geom_hline(yintercept=0) +geom_errorbar(aes(ymin=Intercepts-sd.interc, ymax=Intercepts+sd.interc), width=0,color="black") + geom_point(aes(size=2)) 

#Removed legends and with scale_shape_manual point shapes set to 1 and 16
p <- p + guides(size=FALSE,shape=FALSE) + scale_shape_manual(values=c(1,1,1,16,16,16))

#Changed appearance of plot (black and white theme) and x and y axis labels
p <- p + theme_bw() + xlab("Levels") + ylab("")

#Final adjustments of plot
p <- p + theme(axis.text.x=element_text(size=rel(1.2)),
               axis.title.x=element_text(size=rel(1.3)),
               axis.text.y=element_text(size=rel(1.2)),
               panel.grid.minor=element_blank(),
               panel.grid.major.x=element_blank())

#To put levels on y axis you just need to use coord_flip()
p <- p+ coord_flip()
print(p)

enter image description here

答案 2 :(得分:15)

另一种方法是从每个随机效应的分布中提取模拟值并绘制这些值。使用merTools包,可以轻松地从lmerglmer对象获取模拟,并绘制它们。

library(lme4); library(merTools)       ## for lmer(), sleepstudy
fit <- lmer(Reaction ~ Days + (Days|Subject), sleepstudy)
randoms <- REsim(fit, n.sims = 500)

randoms现在是一个对象,如下所示:

head(randoms)
groupFctr groupID        term       mean     median       sd
1   Subject     308 (Intercept)   3.083375   2.214805 14.79050
2   Subject     309 (Intercept) -39.382557 -38.607697 12.68987
3   Subject     310 (Intercept) -37.314979 -38.107747 12.53729
4   Subject     330 (Intercept)  22.234687  21.048882 11.51082
5   Subject     331 (Intercept)  21.418040  21.122913 13.17926
6   Subject     332 (Intercept)  11.371621  12.238580 12.65172

它提供了分组因子的名称,我们获得估计的因子的级别,模型中的术语,以及模拟值的均值,中位数和标准差。我们可以使用它来生成类似于上面的毛虫图:

plotREsim(randoms)

产生:

A caterpillar plot of random effects

一个很好的特性是具有不重叠零的置信区间的值以黑色突出显示。您可以使用level参数plotREsim来修改间隔的宽度,根据您的需要制作更宽或更窄的置信区间。

答案 3 :(得分:1)

获得所需图形的另一种方法是通过集成在plot_model()软件包中的sjPlot命令。优点是该命令返回一个ggplot对象,因此有许多选项可以根据需要调整图形。我将示例保持简单,因为有许多选项可以使可视化个性化-只需检查?plot_model中的所有选项即可。

library(lme4)
library(sjPlot)
#?plot_model

data(Dyestuff, package = "lme4")
summary(Dyestuff)             

fit1 <- lmer(Yield ~ 1 + (1|Batch), Dyestuff) 
summary(fit1)

plot_model(fit1, type="re",
           vline.color="#A9A9A9", dot.size=1.5,
           show.values=T, value.offset=.2)

The output of the example given above: