2011-06-23 85 views
8

我一直無法理解關於如何調用S3方法的文檔,並且這一次它讓我感到困擾。S3和類的順序

我會先問一個以上的問題,但他們都密切相關。在一組複雜功能的核心中,我創建了很多適合的東西,尤其是後勤部分。現在,glmnet文檔指定其返回值具有「glmnet」和(邏輯迴歸)「lognet」兩個類。實際上,這些按照這個順序指定。

然而,看着glmnet的執行結束後,調用(內部功能)lognet,該套fit後級點對點到「lognet」,我看這行代碼就在返回之前(變量fit)的:

class(fit) = c(class(fit), "glmnet") 

從此,我就得出這樣的結論類的順序,其實是「lognet」,「glmnet」。

不幸的是,我有合適的,只好(如DOC建議):

> class(myfit) 
[1] "glmnet" "lognet" 

與此問題的方式是S3方法分派它,特別是predict。這裏的代碼爲predict.lognet

function (object, newx, s = NULL, type = c("link", "response", 
    "coefficients", "class", "nonzero"), exact = FALSE, offset, 
    ...) 
{ 
    type = match.arg(type) 
    nfit = NextMethod("predict") #<- supposed to call predict.glmnet, I think 
    switch(type, response = { 
     pp = exp(-nfit) 
     1/(1 + pp) 
    }, class = ifelse(nfit > 0, 2, 1), nfit) 
} 

我已經添加了一條評論來解釋我的推理。現在,當我打電話預測這個myfit一個新的數據矩陣mydatatype="response",像這樣:

predict(myfit, newx=mydata, type="response") 

,我不這樣做,因爲每個文檔,得到的預測概率,但線性組合,這是完全立即致電predict.glmnet的結果。

我試圖扭轉類的順序,像這樣:

orgclass<-class(myfit) 
class(myfit)<-rev(orgclass) 

,然後做的預測再打電話:你瞧:它的作品!我得到概率。

所以,來到這裏的一些問題:

  1. 我說得對在「已經瞭解到」那 S3方法是爲了類的外觀 出動?
  2. 我說得對在假設 glmnet的代碼會導致爲 predict正確調度順序錯誤 ?
  3. 在我的代碼中沒有任何東西 明確/明顯地操縱我的知識類 。 有什麼可能導致訂單變更爲 ?

爲了完整性:這裏的一些示例代碼一起玩(因爲我現在在做我自己):

library(glmnet) 
y<-factor(sample(2, 100, replace=TRUE)) 
xs<-matrix(runif(100), ncol=1) 
colnames(xs)<-"x" 
myfit<-glmnet(xs, y, family="binomial") 
mydata<-matrix(runif(10), ncol=1) 
colnames(mydata)<-"x" 
class(myfit) 
predict(myfit, newx=mydata, type="response") 
class(myfit)<-rev(class(myfit)) 
class(myfit) 
predict(myfit, newx=mydata, type="response") 
class(myfit)<-rev(class(myfit))#set it back 
class(myfit) 

根據生成的數據,不同的是多了還是不太明顯(在我的真實數據集中,我注意到了所謂概率中的負值,這是我如何挑選問題的方法),但是您的確應該看到差異。

感謝您的任何意見。

編輯

我剛剛發現了可怕的真相:無論是爲了在glmnet 1.5.2(這是目前在那裏我遇到了實際的代碼,導致配合帶班順序在服務器上工作反過來),但是來自1.6的代碼要求命令是「lognet」,「glmnet」。我還沒有檢查1.7中會發生什麼。

感謝@Aaron提醒我關於信息學的基礎知識(除了'如果一切都失敗了,重新啓動':'檢查你的版本')。我錯誤地認爲統計學習之神的一攬子計劃將免受這種類型的錯誤的影響),以及@Gavin確認我重構S3的工作原理。

+2

當我運行你的代碼時,我在第一個'class'調用之後得到了命令'「lognet」「glmnet」'',這是從你說你得到的東西倒退。我有glmnet 1.7;你有什麼版本? – Aaron

回答

6

是的,調度的順序是按類中列出的順序排列的。在簡單的日常情況下,是的,第一個聲明的類是通過方法調度首先選擇的類,並且只有當它找不到該類的方法(或稱爲NextMethod)時纔會轉到第二類或者未能搜索到default方法。

不,我不認爲你是正確的,類的順序是錯誤的代碼。文檔顯示錯誤。其意圖很明顯是首先調用predict.lognet(),使用主力predict.glmnet()glmnet擬合的所有類型的套索/彈性網模型進行基本計算,最後對這些一般預測進行一些後處理。那predict.glmnet()不是導出從glmnet NAMESPACE,而其他方法也許也是告訴。

我不知道爲什麼你認爲的輸出從這樣的:

predict(myfit, newx=mydata, type="response") 

是錯的?我得到了一個10行21列的矩陣,其中列僅與截距模型預測相加,並且預測了20個拉姆達值,其中沿着套索/彈性網路徑的模型係數已經被計算。這些似乎不是線性組合,並且是您請求的響應比例。

類的順序不變。我認爲你誤解了代碼應該如何工作。文檔中有一個錯誤,因爲在那裏的順序是錯誤的。但是代碼正在運行,我認爲它應該。

+0

很好的答案,但一個小小的問題:你不能在方法調度期間改變類:https://gist.github.com/1043952(你可以,它只是不影響調度) – hadley

+0

另外,它看起來似乎意圖是'predict.lognet'然後'predict.glmnet'。但是當我讀到它時,OP說它在他的系統上首先運行'predict.glmnet',因爲這些類的順序是相反的。 – Aaron

+0

@hadley感謝您指出這一點。我一定誤解了這一點。現在修復。 –