如何在 R 的 lm() 中正确 select 因变量和控件?
How to correctly select dependent variable and controls in lm() in R?
我正在寻找一种方法来构建一个函数,允许用户在给定数据框的情况下:
- 选择哪个变量将作为因变量;
- 选择某个控件(唯一变量);
- 基于这些选择,运行 几种不同的回归;
理想情况下,我想要这样的东西:
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
我正在寻找一种方法来构建一个函数,允许用户在给定数据框的情况下:
- 选择哪个变量将作为因变量;
- 选择某个控件(唯一变量);
- 基于这些选择,运行 几种不同的回归;
理想情况下,我想要这样的东西:
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