如何在 R 的 lm() 中正确 select 因变量和控件?

How to correctly select dependent variable and controls in lm() in R?

我正在寻找一种方法来构建一个函数,允许用户在给定数据框的情况下:

  1. 选择哪个变量将作为因变量;
  2. 选择某个控件(唯一变量);
  3. 基于这些选择,运行 几种不同的回归;

理想情况下,我想要这样的东西:

df <- mtcars

myreg <- function(dv, control) {
  mod1 <- lm(dv ~ control + mpg, data = df)
  mod2 <- lm(dv ~ control + wt, data = df)
  mod3 <- lm(dv ~ control + wt + mpg, data = df)
  return(list("reg1" = mod1, "reg2" = mod2, "reg3" = mod3))
}

我的第一个猜测是提供带有列名的字符串会起作用。但是 R 会抛出一个错误。它告诉我变量的长度不匹配。此外,不传递字符串而仅传递名称也不起作用。

我尝试了一些基于 get 函数的解决方案。但是,它没有正确解析控件,老实说,我还不明白它是如何工作的。

在函数中实现这些选择的正确方法是什么?

您应该使用字符串替换。下面的代码片段简要概述了如何调整函数。将数据集 df 作为函数中的附加参数传递也是一种很好的做法。

df <- mtcars

## these would be function inputs
dv              <- "mpg"
control         <- "cyl"

## this would form the function body 
tmpl            <- "dv ~ control" # create a template formula 
tmpl.dv         <- gsub("dv", dv, tmpl) # insert the dv
tmpl.dv.control <- gsub("control", control, tmpl.dv) # insert the control
form            <- as.formula(tmpl.dv.control) # create the formula to use in lm

## fit the model
mod <- lm(form, data = df)

您要做的是为回归创建一个包装函数。理想情况下,您可以对此进行编程,以便该函数可以接受任意数据集和指定的响应变量、控制变量和其他模型项,然后生成所有感兴趣的模型。

通常我们希望用户输入不带引号的变量名,我们使用 deparse(substitute(...)) 将此输入的名称提取为“未计算的表达式”。对于回归中的其他模型项,由于可以有任意多个,合理的输入将是字符向量列表。当您创建包装函数时,它通常会为感兴趣的模型构造一个“内部调用”,这可能与这些模型的标准调用不同。因此,您通常还想修改模型的调用,使它们看起来像标准调用。所以,使用这种语法,你会写这样的东西:

myreg <- function(response, control, other.terms = NULL, data) {
  
  #Get variable names and other terms
  DATA.NAME     <- deparse(substitute(data))
  RESPONSE.NAME <- deparse(substitute(response))
  CONTROL.NAME  <- deparse(substitute(control))
  if (is.null(other.terms)) {
    OTHER <- vector(mode = 'list', length = 1) } else {
    OTHER <- other.terms }

  #Set formula and model objects
  m <- length(OTHER)
  FORMULAE <- vector(mode = 'list', length = m)
  MODELS   <- vector(mode = 'list', length = m)
  names(MODELS) <- sprintf('MODEL%s', 1:m)
  FORM     <- paste(RESPONSE.NAME, '~', CONTROL.NAME)
  
  #Fit models
  for (i in 1:m) {
    
    #Set the formula
    if (is.null(OTHER[[i]])) {
      FORMULAE[[i]] <- FORM } else {
      FORMULAE[[i]] <- paste(FORM, '+', paste(OTHER[[i]], collapse = '+')) }
    
    #Fit the model and substitute the call
    MODELS[[i]] <- lm(formula(FORMULAE[[i]]), data = data)
    CALL <- paste0('lm(formula = ', FORMULAE[[i]], ', data = ', DATA.NAME, ')')
    MODELS[[i]]$call <- parse(text = CALL)[[1]] }
  
  #Return the models
  MODELS }

然后您可以使用该函数生成具有指定变量的多元回归模型列表。这是一个示例,其中您生成了三个不同的模型,每个模型都具有相同的响应和控制变量,但模型中的附加项不同:

(MODELS <- myreg(response    = hp, 
                 control     = cyl,
                 other.terms = list('mpg', 'wt', c('mpg', 'wt')), 
                 data        = mtcars))

$MODEL1

Call:
lm(formula = hp ~ cyl + mpg, data = mtcars)

Coefficients:
(Intercept)          cyl          mpg  
     54.067       23.979       -2.775  

$MODEL2

Call:
lm(formula = hp ~ cyl + wt, data = mtcars)

Coefficients:
(Intercept)          cyl           wt  
     -51.81        31.39         1.33  

$MODEL3

Call:
lm(formula = hp ~ cyl + mpg + wt, data = mtcars)

Coefficients:
(Intercept)          cyl          mpg           wt  
     115.66        25.03        -4.22       -12.13