gpt4 book ai didi

r - 使用表达式作为参数调度 S4 方法

转载 作者:行者123 更新时间:2023-12-04 02:25:27 24 4
gpt4 key购买 nike

我试图说服 S4 方法使用表达式作为参数,但总是返回错误。一个简单的例子说明了我在这里尝试做的事情:

setGeneric('myfun',function(x,y)standardGeneric('myfun'))

setMethod('myfun',c('data.frame','expression'),
function(x,y) transform(x,y) )

如果我现在尝试:
> 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

如果我理解正确的话,似乎这些论点已经在泛型中进行了评估。因此,将表达式向下传递给方法似乎至少很棘手。是否有可能使用表达式使用 S4 调度方法?

编辑:更改为转换,因为它是一个更好的例子。

最佳答案

在此示例方法中,您已将“表达式”指定为第二个参数的类。第一个示例返回错误,因为

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”列。

关于r - 使用表达式作为参数调度 S4 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6999767/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com