如果您只是引用列表中的某个项目,例如数据框中的一列,然后d$x1
and with(d, x1)
都会返回x1
from d
。然而,后者本身是相当不寻常的,这并不是真正的预期目的with()
;从列表中提取一个值是什么$
is for.
使用的优点with()
是评估表达式在单个环境的上下文中,无需担心全局变量或附加数据框使变量引用不明确。
The $
语法不支持表达式,因此要执行涉及数据框中多个变量的计算,您需要使用d$x1
, d$x2
等等,很不方便。但如果只是从列表中提取一个项目,$
是优选的。
两种方法不相同的一个值得注意的情况如下。认为d
定义为
d <- data.frame(x1=c(1, 2, 3))
现在定义y <- "x1"
。当我们尝试引用时会发生什么x1
using y
?
> d$y
NULL
> with(d, y)
[1] "x1"
> d[, y]
[1] 1 2 3
d$y
回报NULL
因为没有专栏y
in d
,所以没有什么可提取的。
由于没有专栏y
in d
, with(d, y)
寻找y
在父框架中d
,在本例中是全局环境。所以这评估y
在全球环境中,从而返回"x1"
。尽管没有什么可提取的,is需要评估的东西,因为y
does存在,只是不存在于d
.
Now d[, y]
得到我们想要的。这首先评估y
,这将变成d[, "x1"]
,这是提取的正确语法x1
from d
使用另一个变量。
一些更详细的细节由 David Arenburg 提供:
注意with()
实际上是执行方法分派的通用函数,而$
是一个原始的。的检查base:::with.default
很有启发性:
function(data, expr, ...)
eval(substitute(expr), data, enclos = parent.frame())
这可以证实with()
is for 评估.
Since $
是一个原语,它调用.Primitive("$")
,这意味着它调用已编译的内部代码中的入口点。进行一些狩猎表明$
转到一个名为的入口点do_subset3
在子集.c中。该 C 代码之前的注释同样具有启发性:
/* The $ subset operator.
We need to be sure to only evaluate the first argument.
The second will be a symbol that needs to be matched, not evaluated.
*/
这可以证实$
is for 萃取,不评价。
简而言之,正如大卫在评论中所说的那样,with()
and $
具有不同的目的,在某些情况下这些目的可能会重叠。