函数内部使用“With”(包装器)
我想围绕自定义函数编写一个包装器,该函数将一些向量作为输入(例如:mtcars$hp
、mtcars$am
等)以将输入作为数据帧名称(作为 data
参数,例如:mtcars
)和变量名称(例如:hp
和 am
),像大多数标准功能一样。
但我有一些问题,我提出的“演示”函数(围绕 mean
的包装器不起作用。
代码:
f <- function(x, data=NULL) {
if (!missing(data)) {
with(data, mean(x))
} else {
mean(x)
}
}
针对向量运行当然可以工作:
> f(mtcars$hp)
[1] 146.69
但不幸的是 with
失败了:
> f(hp, mtcars)
Error in with(d, mean(x)) : object 'hp' not found
在全局环境中/没有我的自定义函数时可以正常工作:
> with(mtcars, mean(hp))
[1] 146.69
我尝试使用 substitute
、deparse
等进行一些实验,但没有任何成功,欢迎任何提示。 !
I would like to write a wrapper around a custom function that takes some vectors as input (like: mtcars$hp
, mtcars$am
etc.) to take input as data frame name (as data
parameter, eg.: mtcars
) and variable names (like: hp
and am
), as usual in most standard function.
But I have some problems, my proposed 'demo' function (a wrapper around mean
does not work.
Code:
f <- function(x, data=NULL) {
if (!missing(data)) {
with(data, mean(x))
} else {
mean(x)
}
}
Running against a vector works of course:
> f(mtcars$hp)
[1] 146.69
But with
fails unfortunatelly:
> f(hp, mtcars)
Error in with(d, mean(x)) : object 'hp' not found
While in global environment/without my custom function works right:
> with(mtcars, mean(hp))
[1] 146.69
I have tried to do some experiment with substitute
, deparse
and others, but without any success. Any hint would be welcomed!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是难题的关键部分:
请参阅 @Andrie 指向 @Hadley 文档的链接,了解其工作原理的解释。请参阅 @Hadley 的注释以了解重要警告: f() 无法从另一个函数内部运行。
基本上,R 使用惰性求值(例如,在实际使用事物之前它不会求值)。因此,您可以通过传递它
hp
来避免这种情况,因为在它出现在某个地方之前,它仍然是一个未计算的符号。由于match.call
将其作为符号获取并等待对其求值,所以一切都很好。然后
eval
在指定的环境中对其进行评估。根据?eval
,第二个参数表示:因此,无论是 NULL (如果您没有传递 data.frame)还是 data.frame,您都处于良好状态。
惰性求值的证明是,这不会返回错误(因为函数中从未使用 x):
Here's the key piece of the puzzle:
See @Andrie's link to @Hadley's document for an explanation of why it works. See @Hadley's note for a critical caveat: f() cannot be run from inside another function.
Basically R uses lazy evaluation (e.g. it doesn't evaluate things until they're actually used). So you can get away with passing it
hp
because it remains an unevaluated symbol until it appears somewhere. Sincematch.call
grabs it as a symbol and waits to evaluate it, all is well.Then
eval
evaluates it in the specified environment. According to?eval
, the second argument represents:Therefore you're in good shape with either NULL (if you're not passing a data.frame) or a data.frame.
Proof of lazy evaluation is that this doesn't return an error (since x is never used in the function):
(诚然,不像 @gsk 那样紧凑,我想我会尝试记住他的方法而不是我的方法。感谢 Josh O'Brien 指出了一个现已修复的错误。)
(Admittedly not as compact as @gsk's and I think I will try to remember his method over mine. And thanks to Josh O'Brien for pointing out an error that's now been fixed.)
试试这个:
同样在您的示例中,您输入数据集而不是列。
你的例子应该是 f(hp, mtcars)
try this:
Also in your example you enter the data set instead of the column.
Your example should be f(hp, mtcars)