S3 メソッドがどのように呼び出されるかについてのドキュメントを理解するのにいつも苦労していましたが、今回はそれが私を悩ませています。
複数の質問をすることを前もってお詫びしますが、それらはすべて密接に関連しています。複雑な一連の関数の中心部で、私は多くのglmnet
フィット、特にロジスティック フィットを作成します。現在、glmnet
ドキュメントでは、その戻り値が "glmnet" と (ロジスティック回帰の場合) "lognet" の両方のクラスを持つように指定されています。実際、これらはこの順序で指定されます。
しかし、 の実装の最後を見ると、のクラスを「lognet」に設定glmnet
する (内部関数) の呼び出しの直後に、(変数の)リターンの直前に次のコード行が表示されます。lognet
fit
fit
class(fit) = c(class(fit), "glmnet")
このことから、クラスの順序は実際には「lognet」、「glmnet」であると結論付けます。
残念ながら、私が持っていたフィット感は(ドキュメントが示唆するように):
> 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
で、新しい datamatrixmydata
とを使用して predict を呼び出すとtype="response"
、次のようになります。
predict(myfit, newx=mydata, type="response")
、私は、ドキュメントに従って、予測された確率を取得しませんが、線形結合を取得します。これは、まさにpredict.glmnet
すぐに呼び出した結果です。
次のように、クラスの順序を逆にしてみました。
orgclass<-class(myfit)
class(myfit)<-rev(orgclass)
そして、もう一度予測呼び出しを実行します。見よ、うまくいきました! 確率はわかります。
それで、ここにいくつかの質問があります:
- S3メソッドはクラスの出現順にディスパッチされることを「学んだ」のは正しいですか?
- のコードが
glmnet
正しいディスパッチのために間違った順序を引き起こすと 仮定するのは正しいpredict
ですか? - 私のコードでは、私の知る限り、クラスを明示的に/目に見えるように操作するものは何もありません。順序が変更される原因は何ですか?
完全を期すために、ここにいくつかのサンプルコードを示します(私は今自分でやっているように):
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に感謝します(「他のすべてが失敗した場合は、再起動する」:「バージョンを確認する」以外に)。私は、統計学習の神々によるパッケージはこの種のエラーから保護されると誤って想定していました)、そして S3 の仕組みを再構築したことを確認してくれた @Gavin に感謝します。