8

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

lmfun <- function(data, y, x) {
  lm(y ~ x, data = data)
}

该函数显然不起作用,因为 lm 函数无法将 y 和 x 识别为数据集的变量。

我做了一些研究,偶然发现了以下有用的小插曲:用 dplyr 编程。小插图为我面临的类似问题提供了以下解决方案:

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”,没有默认值

任何人都知道如何修改代码以使其工作?

谢谢,

约斯特。

4

4 回答 4

5

您可以使用quo_name's 和解决此问题formula

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  
于 2019-01-06T11:31:53.400 回答
2

如果参数未加引号,则sym在将 quosure 更改为字符串 () 后转换为符号 ( quo_name) 并计算表达式 in 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然后将quote其转换为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

于 2019-01-06T11:44:55.810 回答
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)
}
于 2019-01-06T11:45:36.143 回答
1

这是另一种选择: 编辑: 这是一个重构的答案

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")

和原来的答案:

 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  
于 2019-01-06T11:40:51.253 回答