我想编写一个自定义函数的包装器,它将一些向量作为输入(如:mtcars$hp
,mtcars$am
等)以输入作为数据框名称(如{{1} }参数,例如:data
)和变量名称(如:mtcars
和hp
),与大多数标准函数一样。
但是我遇到了一些问题,我提出的'demo'功能(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
和其他人进行一些实验,但没有取得任何成功。任何暗示都会受到欢迎!
答案 0 :(得分:10)
这是拼图的关键部分:
f <- function(x,data=NULL) {
eval(match.call()$x,data) # this is mtcars$hp, so just take the mean of it or whatever
}
> f(hp,mtcars)
[1] 110 110 93 110 175 105 245 62 95 123 123 180 180 180 205 215 230 66 52 65 97 150 150 245 175 66
[27] 91 113 264 175 335 109
# it even works without a data.frame specified:
> f(seq(10))
[1] 1 2 3 4 5 6 7 8 9 10
请参阅@Andrie与@Hadley文档的链接,了解其工作原理。请参阅@ Hadley的注释,注意一个重要的警告:f()不能从另一个函数内部运行。
基本上R使用惰性评估(例如,在实际使用之前它不会对事物进行评估)。所以你可以通过传递它hp
,因为它仍然是一个未经评估的符号,直到它出现在某个地方。由于match.call
将它作为一个符号并等待评估它,一切都很好。
然后eval
在指定的环境中对其进行评估。根据{{1}},第二个参数代表:
要评估expr的环境。也可能是NULL,a 列表,数据框,pairlist或sys.call指定的整数。
因此,无论是NULL(如果你没有传递data.frame)还是data.frame,你的状态都很好。
延迟评估的证明是这不会返回错误(因为x从未在函数中使用过):
?eval
答案 1 :(得分:3)
f <- function(x, data=NULL) {
if (!missing(data)) { colname=deparse(substitute(x))
mean(data[[colname]])
} else {
mean(x)
}
}
f(hp, mtcars)
[1] 146.6875
(不可否认,它不像@ gsk那样紧凑,我想我会试着记住他的方法而不是我的。感谢Josh O'Brien指出了一个现在已修复的错误。)
答案 2 :(得分:-1)
试试这个:
f <- function(x, data = NULL) {
if (is.null(data)) {
mean(x)
} else {
attach(data)
mean(x)
detach(data)
}
}
同样在您的示例中,您输入数据集而不是列。 你的例子应该是f(hp,mtcars)