使用 "data" 和 "formula" 关键字参数时为什么顺序很重要?

13

R 中,绘图时为什么 dataformula 的关键字顺序很重要?我以为使用 命名参数 时顺序不重要...

以下是一个例子:

library(MASS)
data(menarche)

# Correct formulation (apparently):
plot(formula=Menarche/Total ~ Age, data=menarche)

# In contrast, note how the following returns an error:
plot(data=menarche, formula=Menarche/Total ~ Age)  

这只是plot函数的一个怪癖,还是其他函数也表现出这种行为?


5
graphics:::plot.default(data=menarche, formula=Menarche/Total ~ Age)graphics:::plot.formula(data=menarche, formula=Menarche/Total ~ Age) 的区别是什么? - rawr
3
“@rawr right; it is S3 dispatch working on the arguments and dispatching to different methods not the ordering that is causing the error. However, the first should be graphics:::plot.data.frame as traceback() shows it is this method that is actually being called.”翻译: @rawr对了,引起错误的不是顺序,而是S3分发(dispatch)在处理参数并将其分派到不同方法。然而,第一个应该是 graphics:::plot.data.frame,因为 traceback() 显示实际被调用的是这个方法。 - Gavin Simpson
1个回答

14

这与S3通用函数plot()的S3方法相关。 S3根据第一个参数调度方法,但确切的功能很复杂,因为formula被允许作为plot()的通常通用参数xy加上...的特殊例外:

> args(plot)
function (x, y, ...) 
NULL
因此,在第一种情况下发生的是,由于提供的第一个参数是公式,与plot.formula()的参数匹配,因此运行plot.formula()方法。
> args(graphics:::plot.formula)
function (formula, data = parent.frame(), ..., subset, ylab = varnames[response], 
    ask = dev.interactive()) 
NULL
例如:
> debugonce(graphics:::plot.formula)
> plot(formula=Menarche/Total ~ Age, data=menarche)
debugging in: plot.formula(formula = Menarche/Total ~ Age, data = menarche)
debug: {
    m <- match.call(expand.dots = FALSE)
[...omitted...]

当您调用 plot(data=menarche, formula=Menarche/Total ~ Age)时,第一个参数是数据框(data frame),因此会调用graphics:::plot.data.frame 方法:

> plot(data=menarche, formula=Menarche/Total ~ Age)
Error in is.data.frame(x) : argument "x" is missing, with no default
> traceback()
3: is.data.frame(x)
2: plot.data.frame(data = menarche, formula = Menarche/Total ~ Age)
1: plot(data = menarche, formula = Menarche/Total ~ Age)

但因为该方法需要一个参数x,而您没有提供,所以会收到关于缺少x的错误。

因此,在某种意义上,命名参数的顺序并不重要,也不应该重要,但当S3泛型参与时,方法调度首先会起作用,以决定将参数传递给哪个方法,然后提供的参数 - 而不是顺序 - 通常是容易出错的地方,特别是在混合使用formula方法和其他非formula方法时。


+1。我不知道你是如何能够如此迅速地完成所有这些工作的。事实上,这让我想知道我为什么要在一开始浪费那么多时间寻找答案。现在,请原谅我,我必须处理所有这些... - Steve S
1
@JoshO'Brien 它调用了 plot() -> plot.formula() -> plot.default();这似乎将 HERRINGS 解释为将 Total 传递给 x,将 Age 传递给 y,因此您会得到一个实际的图形,然后 HERRINGS 仍然作为公式保留在调用中,因此出现多个警告。要确切地了解发生了什么,我们必须研究 plot.formula 中的步骤,以查看它如何解释公式或仅从 data = menarche 中提取数据。 - Gavin Simpson
1
@GavinSimpson - 明白了,谢谢。在plot.formula()调用stats::model.frame.default时发生了问题,它在没有任何公式指导的情况下,只返回一个具有列"Age"、"Total"和"Menarche"的模型框架。(如果有公式参数指导,它将生成一个具有列"Menarche/Total"和"Age"的双列模型框架)。之后,在plot.formula()中提取模型框架mf的第一列,并将其传递给plot.default()y参数,将剩余的模型框架传递给x参数。 - Josh O'Brien
(记录一下,我曾经问过Gavin是否知道为什么调用plot(HERRINGS=Menarche/Total ~ Age, data=menarche)会给出这样的结果。) - Josh O'Brien
+1 @JoshO'Brien,考虑到变量被分配给xy的方式,我认为可能会发生这种情况,但是由于午餐非常吸引我,我没有机会自己检查它 :-) - Gavin Simpson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接