glmer logit - 用概率刻度测量的交互作用效应(使用`predict`复制“effects”)

12
我正在使用lme4包运行glmer logit模型。我对各种二元和三元交互作用效应及其解释感兴趣。为简化问题,我只关心固定效应系数。
我设法编写了一段代码来计算并绘制这些效应的logit比例,但我在将它们转换为预测概率比例时遇到了困难。最终,我希望复制“effects”包的输出结果。
该示例依赖于UCLA癌症患者数据
library(lme4)
library(ggplot2)
library(plyr)

getmode <- function(v) {
  uniqv <- unique(v)
  uniqv[which.max(tabulate(match(v, uniqv)))]
}

facmin <- function(n) {
  min(as.numeric(levels(n)))
}

facmax <- function(x) {
  max(as.numeric(levels(x)))
}

hdp <- read.csv("http://www.ats.ucla.edu/stat/data/hdp.csv")

head(hdp)
hdp <- hdp[complete.cases(hdp),]

hdp <- within(hdp, {
  Married <- factor(Married, levels = 0:1, labels = c("no", "yes"))
  DID <- factor(DID)
  HID <- factor(HID)
  CancerStage <- revalue(hdp$CancerStage, c("I"="1", "II"="2", "III"="3", "IV"="4"))
})

直到这里都是关于数据管理、函数和我需要的包。

m <- glmer(remission ~ CancerStage*LengthofStay + Experience +
             (1 | DID), data = hdp, family = binomial(link="logit"))
summary(m)

这是模型。它需要一分钟,并收敛并显示以下警告:

Warning message:
In checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv,  :
  Model failed to converge with max|grad| = 0.0417259 (tol = 0.001, component 1)

尽管我不确定是否应该担心这个警告,但我使用估计值来绘制所关注的交互作用的平均边际效应。首先,我准备将数据集馈送到predict函数中,然后使用固定效应参数计算边际效应以及置信区间。
newdat <- expand.grid(
  remission = getmode(hdp$remission),
  CancerStage = as.factor(seq(facmin(hdp$CancerStage), facmax(hdp$CancerStage),1)),
  LengthofStay  = seq(min(hdp$LengthofStay, na.rm=T),max(hdp$LengthofStay, na.rm=T),1),
  Experience  = mean(hdp$Experience, na.rm=T))

mm <- model.matrix(terms(m), newdat)
newdat$remission <- predict(m, newdat, re.form = NA)
pvar1 <- diag(mm %*% tcrossprod(vcov(m), mm))
cmult <- 1.96

## lower and upper CI
newdat <- data.frame(
  newdat, plo = newdat$remission - cmult*sqrt(pvar1), 
  phi = newdat$remission + cmult*sqrt(pvar1))

我相信这些是在logit比例尺上的正确估计,但也许我错了。无论如何,这是图表:

plot_remission <- ggplot(newdat, aes(LengthofStay,
  fill=factor(CancerStage), color=factor(CancerStage))) +
  geom_ribbon(aes(ymin = plo, ymax = phi), colour=NA, alpha=0.2) + 
  geom_line(aes(y = remission), size=1.2) + 
  xlab("Length of Stay") + xlim(c(2, 10)) +
  ylab("Probability of Remission") + ylim(c(0.0, 0.5)) +
  labs(colour="Cancer Stage", fill="Cancer Stage") + 
  theme_minimal()

plot_remission

我认为现在的OY比例是以logit为单位度量的,但为了理解它,我希望将其转换为预测概率。根据wikipedia,类似于exp(value)/(exp(value)+1)这样的公式可以得到预测概率。虽然我可以使用newdat$remission <- exp(newdat$remission)/(exp(newdat$remission)+1),但我不确定应该如何处理置信区间。 最终,我想得到与effects包生成的相同图形。即:
eff.m <- effect("CancerStage*LengthofStay", m, KR=T)

eff.m <- as.data.frame(eff.m)

plot_remission2 <- ggplot(eff.m, aes(LengthofStay,
  fill=factor(CancerStage), color=factor(CancerStage))) +
  geom_ribbon(aes(ymin = lower, ymax = upper), colour=NA, alpha=0.2) + 
  geom_line(aes(y = fit), size=1.2) + 
  xlab("Length of Stay") + xlim(c(2, 10)) +
  ylab("Probability of Remission") + ylim(c(0.0, 0.5)) +
  labs(colour="Cancer Stage", fill="Cancer Stage") + 
  theme_minimal()

plot_remission2

即使我可以使用effects包,但是它不幸地无法与我必须运行的许多模型编译。
Error in model.matrix(mod2) %*% mod2$coefficients : 
  non-conformable arguments
In addition: Warning message:
In vcov.merMod(mod) :
  variance-covariance matrix computed from finite-difference Hessian is
not positive definite or contains NA values: falling back to var-cov estimated from RX

修复这个问题需要调整估计过程,但目前我想避免这样做。此外,我也很好奇 effects 在这里实际上是做什么。 如果有任何关于如何调整我的初始语法以获得预测概率的建议,我将不胜感激!

