R:使用作为对象传递的参数计算数据框中的表达式

Sim*_*onG 6 evaluation expression r object dataframe

我想编写一个函数来计算数据框中的表达式,但是使用可能包含也可能不包含用户定义对象的表达式来执行此操作.我认为这个神奇的词汇是"非标准的评价",但我还不能理解它.

一个简单的例子(对于我的目的来说还是现实的):说,我想评估lm()对数据框中找到的变量的调用.

mydf <- data.frame(x=1:10, y=1:10)
Run Code Online (Sandbox Code Playgroud)

这样做的函数可以写成如下:

f <- function(df, expr){
  expr <- substitute(expr)
  pf <- parent.frame()
  eval(expr, df, pf)
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以使用以下命令得到我想要的东西.

f(mydf, lm(y~x))

# Call:
# lm(formula = y ~ x)
# 
# Coefficients:
# (Intercept)            x  
#    1.12e-15     1.00e+00  
Run Code Online (Sandbox Code Playgroud)

尼斯.但是,有些情况下,在调用之前将模型方程式保存在对象中会更方便lm().不幸的是,上述功能不再适用.

fml <- y~x

f(mydf, lm(fml))
# Error in eval(expr, envir, enclos): object 'y' not found
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么第二次通话不起作用?如何改变功能,以便两个呼叫都能产生预期的结果?(期望=合身模型)

干杯!

Bro*_*ieG 5

来自?lm,重新data论证:

如果在数据中找不到,则变量取自环境(公式)

在第一种情况下,公式是在您的eval(expr, df, pf)调用中创建的,因此公式的环境是基于的环境df.在第二种情况下,公式是在全局环境中创建的,这就是它不起作用的原因.

因为公式有自己的环境,所以在NSE中处理它们会很棘手.

你可以尝试:

with(mydf,
  {
    print(lm(y~x))
    fml <- y~x
    print(lm(fml))
  }
)
Run Code Online (Sandbox Code Playgroud)

但这可能不适合你.如果没有检查捕获的参数中的任何名称是否解析为公式,并重新分配他们的环境,那么您将遇到一些麻烦. 更糟糕的是,重新分配环境是正确的做法并不一定是显而易见的.在许多情况下,您确实希望查看公式环境.

关于R Chat的这个问题有一个松散的相关讨论: