【问题标题】:Use function arguments in lm formula within function environment在函数环境中使用 lm 公式中的函数参数
【发布时间】:2019-03-22 05:47:14
【问题描述】:

考虑以下函数:

lm_eqn <- function(df, indep, dep){
  
  lm(formula = dep ~ indep, data = df)
}

lm_eqn(iris, Sepal.Length, Sepal.Width)  ## does not work, throws error. 

我尝试以多种方式引用/取消引用。这些都没有成功,抛出不同的错误,而且对我没有任何帮助:

使用deparse(substitute(dep))

contrasts&lt;-(*tmp*, value = contr.funs[1 + isOF[nn]]) 中的错误: 对比只能应用于具有 2 个或更多级别的因素

使用quo(dep)enquo(dep)expr(dep)

model.frame.default(formula = dep ~ indep, data = df, drop.unused.levels = TRUE) 中的错误:对象不是矩阵

在上面使用 !! 取消引用:

!dep 中的错误:参数类型无效

在函数体内为公式指定变量名有效:

lm_eqn2 <- function(df){
  
     lm(formula = Sepal.Length ~ Sepal.Width, data = df)
}

lm_eqn2(iris)

# Call:
# lm(formula = Sepal.Length ~ Sepal.Width, data = df)

# Coefficients:
# (Intercept)  Sepal.Width  
#     6.5262      -0.2234 

我错过了什么?

【问题讨论】:

    标签: r


    【解决方案1】:

    你可以引用输入,然后在函数内部使用eval(as.name())

    lm_eqn <- function(df, indep, dep){
    
      lm(formula = eval(as.name(dep)) ~ eval(as.name(indep)), data = df)
    }
    
    lm_eqn(iris, 'Sepal.Length', 'Sepal.Width')
    

    【讨论】:

    • 这看起来很不错。我在路上,很快就会去看看。已经非常感谢了
    【解决方案2】:

    您可以同时使用带引号和不带引号的列名以及从函数library 获取的以下substitute 技巧,它也接受两者。

    lm_eqn <- function(df, indep, dep){
      indep <- as.character(substitute(indep))
      dep <- as.character(substitute(dep))
      fmla <- as.formula(paste(dep, indep, sep = "~"))
      lm(fmla, data = df)
    }
    
    lm_eqn(iris, 'Sepal.Length', 'Sepal.Width')
    #
    #Call:
    #lm(formula = fmla, data = df)
    #
    #Coefficients:
    # (Intercept)  Sepal.Length  
    #     3.41895      -0.06188  
    #
    
    lm_eqn(iris, Sepal.Length, Sepal.Width)
    #
    #Call:
    #lm(formula = fmla, data = df)
    #
    #Coefficients:
    # (Intercept)  Sepal.Length  
    #     3.41895      -0.06188  
    #
    

    【讨论】:

    • 谢谢!这是一个巧妙的技巧!不过,我会接受@bobbel 的回答,因为他们回答得更早,而且代表也更少
    【解决方案3】:

    不带引号的方法:

    > lm_eqn(iris, Sepal.Length, Sepal.Width)
    
    Call:
    lm(formula = dep ~ indep, data = df_lm)
    
    Coefficients:
    (Intercept)        indep  
        3.41895     -0.06188  
    

    警告:传递不带引号的对象名称在视觉上令人愉悦,但通常不受欢迎,因为它可能引入不稳定。

    代码

    lm_eqn <- function(df_lm, indep, dep){
        df_lm <- eval(as.name(deparse(substitute(df_lm))))
        indep <- df_lm[, grep(deparse(substitute(indep)), colnames(df_lm))]
        dep <- df_lm[, grep(deparse(substitute(dep)), colnames(df_lm))]
    
        lm(formula = dep ~ indep, data = df_lm)
    }
    

    【讨论】:

    • 感谢您的想法,也很有趣。我承认我更喜欢其他解决方案;)
    【解决方案4】:

    如果您想让输出中的公式保持漂亮,您可以在整个调用中调用 substitute,这将插入变量名称,然后在结果上调用 eval 以运行它:

    lm_eqn <- function(data, x, y){
        eval(substitute(
            lm(formula = y ~ x, data = data)
        ))
    }
    
    lm_eqn(iris, Sepal.Width, Sepal.Length)
    #> 
    #> Call:
    #> lm(formula = Sepal.Length ~ Sepal.Width, data = iris)    # <- pretty!
    #> 
    #> Coefficients:
    #> (Intercept)  Sepal.Width  
    #>      6.5262      -0.2234
    

    或者让这一切变得非常简单(并且更加灵活),只需直接传递一个公式:

    lm_frm <- function(data, formula){
        lm(formula, data)
    }
    
    lm_frm(iris, Sepal.Length ~ Sepal.Width)
    #> 
    #> Call:
    #> lm(formula = formula, data = data)
    #> 
    #> Coefficients:
    #> (Intercept)  Sepal.Width  
    #>      6.5262      -0.2234
    

    lm 调用包装在eval(substitute(...)) 中也将使用这种方法修复存储的调用结构。

    【讨论】:

      猜你喜欢
      • 2021-02-09
      • 2020-03-04
      • 1970-01-01
      • 2019-08-24
      • 2016-01-27
      • 2019-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多