1
我认为如果按照以下方式操作,你的图表会更易读: ggplot(newdat, aes(LengthofStay, fill=factor(CancerStage), color=factor(CancerStage))) + geom_ribbon(aes(ymin=plo, ymax=phi), colour=NA, alpha=0.2) + geom_line(aes(y = remission), size=1.2) + xlab("住院时间") + ylab("缓解概率") + labs(colour="癌症分期", fill="癌症分期") + theme_minimal() - eipi10
我真的不明白为什么这个问题如此难以回答...我在请求中有什么地方不清楚吗? - Erdne Htábrob
当然,谢谢!但那只是一个次要的问题。基于“predict”的初始语法,我如何使图表反映出预测概率? - Erdne Htábrob
可以通过运行getAnywhere(Effect.default)来获取由Effects包运行的代码。 - Ian Wesley
顺便提一下,你代码中的这行无法复制,因为“revalue”函数既不在基本的 R 中,也不在已加载的包中:“CancerStage <- revalue(hdp $ CancerStage,c(“I”=“1”,“II”=“2”,“III”=“3”,“IV”=“4”))”。我改用了“levels(hdp $ CancerStage) <- c(1:4)”代替。 - Gilles San Martin
显示剩余2条评论
1个回答

5
要获得与您问题中提供的effect函数类似的结果,您只需要使用您提供的转换方法将预测值和置信区间的边界从logit比例尺转换回原始比例尺:exp(x)/(1+exp(x))
在基本R中可以使用plogis函数进行此转换:
> a <- 1:5
> plogis(a)
[1] 0.7310586 0.8807971 0.9525741 0.9820138 0.9933071
> exp(a)/(1+exp(a))
[1] 0.7310586 0.8807971 0.9525741 0.9820138 0.9933071

因此,采用 @eipi10 的建议,使用彩带来代替虚线表示置信区间(我也觉得这种展示更易读):

   ggplot(newdat, aes(LengthofStay, fill=factor(CancerStage), color=factor(CancerStage))) +
        geom_ribbon(aes(ymin = plogis(plo), ymax = plogis(phi)), colour=NA, alpha=0.2) + 
        geom_line(aes(y = plogis(remission)), size=1.2) + 
        xlab("Length of Stay") + xlim(c(2, 10)) +
        ylab("Probability of Remission") + ylim(c(0.0, 0.5)) +
        labs(colour="Cancer Stage", fill="Cancer Stage") + 
        theme_minimal()

enter image description here

结果相同(使用effects_3.1-2lme4_1.1-13):

> compare <- merge(newdat, eff.m) 
> compare[, c("remission", "plo", "phi")] <- 
+     sapply(compare[, c("remission", "plo", "phi")], plogis)
> head(compare) 
  CancerStage LengthofStay  remission Experience        plo       phi        fit        se      lower     upper
1           1           10 0.20657613   17.64129 0.12473504 0.3223392 0.20657613 0.3074726 0.12473625 0.3223368
2           1            2 0.35920425   17.64129 0.27570456 0.4522040 0.35920425 0.1974744 0.27570598 0.4522022
3           1            4 0.31636299   17.64129 0.26572506 0.3717650 0.31636299 0.1254513 0.26572595 0.3717639
4           1            6 0.27642711   17.64129 0.22800277 0.3307300 0.27642711 0.1313108 0.22800360 0.3307290
5           1            8 0.23976445   17.64129 0.17324422 0.3218821 0.23976445 0.2085896 0.17324530 0.3218805
6           2           10 0.09957493   17.64129 0.06218598 0.1557113 0.09957493 0.2609519 0.06218653 0.1557101
> compare$remission-compare$fit
 [1] 8.604228e-16 1.221245e-15 1.165734e-15 1.054712e-15 9.714451e-16 4.718448e-16 1.221245e-15 1.054712e-15 8.326673e-16
[10] 6.383782e-16 4.163336e-16 7.494005e-16 6.383782e-16 5.689893e-16 4.857226e-16 2.567391e-16 1.075529e-16 1.318390e-16
[19] 1.665335e-16 2.081668e-16

置信区间之间的差异较大,但仍然非常小:
> compare$plo-compare$lower
 [1] -1.208997e-06 -1.420235e-06 -8.815678e-07 -8.324261e-07 -1.076016e-06 -5.481007e-07 -1.429258e-06 -8.133438e-07 -5.648821e-07
[10] -5.806940e-07 -5.364281e-07 -1.004792e-06 -6.314904e-07 -4.007381e-07 -4.847205e-07 -3.474783e-07 -1.398476e-07 -1.679746e-07
[19] -1.476577e-07 -2.332091e-07

但是如果我使用正态分布的实际分位数cmult <- qnorm(0.975),而不是cmult <- 1.96,我对于这些边界也获得非常小的差异:

> compare$plo-compare$lower
 [1] 5.828671e-16 9.992007e-16 9.992007e-16 9.436896e-16 7.771561e-16 3.053113e-16 9.992007e-16 8.604228e-16 6.938894e-16
[10] 5.134781e-16 2.289835e-16 4.718448e-16 4.857226e-16 4.440892e-16 3.469447e-16 1.006140e-16 3.382711e-17 6.765422e-17
[19] 1.214306e-16 1.283695e-16

谢谢!这很有帮助!不幸的是,两个图之间仍然存在一些小差别。我将它们放到了相同的比例尺中,这样曲线上就可以看到它们的区别(我添加了xlimylim)。您也可以使用例如compare <- merge(newdat, eff.m)head(compare)以及compare$remission - compare$fit来查看差异。实际上,在这个例子中,差异非常小,但是我想知道这个偏差来自何处,以便在我的研究中消除它。PS: 我编辑了图并添加了plyr包。感谢您的回答! - Erdne Htábrob
请参见编辑后的回复。我无法复制任何显着差异。也许是包版本的差异?注意,在您的代码中还应添加library(effects)并删除第一个图的ylim(此图在logit比例上,因此0,0.5限制超出了图的范围)。 - Gilles San Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接