在此示例方法中,您已将“表达式”指定为第二个参数的类。第一个示例返回错误,因为
NewVar=Petal.Width*Petal.Length
被解释为具有值的 myfun 的命名参数
Petal.Width*Petal.Length
没有机会被评估,因为 NewVar 不是此方法或泛型的参数。
在第二个示例中,我不确定闭合花括号发生了什么,因为我的错误与显示的错误不同:
myfun 中的错误(iris,{:在为函数“myfun”选择方法时评估参数“y”时出错:错误:找不到对象“Petal.Width”
但是,当我强制您的表达式成为表达式对象时,我没有收到错误并将 iris data.frame 作为输出:
myfun(iris, expression(NewVar=Petal.Width*Petal.Length))
我认为这只是部分回答了您的问题,因为简单地返回 iris data.frame 不是您想要的。transform() 未正确评估表达式。我怀疑您希望输出与以下硬编码版本的输出完全匹配:
transform(iris, NewVar=Petal.Width*Petal.Length)
这是一个使用 eval 评估表达式的简短示例
z <- expression(NewVar = Petal.Width*Petal.Length)
test <- eval(z, iris)
head(test, 2)
[1] 0.28 0.28
这是一个适用于向 data.frame 添加一个变量列的版本:
setGeneric('myfun',function(x,y)standardGeneric('myfun'))
setMethod('myfun',c('data.frame','expression'), function(x,y){
etext <- paste("transform(x, ", names(y), "=", as.character(y), ")", sep="")
eval(parse(text=etext))
})
## now try it.
test <- myfun(iris, expression(NewVar=Petal.Width*Petal.Length))
names(test)
[1] "花萼长度" "花萼宽度" "花瓣长度" "花瓣宽度" "物种" "NewVar"
head(test)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species NewVar
1 5.1 3.5 1.4 0.2 setosa 0.28
2 4.9 3.0 1.4 0.2 setosa 0.28
同样,这个实现基本上硬编码了一个,并且只有一个变量列将添加到输入 data.frame,尽管该变量列的名称和表达式是任意的,并且作为表达式提供。我确信有一个更好、更通用的答案可以评估 y 中保存的表达式,就好像它是 transform() 函数中的直接调用一样,但我现在很难过使用什么作为适当的“逆” " 函数到表达式()。
总是有标准 ... ,如果您实际上不想在 y 上发送:
setGeneric('myfun', function(x, ...) standardGeneric('myfun'))
setMethod('myfun', 'data.frame', function(x, ...){
transform(x, ...)
})
这很好用。但是您的问题是关于实际调度表达式对象。
以下不起作用,但我认为它越来越接近。也许有人可以加入并进行一些最后的调整:
setGeneric('myfun', function(x, y) standardGeneric('myfun'))
setMethod('myfun',c('data.frame', 'expression'), function(x, y){
transform(x, eval(y, x, parent.frame()))
})
## try out the new method
z <- expression(NewVar = Petal.Width*Petal.Length)
test <- myfun(iris, z)
names(test)
[1] "花萼长度" "花萼宽度" "花瓣长度" "花瓣宽度" "物种"
本质上,当我们调用 myfun() 时,表达式的 "NewVar=" 部分并没有传递给 transform()。
经过多次反复试验,我找到了一种真正可行的方法。首先使用 as.list() 将表达式对象转换为列表,然后使用 marvelous 构建您想要的调用
do.call()
完整的示例如下所示:
setGeneric('myfun', function(x, y) standardGeneric('myfun'))
setMethod('myfun',c('data.frame', 'expression'), function(x, y){
do.call("transform", c(list(x), as.list(y)))
})
# try out the new method
z <- expression(NewVar = Petal.Width*Petal.Length)
test <- myfun(iris, z)
names(test)
[1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
[6] "NewVar"
新的 data.frame 对象“test”有我们想要的“NewVar”列。