具有动态变量数量的公式

92

假设有一个数据框 foo_data_frame,想要通过其他列找到目标列 Y 的回归关系。为此通常使用公式和模型。例如:

linear_model <- lm(Y ~ FACTOR_NAME_1 + FACTOR_NAME_2, foo_data_frame)

如果公式被静态编码,那么这可以很好地完成工作。如果想要在具有恒定自变量数量(比如2个)的多个模型上进行开方运算,则可以按以下方式处理:


for (i in seq_len(factor_number)) {
  for (j in seq(i + 1, factor_number)) {
    linear_model <- lm(Y ~ F1 + F2, list(Y=foo_data_frame$Y,
                                         F1=foo_data_frame[[i]],
                                         F2=foo_data_frame[[j]]))
    # linear_model further analyzing...
  }
}

我的问题是,在程序运行期间变量数量动态改变时如何实现相同的效果?

for (number_of_factors in seq_len(5)) {
   # Then root over subsets with #number_of_factors cardinality.
   for (factors_subset in all_subsets_with_fixed_cardinality) {
     # Here I want to fit model with factors from factors_subset.
     linear_model <- lm(Does R provide smth to write here?)
   }
}

2
谢谢!你的中间例子让我意识到我不需要解决你的问题,而可以做一些更简单的事情! - Mark Adamson
5个回答

118

请参见?as.formula,例如:

factors <- c("factor1", "factor2")
as.formula(paste("y~", paste(factors, collapse="+")))
# y ~ factor1 + factor2

其中factors是包含要在模型中使用的因子名称的字符向量。您可以将其粘贴到lm模型中,例如:

set.seed(0)
y <- rnorm(100)
factor1 <- rep(1:2, each=50)
factor2 <- rep(3:4, 50)
lm(as.formula(paste("y~", paste(factors, collapse="+"))))

# Call:
# lm(formula = as.formula(paste("y~", paste(factors, collapse = "+"))))

# Coefficients:
# (Intercept)      factor1      factor2  
#    0.542471    -0.002525    -0.147433

74

一个经常被忽视的函数是reformulate。来自于?reformulate:

reformulate可以从字符向量中创建公式。


一个简单的例子:

listoffactors <- c("factor1","factor2")
reformulate(termlabels = listoffactors, response = 'y')

将产生以下公式:

y ~ factor1 + factor2


虽然没有明确记录,但您也可以添加交互项:

listofintfactors <- c("(factor3","factor4)^2")
reformulate(termlabels = c(listoffactors, listofintfactors), 
    response = 'y')

将产生:

y ~ 因子1 + 因子2 + (因子3 + 因子4)^2


3
@JorisMeys,这样做更好,因为它允许添加交互项!我寻找类似的解决方案已经好几年了… - landroni
如果x变量包含空格怎么办?比如说“因子1”,“因子2”等等。 - axiom

11

另一个选项可能是在公式中使用矩阵:

Y = rnorm(10)
foo = matrix(rnorm(100),10,10)
factors=c(1,5,8)

lm(Y ~ foo[,factors])

3
+1,但需要注意这并不允许使用交互效应。为此,可以像构建模型矩阵一样构建一个模型矩阵(参见?model.matrix)。 - Joris Meys

4

您实际上不需要公式。这个方法可以解决问题:

lm(data_frame[c("Y", "factor1", "factor2")])

就像这样:

v <- c("Y", "factor1", "factor2")
do.call("lm", list(bquote(data_frame[.(v)])))

非常正确,但是你仍需要使用model.matrix来构建一个包含交互效应的矩阵。 - Joris Meys

1

我通常通过更改响应列的名称来解决这个问题。这样做可以更加动态化,可能更加清晰。

model_response <- "response_field_name"
setnames(model_data_train, c(model_response), "response") #if using data.table
model_gbm <- gbm(response ~ ., data=model_data_train, ...)

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