我经常需要为一次分析创建 10 多个模型,有时甚至超过 20 个模型。这些模型的基础公式通常遵循一个清晰的模式,但我常常难以想出一种编程方式来创建它们。如果我需要在许多模型中添加或更改某些内容,那么不要为每个模型重复自己就变得更加重要。
这是我的意思的一个例子。
假设我们有这个数据:
mydata <- mtcars %>%
mutate(standardized_mpg = scale(mpg)%>%as.numeric(),
logged_mpg = log(mpg))
现在我们要为三个 DV
mpg
、standaridzed_mpg
和 logged_mpg
创建回归公式。出于某种任意原因,我们总是想要两个 IV,其中一个是 gear
或 cyl
,另一个是 disp
或 hp
。换句话说,我们想要这个:
mpg ~ gear + dips
mpg ~ cyl + dips
mpg ~ gear + hp
mpg ~ cyl + hp
logged_mpg ~ gear + dips
etc.
etc.
etc.
standardized_mpg ~ gear + dips
etc.
etc.
etc.
可以通过
expand.grid()
实现这一点:
specs_dv <- c("mpg", "standardized_mpg", "logged_mpg")
specs_iv1 <- c("gear", "cyl")
specs_iv2 <- c("disp", "hp")
f <- expand.grid(
specs_dv = specs_dv,
" ~ ",
specs_iv1 = specs_iv1,
" + ",
specs_iv2 = specs_iv2
) %>%
arrange(specs_dv)
# Collapse each df row to char vector, then convert them to formulas
# At the end we will have a list-type object where every list item is a formula
f <- apply(f, 1, function(x) {
as.formula(
paste0(
as.character(x), collapse = ""
)
)})
从这里开始,我可以使用 for 循环和函数来创建模型和表格。我不会在这里添加它们,因为它偏离了主要观点。
现在,当模型之间的变量数量固定时,上述方法效果很好。然而,更常见的是,一些模型会忽略其他模型的变量。这就是我现在被困的地方。这是一些示例数据:
mydata <- ggplot2::economics %>%
mutate(psavert_l1 = lag(psavert),
standardized_psavert = scale(psavert)%>%as.numeric(),
standardized_psavert_l1 = scale(psavert_l1)%>%as.numeric(),
logged_psavert = log(psavert),
logged_psavert_l1 = log(psavert_l1)
)
这些是我想要生成的公式:
uempmed ~ psavert + psavert_l1 + unemploy
uempmed ~ psavert + psavert_l1
uempmed ~ psavert + unemploy
uempmed ~ psavert_l1 + unemploy
uempmed ~ standardized_psavert + standardized_psavert_l1 + unemploy
uempmed ~ standardized_psavert + standardized_psavert_l1
uempmed ~ standardized_psavert + unemploy
uempmed ~ standardized_psavert_l1 + unemploy
uempmed ~ log_psavert + log_psavert_l1 + unemploy
uempmed ~ log_psavert + log_psavert_l1
uempmed ~ log_psavert + unemploy
uempmed ~ log_psavert_l1 + unemploy
如您所见,这次我有两个或三个自变量。这里的模式是让一个模型包含所有三个 IV,然后再添加三个模型,每次省略一个 IV。最后,我需要这三个变量中的两个的三个修改版本。
像这样增减变量是建模时很正常的事情。因此,我想知道是否有更快的方法来创建这些公式,就像变量的数量是否固定一样。您处理这个问题的方法是什么,特别是如果有更多的变量需要处理更多的模型?手写一切似乎......只是错误的。
您可以在前缀上使用
combn
和 lapply
。
lapply(c('', 'standardized_', 'log_'), \(z) {
combn(c('psavert', 'psavert_l1', 'unemploy'), 2, FUN=\(x)
reformulate(paste0(z, x), 'uempmed'), simplify=FALSE)
})
# [[1]]
# [[1]][[1]]
# uempmed ~ psavert + psavert_l1
# <environment: 0x55c229491980>
#
# [[1]][[2]]
# uempmed ~ psavert + unemploy
# <environment: 0x55c22948f078>
#
# [[1]][[3]]
# uempmed ~ psavert_l1 + unemploy
# <environment: 0x55c2294883c8>
#
#
# [[2]]
# [[2]][[1]]
# uempmed ~ standardized_psavert + standardized_psavert_l1
# <environment: 0x55c22821cc60>
#
# [[2]][[2]]
# uempmed ~ standardized_psavert + standardized_unemploy
# <environment: 0x55c22820f3d0>
#
# [[2]][[3]]
# uempmed ~ standardized_psavert_l1 + standardized_unemploy
# <environment: 0x55c228206758>
#
#
# [[3]]
# [[3]][[1]]
# uempmed ~ log_psavert + log_psavert_l1
# <environment: 0x55c2281fed40>
#
# [[3]][[2]]
# uempmed ~ log_psavert + log_unemploy
# <environment: 0x55c2281fc438>
#
# [[3]][[3]]
# uempmed ~ log_psavert_l1 + log_unemploy
# <environment: 0x55c2281f37f8>
经过更多测试,我找到了一种合理编程的方式。
如果您有一个公式,并希望基于减去该公式的各个变量和变量名称的一些更改来创建许多新公式,则可以使用我的方法。
请注意,我正在使用各种 tidyverse 函数来实现此功能。
f <- tibble(
dv = "uempmed"
tilde = "~",
iv1 = "PREFIXpsavert",
plus = "+",
iv2 = "PREFIXpsavert_l1",
plus2 = "+",
iv3 = "unemploy"
)
f <- f %>% slice(rep(1:n(), each = 12))
# This replaces the third IV with a blank space for every fourth model, counting from the second
# (Set "by" to the number of formulas per set of formulas. In this case it's three sets of four, so it's four.)
f[seq(2, nrow(f), by=4), c("iv3", "plus2")] <- " "
# This replace the second IV with a blank space for every fourth model, counting from the third
f[seq(3, nrow(f), by=4), c("iv2", "plus")] <- " "
# This replace the first IV with a blank space for every fourth model, counting from the fourth
f[seq(4, nrow(f), by=4), c("iv1", "plus")] <- " "
f <- apply(f, 1, function(x) {
paste0(
as.character(x), collapse = ""
)})
f[1:4] <- str_replace_all(f[1:4], "PREFIX", "")
f[5:8] <- str_replace_all(f[5:8], "PREFIX", "standardized_")
f[9:12] <- str_replace_all(f[9:12], "PREFIX", "log_")
f <- lapply(f, as.formula)
我们最终得到了一个公式列表
f
,可以与lm(formula = f[[1]], data = mydata)
之类的东西一起使用。
基于这种结构,您可以轻松地将所有内容包装在一个函数中,从而使创建公式更加程序化。当然,实际模型也可以在循环中创建,例如:
for(i in length(f)) {
assign(
x = paste0("m", str_pad(i, width=2, pad=0)),
value = lm(
formula = f[[i]],
data = mydata
)
)}
据此创建观星表也是可以的,但与原题相差太远,这里不再多说。希望这篇文章能帮助遇到与我类似问题的人!