运行lm在不同变量上的函数

10
我希望创建一个函数,可以在给定数据集的不同变量上运行回归模型(例如使用lm)。在该函数中,我将指定使用的数据集,因变量y和自变量x作为参数。我希望这是一个函数而不是循环,因为我想在脚本的各个位置调用代码。我的函数看起来像这样:
lmfun <- function(data, y, x) {
  lm(y ~ x, data = data)
}

这个函数显然无法正常工作,因为lm函数不将y和x识别为数据集的变量。
我做了一些研究,偶然发现了以下有用的vignette:使用dplyr进行编程。这篇vignette提供了与我面临的类似问题的以下解决方案:
df <- tibble(
  g1 = c(1, 1, 2, 2, 2),
  g2 = c(1, 2, 1, 2, 1),
  a = sample(5),
  b = sample(5)
)

my_sum <- function(df, group_var) {
  group_var <- enquo(group_var)
  df %>%
    group_by(!! group_var) %>%
    summarise(a = mean(a))
}

我知道lm不是dplyr包中的函数,但我想找出类似于这个解决方案的方法。我尝试了以下方法:

lmfun <- function(data, y, x) {
  y <- enquo(y)
  x <- enquo(x)

  lm(!! y ~ !! x, data = data)
}

lmfun(mtcars, mpg, disp)

运行这段代码会出现以下错误信息:

在 is_quosure(e2) 函数中出错:参数“e2”缺失,无默认值

有没有人知道如何修改代码使其正常工作?
谢谢,
Joost。
4个回答

5

您可以通过使用quo_nameformula来解决此问题:

lmfun <- function(data, y, x) {
  y <- enquo(y)
  x <- enquo(x)

  model_formula <- formula(paste0(quo_name(y), "~", quo_name(x)))
  lm(model_formula, data = data)
}

lmfun(mtcars, mpg, disp)

# Call:
#   lm(formula = model_formula, data = data)
# 
# Coefficients:
#   (Intercept)         disp  
#      29.59985     -0.04122  

2
这里还有另一个选项: 编辑: 这是一份重构后的答案。
lmfun<-function(data,yname,xname){
 formula1<-as.formula(paste(yname,"~",xname))
  lm.fit<-do.call("lm",list(data=quote(data),formula1))
  lm.fit
}
lmfun(mtcars,"mpg","disp")

And the Original Answer:

 lmfun<-function(data,y,x){
      formula1<-as.formula(y~x)
      lm.fit<-do.call("lm",list(data=quote(data),formula1))
      lm.fit
    }
lmfun(mtcars,mtcars$mpg,mtcars$disp)

产生:

Call:
lm(formula = y ~ x, data = data)

Coefficients:
(Intercept)            x  
   29.59985     -0.04122  

2

如果参数没有加引号,那么在将quosure变成字符串(quo_name)后,转换为符号(sym),并在lm中评估表达式(类似于OP使用lm的语法)。

library(rlang)
lmfun <- function(data, y, x) {
  y <- sym(quo_name(enquo(y)))
  x <- sym(quo_name(enquo(x)))
  expr1 <- expr(!! y ~ !! x)

  model <- lm(expr1, data = data)
  model$call$formula <- expr1 # change the call formula
  model
}

lmfun(mtcars, mpg, disp)
#Call:
#lm(formula = mpg ~ disp, data = data)

#Coefficients:
#(Intercept)         disp  
#   29.59985     -0.04122  

如果我们传递的是字符串,可以使用ensym将其转换为符号,然后在lm中引用它。
lmfun <- function(data, y, x) {
  y <- ensym(y)
  x <- ensym(x)
  expr1 <- expr(!! y ~ !! x)

  model <- lm(expr1, data = data)
  model$call$formula <- expr1 # change the call formula
  model

}

lmfun(mtcars, 'mpg', 'disp')
#Call:
#lm(formula = mpg ~ disp, data = data)


#Coefficients:
#(Intercept)         disp  
#   29.59985     -0.04122  

注意:这两个选项都来自于 tidyverse

2

另一种解决方案:

lmf2 <- function(data,y,x){
  fml <- substitute(y~x, list(y=substitute(y), x=substitute(x)))
  lm(eval(fml), data)
}

lmf2(mtcars, mpg, disp)
# Call:
# lm(formula = eval(fml), data = data)
# 
# Coefficients:
# (Intercept)         disp  
#    29.59985     -0.04122  

或者,等价于:
lmf3 <- function(data,y,x){
  lm(eval(call("~", substitute(y), substitute(x))), data)
}

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