R公式相对于约束环境的行为

时间:2015-01-25 22:56:18

标签: r

我想知道R如何将环境与公式联系起来的一些细节,以及在不同情况下所述环境需要什么,特别是关于〜是否开启的公式中没有包含。

让我们说我有两个像字符串一样的公式,通常会以编程方式创建,但为了简单起见,我将只定义为文字:

$ formula_str_no_tilde <- "a + b"
$ formula_str_with_tilde <- "~ a + b"

我打算使用这些来从包含a和b列的数据框进一步创建模型矩阵。为此,我想将类似公式的字符串转换为合法的公式。这里有一些非常奇怪的不同行为:

$ formula_no_tilde <- as.formula(formula_str_no_tilde)
> Error in eval(expr, envir, enclos) : object 'a' not found

,同时:

$ formula_with_tilde <- as.formula(formula_str_with_tilde)
no error

检查as.formula的文档,有一个env参数用于将环境绑定到公式。这个论点默认绑定了全局环境,这使得我们对错误信息有了一定的了解,因为我们还没有得到一个&#39; a&#39;在我们的全球环境中。它确实接受了第二次调用as.formula的神秘感,因为我们处于相同的情况......

由于全球环境受到约束,人们可能会怀疑可能整个冒险都被误导了,我们将无法使用我们的formula_with_tilde来制作模型矩阵,因为全球环境已经存在界。尽管如此:

$ D <- data.frame('a'=c(1, 2, 3), 'b'=c(-1, 0, 1))
$ model.matrix(formula_with_tilde, D)

按照你天真的希望工作。可能这是model.matrix的一个特性,它为你重新环境......

所以这是我的问题:

  • R中没有波形的公式是非法的吗?是否存在有意义的情况?
  • 为什么不包括波形符会抛出环境查找错误,而包含它却没有?
  • model.matrix重新绑定与公式关联的环境吗?

并且为了完整性:

  • 以编程方式生成和操作公式是否有更好的专业开始?

1 个答案:

答案 0 :(得分:3)

如果你想要一个未评估的调用对象(这是波形符操作符返回的那种R语言对象),那么你可以使用call

 call( '+',quote(a),quote(b))
 #a + b

您需要阻止解释器的默认操作,通过围绕quote来评估第二个和第三个参数。您可以将结果用作`eval的合法第一个参数,并使用数据框作为环境:

dat <- data.frame(a=1:10,b=1:10)
eval( call( '+',quote(a),quote(b)), dat)
# [1]  2  4  6  8 10 12 14 16 18 20

问题的答案&#34;是公式的代价部分&#34;:可能,是的,如果我们要相信这一点:

 (~a)[[1]]
#`~`

并从字符串&#34; a + b&#34;中构建功能结果。这将是一种方式:

 as.call( parse(text="a+b") )
#(a + b)()

&#34; model.matrix重新绑定与公式关联的环境?&#34;

嗯,不完全是这样,至少我理解这个问题。 model.matrix从model.frame中提取值,这是一个增强的数据帧,但它的属性列表中没有附加的环境。

看一些这些语言对象的属性很有意思:

> class(bquote(a+b))
[1] "call"
> identical( bquote(a+b), ~a+b)
[1] FALSE

> attributes( ~a+b)
$class
[1] "formula"

$.Environment
<environment: R_GlobalEnv>

> attributes( bquote(a+b))
NULL

Globalenv中的a = 1且b = 2,如上所述:

> eval(  (~a+b)[[2]], envir=dat)
 [1]  2  4  6  8 10 12 14 16 18 20
> 
> eval( (~a+b)[[2]] )
[1] 3

附录:康拉德的评论,其中指出eval的论点可以是公式调用或表达式中的任何一个,因此您不需要as.call,提示me furhter说明evalevalq可以用来产生反映上述差异的结果,只有表达式a + b:

> evalq( a+b, envir=dat)
 [1]  2  4  6  8 10 12 14 16 18 20
> eval( a+b, envir=dat)   # evaluated in current scope despite  envir=dat
[1] 3