Jor*_*eys 11 expression r dispatch s4
我试图说服一个S4方法使用一个表达式作为参数,但我总是得到一个错误返回.一个简单的例子,说明了我在这里尝试做的事情:
setGeneric('myfun',function(x,y)standardGeneric('myfun'))
setMethod('myfun',c('data.frame','expression'),
function(x,y) transform(x,y) )
Run Code Online (Sandbox Code Playgroud)
如果我现在尝试:
> myfun(iris,NewVar=Petal.Width*Petal.Length)
Error in myfun(iris, NewVar = Petal.Width * Petal.Length) :
unused argument(s) (NewVar = Petal.Width * Petal.Length)
> myfun(iris,{NewVar=Petal.Width*Petal.Length})
Error in myfun(iris, list(NewVar = Petal.Width * Petal.Length)) :
error in evaluating the argument 'y' in selecting a method for
function 'myfun': Error: object 'Petal.Width' not found
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话,似乎参数已经在通用中进行了评估.所以将表达式传递给方法似乎至少是棘手的.是否有可能使用表达式的S4调度方法?
编辑:改为变换,因为它是一个更好的例子.
您已在此示例方法中指定“表达式”作为第二个参数的类。第一个示例返回错误,因为
NewVar=Petal.Width*Petal.Length
Run Code Online (Sandbox Code Playgroud)
被解释为 myfun 的命名参数,其值为
Petal.Width*Petal.Length
Run Code Online (Sandbox Code Playgroud)
它没有机会被评估,因为 NewVar 不是此方法或泛型的参数。
在第二个示例中,我不确定闭合大括号发生了什么,因为我的错误与所示的错误不同:
myfun 中出错(iris,{:在为函数“myfun”选择方法时评估参数“y”时出错:错误:未找到对象“Petal.Width”
但是,当我强制您的表达式成为表达式对象时,我没有收到任何错误并获取 iris data.frame 作为输出:
myfun(iris, expression(NewVar=Petal.Width*Petal.Length))
Run Code Online (Sandbox Code Playgroud)
我认为这只能部分回答您的问题,因为简单地返回 iris data.frame 并不是您想要的。Transform() 未正确评估表达式。我怀疑您希望输出与以下硬编码版本的输出完全匹配:
transform(iris, NewVar=Petal.Width*Petal.Length)
Run Code Online (Sandbox Code Playgroud)
这是一个使用 eval 评估表达式的简短示例
z <- expression(NewVar = Petal.Width*Petal.Length)
test <- eval(z, iris)
head(test, 2)
Run Code Online (Sandbox Code Playgroud)
[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)
Run Code Online (Sandbox Code Playgroud)
[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
Run Code Online (Sandbox Code Playgroud)
同样,此实现本质上是硬编码的,将一个且仅一个变量列添加到输入 data.frame,尽管该变量列的名称和表达式是任意的,并且作为表达式提供。我确信有一个更好、更通用的答案,它可以评估 y 中保存的表达式,就好像它是 Transform() 函数中的直接调用一样,但我目前很难使用什么作为适当的“逆” “函数到表达式()。
如果您实际上不想在 y 上调度,则始终有标准 ... :
setGeneric('myfun', function(x, ...) standardGeneric('myfun'))
setMethod('myfun', 'data.frame', function(x, ...){
transform(x, ...)
})
Run Code Online (Sandbox Code Playgroud)
这效果很好。但你的问题是关于实际调度表达式对象。
以下行不通,但我认为已经越来越接近了。也许有人可以介入并进行一些最后的调整:
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)
Run Code Online (Sandbox Code Playgroud)
[1]“萼片长度”“萼片宽度”“花瓣长度”“花瓣宽度”“种类”
本质上,当我们调用 myfun() 时,表达式的“NewVar=”部分并未传递给 Transform()。
经过多次尝试和错误,我找到了一种真正有效的方法。首先使用 as.list() 将表达式对象转换为列表,然后使用奇妙的函数构建您想要的调用
do.call()
Run Code Online (Sandbox Code Playgroud)
完整的示例如下所示:
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"
Run Code Online (Sandbox Code Playgroud)
新的 data.frame 对象“test”具有我们想要的“NewVar”列。
| 归档时间: |
|
| 查看次数: |
1179 次 |
| 最近记录: |