仅在第一次出现另一个模式之前查找模式(或:如何从混合效应模型的公式中删除随机效应)

Find pattern only until first occurrence of another pattern (or: how to remove random effects from a formula of mixed effects models)

我想从模型公式中提取信息,特别是我想删除随机效应以仅从混合模型(lme4-notation)中获得 "fixed effects part"。

为此,我在找到括号 ( 之前搜索公式中的最后一个 ++ 之前的所有内容都必须是公式的 "fixed" 部分。这适用于具有固定效应预测变量/变量的模型。

但是,对于空模型(固定效应中的截距),可能没有 +,例如如果公式是 Reaction ~ (Days | Subject)。在这种情况下,我检查是否有 no +-sign。但这不适用于具有 多个 随机部分的模型。在下面的示例中,grepl()for f2 应该 return FALSE,但是 returns TRUE,因为 + 是在随机部分找到 second 开头的括号。

我的问题:如何在第一个 ( 之后停止检查 +,以便忽略可能的第二个或第三个随机效应项?以下示例的目标是 grepl()-命令 return FALSEFALSETRUETRUE.

f1 <- "Reaction ~ (1 + Days | Subject)"
f2 <- "Reaction ~ (1 | mygrp/mysubgrp) + (1 | Subject)"
f3 <- "Reaction ~ x1 + x2 + (1 + Days | Subject)"
f4 <- "Reaction ~ x1 + x2 + (1 | mygrp/mysubgrp) + (1 | Subject)"

# works!
grepl("\+(\s)*\((.*)\)", f1) # should return FALSE
#> [1] FALSE

# fails...
grepl("\+(\s)*\((.*)\)", f2) # should return FALSE
#> [1] TRUE

# works!
grepl("\+(\s)*\((.*)\)", f3) # should return TRUE
#> [1] TRUE

# works!
grepl("\+(\s)*\((.*)\)", f4) # should return TRUE
#> [1] TRUE

这并不是真正从 RE 角度回答您的问题(可能有答案),但如果您的目标是提取随机效应 and/or 固定效应公式,您可能会从中获得更多收益glFormulalFormula 的源代码构成了 lme4 包本身。由于他们分别为固定效应和随机效应创建设计矩阵 XZ,因此他们必须在某些点提取各自的部分。

例如,要提取固定效应,使用函数 nobarsRHSForm

library(lme4)
f1 <- Reaction ~ (1 + Days | Subject)
f2 <- Reaction ~ (1 | mygrp/mysubgrp) + (1 | Subject)
f3 <- Reaction ~ x1 + x2 + (1 + Days | Subject)
f4 <- Reaction ~ x1 + x2 + (1 | mygrp/mysubgrp) + (1 | Subject)
(f1FixedEffects <- nobars(lme4:::RHSForm(f1)) #note the triple 'lme4:::'. RHSForm is not exported to the public environment.
[1] 1
(f2FixedEffects <- nobars(lme4:::RHSForm(f2))
[1] 1
(f1FixedEffects <- nobars(lme4:::RHSForm(f3))
x1 + x2
(f1FixedEffects <- nobars(lme4:::RHSForm(f4))
x1 + x2

如果想要提取整个公式,您可以使用

lme4:::RHSForm(f1) <- nobars(lme4:::RHSForm(f1)
f1
Reaction ~ 1

或类似(感谢 AkselA 的评论)

nobars(f1)
Reaction ~ 1

对于固定效应。

请注意,我已将您的字符串公式转换为公式。这也可以用 'as.formula()'

来完成

Oliver 的回答是正确的,尤其是当您已经在使用 lme4 时,但还有一个 base 框架可以用来修改公式。

# Is read as class formula
f4 <- Reaction ~ x1 + x2 + (1 | mygrp/mysubgrp) + (1 | Subject)

# Isolate the terms and find which contains a vertical bar
f4t <- terms(f4)
dr <- grep("|", labels(f4t), fixed=TRUE)

# Drop the term(s) containing a vertical bar
f4td <- drop.terms(f4t, dr)

# Update the old formula with the new set of terms
f4u <- update(f4, f4td)

# Voilà
f4u
# Reaction ~ x1 + x2

如评论中所述,这在两种特殊情况下会失败:所有效果都是随机的,没有效果是随机的。为了妥善处理这些异常,我发现最好在编写函数时编写一个适当的函数。

drop_randfx <- function(form) {
    form.t <- terms(form)
    dr <- grepl("|", labels(form.t), fixed=TRUE)
    if (mean(dr) == 1) {
        form.u <- update(form, . ~ 1)
    } else {
        if (mean(dr) == 0) {
            form.u <- form
        } else {
            form.td <- drop.terms(form.t, which(dr))
            form.u <- update(form, form.td)
        }
    }
    form.u
}

这通过了所有测试

f1 <- Reaction ~ (1 + Days | Subject)
f2 <- Reaction ~ (1 | mygrp/mysubgrp) + (1 | Subject)
f3 <- Reaction ~ x1 + x2 + (1 + Days | Subject)
f4 <- Reaction ~ x1 * x2 + (1 | mygrp/mysubgrp) + (1 | Subject)
f5 <- Reaction ~ x1 + x2

sapply(list(f1, f2, f3, f4, f5), drop_randfx)    # [[1]]

# [[1]]
# Reaction ~ 1
# 
# [[2]]
# Reaction ~ 1
# 
# [[3]]
# Reaction ~ x1 + x2
# 
# [[4]]
# Reaction ~ x1 + x2 + x1:x2
# 
# [[5]]
# Reaction ~ x1 + x2