2011-08-09 35 views
11

我試圖說服S4方法使用表達式作爲參數,但我總是得到一個返回錯誤。使用表達式作爲參數調度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調度方法使用表達式?


編輯:改爲轉換,因爲它是一個更好的例子。

+1

請參閱SfDA的第399-402頁,其中Chambers描述了爲什麼要評估經過簽名測試的參數_must_。 –

+0

@DWin:小心分享鏈接? sfDA聽起來對我來說並不熟悉,我想你不是在談論國家食品和藥物管理局... –

+0

對不起。 John Chambers的「數據分析軟件」。作爲附加的一點,我注意到你的簽名值與參數名稱沒有關聯,而在這個例子中是格式。 (注意:在問題體中你還沒有變成'transform')。 –

回答

2

您已經在此示例方法中將「expression」指定爲第二個參數的類。因爲

NewVar=Petal.Width*Petal.Length 

被解釋爲一個命名參數值爲

Petal.Width*Petal.Length 

不會得到機會進行評估,以myfun第一個例子返回一個錯誤,因爲NewVar不是爭論對於這種方法或通用。

在第二個例子,我不知道是怎麼回事與封閉大括號,因爲我的錯誤與圖示不同:

錯誤myfun(光圈,{: 錯誤評估參數'y'爲函數'myfun'選擇方法:錯誤:找不到對象'Petal.Width'

但是,當我強制將表達式設置爲表達對象:

myfun(iris, expression(NewVar=Petal.Width*Petal.Length)) 

我認爲這隻能部分回答你的問題,因爲平凡地返回虹膜數據幀不是你想要的。該表達式沒有被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

這是一個版本,用於向數據添加一個變量列。幀:

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] 「Sepal.Length」 「Sepal.Width」 「Petal.Length」 「Petal.Width」, 「物種」, 「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 

再次,這實現了本質上是硬編碼的,即只有一個變量列將被添加到輸入數據幀中,儘管該變量列和表達式的名稱是任意的,並且作爲表達式提供。我敢肯定,有一個更好的,更一般的答案,可以評估y中的表達式,就好像它是transform()函數中的直接調用一樣,但我目前難以用什麼作爲適當的「inverse 「函數表達式()。

總是有標準......,如果你不真正想派遣的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] 「Sepal.Length」 「Sepal.Width」 「Petal.Length」 「Petal.Width」, 「物種」

從本質上講,當我們調用myfun()時,表達式的「NewVar =」部分沒有傳遞給transform()。

經過多次試驗和錯誤之後,我想出了一種適用於真實的方法。首先表達對象轉換成與as.list()的列表,從而建立要與奇妙

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

+1

當你有嵌套函數時,eval會帶來一整套新問題。環境......我知道我可以對它進行硬編碼,但重要的是要有轉換的靈活性,但對於我自己的S4對象。我使用S3方法解決了這個問題,但是我對屏幕背後發生的事情特別感興趣...... –

+1

是的,我在eval中發現了同樣的問題。我認爲我附加的do.call方法可能適用於您的問題。 –

+1

我可以找到的最佳解決方法,所以你去了。 –

1

它不是S4或參數評估,它不能告訴R是否意味着要傳遞一個命名參數,或者如果您的表達式的格式爲a = b。

如果您查看「內部」的幫助,它會使用大括號來確保將表達式解析爲表達式。

我也想呼籲內內的功能不會做的函數的調用者更換...

我還以爲我不知道足夠的表達式。

+0

僅僅因爲'expr'是多行表達式意義上的多行表達式而不是大括號?如果您提供單個R表達式,則您不需要'within()'中的大括號。 –

+0

關於命名參數或表達式的觀點很有意思。這是一個時間,作爲任務的'='和'< - '的不平等是在屁股裏咬@Joris嗎? IIRC你必須在'()'內使用'<-',因爲'='不能在那裏工作。 –

+0

試一試:它不起作用。同樣使用'<-'。 –

相關問題