glmnetは


8

最適値を選択するための一つの基準弾性ネットまたは類似献上回帰では、範囲に対するずれのプロットを調べることである選択し逸脱が最小化される場合(またはの1つの標準誤差以内最小)。λ λ λλλλλ

ただし、表示されるプロットはに対する逸脱をプロットした結果にまったく似ていないため、正確に何がglmnet表示されるかを理解するのは困難です。plot.cv.glmnetλ

set.seed(4567)
N       <- 500
P       <- 100
coefs   <- NULL
for(p in 1:P){
    coefs[p]    <- (-1)^p*100*2^(-p)
}
inv.logit <- function(x) exp(x)/(1+exp(x))
X   <- matrix(rnorm(N*P), ncol=P, nrow=N)
Y   <- rbinom(N, size=1, p=inv.logit(cbind(1, X)%*%c(-4, coefs)))
plot(test   <- cv.glmnet(x=X, y=Y, family="binomial", nfolds=10, alpha=0.8))
plot(log(test$lambda), deviance(test$glmnet.fit))

ここに画像の説明を入力してください ここに画像の説明を入力してください

2番目のプロットにはエラスティックネットペナルティが組み込まれておらず、垂直方向に誤ってスケーリングされているようです。値が大きい場合の曲線の形状は出力の形状に似ているという根拠に基づいて、私は主張を基にしています。しかし、自分でペナルティを計算しようとした場合、私の試みも同様に非常に不正確に見えます。λglmnet

penalized.dev.fn    <- function(lambda, alpha=0.2, data, cv.model.obj){
    dev <- deviance(cv.model.obj$glmnet.fit)[seq_along(cv.model.obj$lambda)[cv.model.obj$lambda==lambda]]
    beta <- coef(cv.model.obj, s=lambda)[rownames(coef(cv.model.obj))!="(Intercept)"]
    penalty <- lambda * ( (1-alpha)/2*(beta%*%beta) + alpha*sum(abs(beta)) )
    penalized.dev <- penalty+dev
    return(penalized.dev)
}

out <- sapply(test$lambda, alpha=0.2, cv.model.obj=test, FUN=penalized.dev.fn)
    plot(log(test$lambda), out)

私の質問は、デフォルトのplot.cv.glmnet図で報告された逸脱を手動でどのように計算するのですか?その式は何ですか、そしてそれを計算する私の試みで何が間違っていますか?


cv.glmnet10分割交差検証を実行していることをご存知でしょうか?それで、それは10%のホールドアウトデータの逸脱の平均+/- 1標準誤差をプロットしていますか?
アンドリューM

はい、そうです。
Sycoraxは、モニカを2015

回答:


6

私は入力に追加したかっただけですが、現時点では簡潔な答えはありません。コメントには長すぎます。うまくいけば、これにより多くの洞察が得られます。

対象の関数は、解凍されたglmnetライブラリにあり、cv.lognet.Rと呼ばれているようです。S3/ S4コードと同様に、すべてを明示的にトレースすることは困難ですが、上記の関数は「内部glmnet関数」としてリストされています。 、 '作者が使用し、cv.glmnetが二項偏差を計算する方法と一致しているようです。

紙のどこにも見かけませんでしたが、glmnetコードのトレースからcv.lognetまで、ここで説明した上限付き二項偏差と呼ばれるものを使用していることがわかります

[Yログ10E+1Yログ101E]

predmatは、各ラムダのキャップされた確率値(E、1-E)の出力の行列で、yとyの補数値と比較され、結果としてlpになります。次に、それらは2 *(ly-lp)逸脱フォームに入れられ、相互検証されたホールドフォールドで平均化されて、最初の画像でプロットしたcvm-平均相互検証エラー-およびcv範囲が得られます。

手動の逸脱関数(2番目のプロット)は、この内部関数(1番目のプロット)と同じ方法で計算されていないと思います。

    # from cv.lognet.R

    cvraw=switch(type.measure,
    "mse"=(y[,1]-(1-predmat))^2 +(y[,2]-predmat)^2,
    "mae"=abs(y[,1]-(1-predmat)) +abs(y[,2]-predmat),
    "deviance"= {
      predmat=pmin(pmax(predmat,prob_min),prob_max)
      lp=y[,1]*log(1-predmat)+y[,2]*log(predmat)
      ly=log(y)
      ly[y==0]=0
      ly=drop((y*ly)%*%c(1,1))
      2*(ly-lp)

   # cvm output
   cvm=apply(cvraw,2,weighted.mean,w=weights,na.rm=TRUE)

回答ありがとうございます、パット。これは、ソフトウェアだけでなく、手順がどのように機能するか、および根底にある統計的概念について私が持っていたすべての質問に対処します。
Sycoraxは、モニカ

2

そこで、CRANサイトにアクセスして、glmnetパッケージのソースであると私が思うものをダウンロードしました。./glmnet/R/plot.cv.glmnet.Rには、目的のソースコードが見つかるようです。それはかなり簡単なのでここに貼り付けますが、実際に実行されているコードであることを確認するために自分で確認するのがおそらく最善です。

plot.cv.glmnet=function(x,sign.lambda=1,...){
  cvobj=x
  xlab="log(Lambda)"
  if(sign.lambda<0)xlab=paste("-",xlab,sep="")
  plot.args=list(x=sign.lambda*log(cvobj$lambda),y=cvobj$cvm,ylim=range(cvobj$cvup,cvobj$cvlo),xlab=xlab,ylab=cvobj$name,type="n")
      new.args=list(...)
      if(length(new.args))plot.args[names(new.args)]=new.args
    do.call("plot",plot.args)
    error.bars(sign.lambda*log(cvobj$lambda),cvobj$cvup,cvobj$cvlo,width=0.01,col="darkgrey")
  points(sign.lambda*log(cvobj$lambda),cvobj$cvm,pch=20,col="red")
axis(side=3,at=sign.lambda*log(cvobj$lambda),labels=paste(cvobj$nz),tick=FALSE,line=0)
abline(v=sign.lambda*log(cvobj$lambda.min),lty=3)
    abline(v=sign.lambda*log(cvobj$lambda.1se),lty=3)
  invisible()
}

1
S3メソッドはRではわずかに隠されていますが、実行されているものを正確に確認getS3method('plot', 'cv.glmnet')するには、ソースパッケージをダウンロードする手間をかけずに入力できます。(内部的にglmnetは、呼び出された関数を定義しましたが、plot.cv.glmnetそれをエクスポートしていません。:::演算子:を使用して名前空間内を覗くと、まだそれを表示できますglmnet:::plot.cv.glmnet)。
アンドリューM

(+1)答えてくれてありがとう、ディエゴ。これは私を正しい方向に向け、私がどこで間違っていたかを暗黙的に指摘します。ただし、これは私の投稿の下部に記載されている特定の統計(副プログラミング)の質問には答えられないため、当面は受け入れを保留します。
Sycoraxは、モニカを2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.