8

S3 メソッドがどのように呼び出されるかについてのドキュメントを理解するのにいつも苦労していましたが、今回はそれが私を悩ませています。

複数の質問をすることを前もってお詫びしますが、それらはすべて密接に関連しています。複雑な一連の関数の中心部で、私は多くのglmnetフィット、特にロジスティック フィットを作成します。現在、glmnetドキュメントでは、その戻り値が "glmnet" と (ロジスティック回帰の場合) "lognet" の両方のクラスを持つように指定されています。実際、これらはこの順序で指定されます。

しかし、 の実装の最後を見ると、のクラスを「lognet」に設定glmnetする (内部関数) の呼び出しの直後に、(変数の)リターンの直前に次のコード行が表示されます。lognetfitfit

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)

そして、もう一度予測呼び出しを実行します。見よ、うまくいきました! 確率はわかります

それで、ここにいくつかの質問があります:

  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に感謝します(「他のすべてが失敗した場合は、再起動する」:「バージョンを確認する」以外に)。私は、統計学習の神々によるパッケージはこの種のエラーから保護されると誤って想定していました)、そして S3 の仕組みを再構築したことを確認してくれた @Gavin に感謝します。

4

1 に答える 1

6

はい、クラスが class 属性にリストされている順序で発送されます。単純な日常のケースでは、そうです、最初に宣言されたクラスは、メソッド ディスパッチによって最初に選択されたクラスであり、そのクラスのメソッドが見つからない (またはNextMethod呼び出された) 場合にのみ、2 番目のクラスに移動します。またはメソッドの検索に失敗しますdefault

いいえ、コード内でクラスの順序が間違っているというあなたの意見は正しいとは思いません。ドキュメントが間違っているようです。その意図は明らかに、predict.lognet()最初に呼び出し、主力製品を使用してglmnetpredict.glmnet()によってフィッティングされたすべてのタイプの投げ縄/エラスティック ネット モデルの基本的な計算を行い、最後にこれらの一般的な予測の後処理を行うことです。これはglmnet NAMESPACEからはエクスポートされませんが、他のメソッドもおそらくそれを示しています。predict.glmnet()

なぜあなたがこれからの出力を考えるのか分かりません:

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

間違っている?10 行 21 列の行列を取得します。列は、切片のみのモデル予測に関連するものと、なげなわ/エラスティック ネット パスに沿ったモデル係数が計算されたラムダの 20 値での予測に関連しています。これらは線形結合ではないようで、ご要望の応答スケールの 1 つです。

クラスの順番は変わりません。コードがどのように機能するかを誤解していると思います。順序が間違っていると記載されているため、ドキュメントにバグがあります。しかし、コードは私が思うように機能しています。

于 2011-06-23T23:15:22.797 に答える