[英]How to extract just the random effects part of the formula from lme4
假设我安装了一个 model 这样的
mymodel <- lmer(Y~X1+(1|fac1)+(1|fac2),mydata)
如何仅提取公式 ( (1|fac1)+(1|fac2)
的随机效应部分?
我知道我能做到
formula(mymodel)[-2]
但这只会返回X1 + (1| fac1) + (1| fac2)
我知道我可以用正则表达式做点什么,但我希望有更简单的方法。
lme4 package 提供了findbars
:
library(lme4)
fo <- Y~X1+(1|fac1)+(1|fac2)
findbars(fo)
## [[1]]
## 1 | fac1
##
## [[2]]
## 1 | fac2
如果需要字符串,我们可以使用以下内容。 deparse1
将处理deparse
失败的某些不常见情况,但如果有必要在 R 早于 R 4.0.0 的版本中工作, deparse
将主要作为替代方案工作。
sapply(findbars(fo), deparse1)
## [1] "1 | fac1" "1 | fac2"
如果所需的结果是公式的 RHS 但没有固定效应项,那么我们可以通过加回括号并使用reformulate
来重构上述结果。 如果需要公式 object,请省略 [[2]]。 上面关于deparse1
的讨论也适用于此。
reformulate(sprintf("(%s)", sapply(findbars(fo), deparse1)))[[2]]
## (1 | fac1) + (1 | fac2)
获取字符结果的另一种方法是使用将从terms
中提取字符的labels
。 如果需要公式,请如上所述使用reformulate
。 这不使用任何包。
X <- grep("|", labels(terms(fo)), fixed = TRUE, value = TRUE)
X
## [1] "1 | fac1" "1 | fac2"
如上所述,公式及其右侧可以从X
生成,如下所示:
reformulate(sprintf("(%s)", X))
reformulate(sprintf("(%s)", X))[[2]]
另一种方法是使用getTerms
from Terms of a sum in a R expression这个简短的 function 递归地遍历公式以提取术语。 它不使用任何包。
XX <- grep("|", sapply(getTerms(fo[[3]]), deparse1), fixed = TRUE, value = TRUE)
XX
## [1] "(1 | fac1)" "(1 | fac2)"
可以像这样生成公式和它的右侧:
reformulate(XX)
reformulate(XX)[[2]]
不需要正则表达式,但是,它仍然是字符串操作。
# stringsplit the output of your formula()
# remove the first entry
# remove spaces with gsub()
# paste it back together
inp <- "X1 + (1| fac1) + (1| fac2)"
paste(gsub(" ", "", unlist(strsplit(inp, "+", fixed = T))[-1], fixed = T),
collapse = " + ")
# [1] "(1|fac1) + (1|fac2)"
一个可能无法概括的简单解决方案:
# This model may not make much sense, just for reproducibility
mymodel <- lmer(Petal.Length~Sepal.Width+(1|Species) + (1|Petal.Width),iris)
stringr::str_extract_all(formula(mymodel),"\\(.*\\)")[3]
[[1]]
[1] "(1 | Species) + (1 | Petal.Width)"
要“自动”删除所有空元素:
purrr::compact(stringr::str_extract_all(formula(mymodel),"\\(.*\\)"))
[[1]]
[1] "(1 | Species) + (1 | Petal.Width)"
在看到 G Grthendieck 的回答后,我意识到我可能正在重新发明轮子,但这里有一种方法可以在不使用正则表达式的情况下从 model 中获取随机效果部分。 它使用递归来检查公式的 AST 中的每个调用,并仅将那些调用保留在括号中,然后将其重建为一个表达式。 我可能是错的,但这感觉比在字符串和语言对象之间切换更安全。 可以修改为仅拉出|
电话。
get_random_effects <- function(mod)
{
rip_formula <- function(form)
{
if(rlang::is_formula(form)) form <- as.list(form)[-c(1:2)][[1]]
if(is.call(form)) {
call_list <- as.list(form)
if(as.character(call_list[[1]]) == "+")
return(unlist(lapply(call_list[-1], rip_formula)))
if(as.character(call_list[[1]]) == "(")
return(form)
}
}
re_list <- rip_formula(formula(mod))
while(length(re_list) > 2)
re_list <- c(as.call(list(bquote(`+`), re_list[1:2])), re_list[-(1:2)])
as.call(list(bquote(`+`), re_list[[1]], re_list[[2]]))
}
所以现在很简单:
get_random_effects(mymodel)
#> (1 | fac1) + (1 | fac2)
您可以使用insight-package访问各种 model 信息,例如公式、预测变量、数据等。insight提供适用于许多不同模型的类型安全“泛型”。 在这种情况下,您可以使用find_formula()
或find_random()
:
library(insight)
library(lme4)
data(sleepstudy)
sleepstudy$mygrp <- sample(1:5, size = 180, replace = TRUE)
sleepstudy$mysubgrp <- NA
for (i in 1:5) {
filter_group <- sleepstudy$mygrp == i
sleepstudy$mysubgrp[filter_group] <-
sample(1:30, size = sum(filter_group), replace = TRUE)
}
m <- lmer(
Reaction ~ Days + (1 | mygrp / mysubgrp) + (1 | Subject),
data = sleepstudy
)
#> boundary (singular) fit: see ?isSingular
find_formula(m)
#> $conditional
#> Reaction ~ Days
#>
#> $random
#> $random[[1]]
#> ~1 | mysubgrp:mygrp
#>
#> $random[[2]]
#> ~1 | mygrp
#>
#> $random[[3]]
#> ~1 | Subject
find_random(m)
#> $random
#> [1] "mysubgrp:mygrp" "mygrp" "Subject"
#>
find_random(m, split_nested = TRUE)
#> $random
#> [1] "mysubgrp" "mygrp" "Subject"
find_random(m, split_nested = TRUE, flatten = TRUE)
#> [1] "mysubgrp" "mygrp" "Subject"
find_formula()
和find_random()
也适用于具有随机效应的零膨胀部分的模型,例如来自glmmTMB或brms包的模型。 找到可能的随机斜率的“对应物”是find_random_slopes()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.