La fonction qqmath crée de superbes tracés d'effets aléatoires à l'aide de la sortie du package lmer. Autrement dit, qqmath est excellent pour tracer les intersections à partir d'un modèle hiérarchique avec leurs erreurs autour de l'estimation ponctuelle. Un exemple des fonctions lmer et qqmath est présenté ci-dessous en utilisant les données intégrées dans le package lme4 appelé Dyestuff. Le code produira le modèle hiérarchique et un tracé de Nice en utilisant la fonction 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
La dernière ligne de code produit un tracé vraiment agréable de chaque interception avec l'erreur autour de chaque estimation. Mais le formatage de la fonction qqmath semble être très difficile, et j'ai eu du mal à formater l'intrigue. J'ai trouvé quelques questions auxquelles je ne peux pas répondre, et que je pense que d'autres pourraient également bénéficier s'ils utilisent la combinaison lmer/qqmath:
Jusqu'à présent, l'ajout d'une option supplémentaire dans la fonction qqmath produit des erreurs où je n'obtiendrais pas d'erreurs s'il s'agissait d'un tracé standard, donc je suis à perte.
De plus, si vous pensez qu'il existe un meilleur package/fonction pour tracer les interceptions à partir de la sortie lmer, j'aimerais l'entendre! (par exemple, pouvez-vous faire les points 1-3 en utilisant dotplot?)
EDIT: Je suis également ouvert à un pointplot alternatif s'il peut être raisonnablement formaté. J'aime juste l'apparence d'un complot ggmath, donc je commence par une question à ce sujet.
Une possibilité consiste à utiliser la bibliothèque ggplot2
pour dessiner un graphique similaire, puis vous pouvez ajuster l'apparence de votre tracé.
Tout d'abord, l'objet ranef
est enregistré sous randoms
. Ensuite, les variances des interceptions sont enregistrées dans l'objet qq
.
randoms<-ranef(fit1, postVar = TRUE)
qq <- attr(ranef(fit1, postVar = TRUE)[[1]], "postVar")
Objet Rand.interc
contient juste des interceptions aléatoires avec des noms de niveau.
Rand.interc<-randoms$Batch
Tous les objets sont placés dans un seul bloc de données. Pour les intervalles d'erreur sd.interc
est calculé comme la racine carrée de la variance 2 fois.
df<-data.frame(Intercepts=randoms$Batch[,1],
sd.interc=2*sqrt(qq[,,1:length(qq)]),
lev.names=rownames(Rand.interc))
Si vous avez besoin que les interceptions soient ordonnées dans le tracé selon la valeur, alors lev.names
doit être réorganisé. Cette ligne peut être ignorée si les interceptions doivent être classées par nom de niveau.
df$lev.names<-factor(df$lev.names,levels=df$lev.names[order(df$Intercepts)])
Ce code produit un tracé. Maintenant, les points différeront de shape
selon les niveaux de facteur.
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)
La réponse de Didzis est excellente! Pour résumer un peu, je l'ai mis dans sa propre fonction qui se comporte un peu comme qqmath.ranef.mer()
et dotplot.ranef.mer()
. En plus de la réponse de Didzis, il gère également des modèles avec plusieurs effets aléatoires corrélés (comme qqmath()
et dotplot()
do). Comparaison avec 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
Comparaison avec dotplot()
:
ggCaterpillar(ranef(fit, condVar=TRUE), QQ=FALSE)
dotplot(ranef(fit, condVar=TRUE))
Parfois, il peut être utile d'avoir différentes échelles pour les effets aléatoires - quelque chose que dotplot()
applique. Quand j'ai essayé de détendre cela, j'ai dû changer la facette (voir ceci réponse ).
ggCaterpillar(ranef(fit, condVar=TRUE), QQ=FALSE, likeDotplot=FALSE)
## 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)
}
Une autre façon de procéder consiste à extraire des valeurs simulées de la distribution de chacun des effets aléatoires et à les tracer. En utilisant le package merTools
, il est possible d'obtenir facilement les simulations à partir d'un objet lmer
ou glmer
, et de les tracer.
library(lme4); library(merTools) ## for lmer(), sleepstudy
fit <- lmer(Reaction ~ Days + (Days|Subject), sleepstudy)
randoms <- REsim(fit, n.sims = 500)
randoms
est maintenant un objet qui ressemble à:
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
Il fournit le nom du facteur de regroupement, le niveau du facteur pour lequel nous obtenons une estimation, le terme dans le modèle et la moyenne, la médiane et l'écart type des valeurs simulées. Nous pouvons l'utiliser pour générer un tracé de chenille similaire à ceux ci-dessus:
plotREsim(randoms)
Ce qui produit:
Une caractéristique intéressante est que les valeurs qui ont un intervalle de confiance qui ne chevauche pas zéro sont surlignées en noir. Vous pouvez modifier la largeur de l'intervalle en utilisant le paramètre level
sur plotREsim
en élargissant ou en rétrécissant les intervalles de confiance en fonction de vos besoins.