Quelle déviance glmnet utilise-t-il pour comparer les valeurs de

8

Un critère de sélection de la valeur optimale de avec un filet élastique ou une régression pénalisée similaire consiste à examiner un tracé de la déviance par rapport à la plage de et à sélectionner lorsque la déviance est minimisée (ou dans une erreur standard de la le minimum).λλλλ

Cependant, j'ai du mal à comprendre avec quoi exactement glmnets'affiche plot.cv.glmnet, car le tracé affiché ne ressemble pas du tout aux résultats du tracé de la déviance contre .λ

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))

entrez la description de l'image ici entrez la description de l'image ici

Il semble que le deuxième tracé n'incorpore pas la pénalité nette élastique et est également incorrectement mis à l'échelle verticalement. Je fonde l'affirmation sur la base que la forme de la courbe pour des valeurs plus élevées de ressemble à celle de la sortie. Cependant, lorsque j'ai tenté de calculer la pénalité par moi-même, ma tentative semble également extrêmement inexacte.λ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)

Ma question est: comment calculer manuellement la déviance signalée dans le plot.cv.glmnetdiagramme par défaut ? Quelle est sa formule et qu'ai-je fait de mal dans ma tentative de calcul?

Sycorax dit de réintégrer Monica
la source
Vous savez que la cv.glmnetvalidation croisée est multipliée par 10, non? Donc, il trace la moyenne de l'erreur standard +/- 1 de la déviance sur les données de maintien de 10%?
Andrew M
J'en suis conscient, oui.
Sycorax dit Réintégrer Monica le

Réponses:

6

Je voulais juste ajouter quelque chose, mais pour le moment je n'ai pas de réponse concise et c'est trop long pour un commentaire. Espérons que cela donne plus d'informations.

Il semble que la fonction qui nous intéresse se trouve dans la bibliothèque glmnet non compressée et s'appelle cv.lognet.R Il est difficile de tout tracer explicitement, tout comme dans le code S3 / S4, mais la fonction ci-dessus est répertoriée comme une `` fonction glmnet interne », utilisé par les auteurs et semble correspondre à la façon dont le cv.glmnet calcule la déviance binomiale.

Bien que je ne l'ai vu nulle part dans le document, du traçage du code glmnet à cv.lognet, ce que je comprends, c'est qu'il utilise quelque chose appelé la déviance binomiale plafonnée décrite ici .

[Ylog10(E)+(1Y)log10(1E)]

predmat est une matrice des valeurs de probabilité plafonnées (E, 1-E) produites pour chaque lambda, qui sont comparées aux valeurs de complément de y et y résultant en lp. Ils sont ensuite placés sous la forme de déviance 2 * (ly-lp) et moyennés sur les plis de maintien validés de manière croisée pour obtenir cvm - l'erreur moyenne de validation croisée - et les plages de cv que vous avez tracées dans la première image.

Je pense que la fonction de déviation manuelle (2e tracé) n'est pas calculée de la même manière que celle interne (1er tracé).

    # 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)
tapoter
la source
Merci pour la réponse, pat. Cela répond à toutes les questions que j'avais sur le fonctionnement de la procédure et les concepts statistiques sous-jacents, pas seulement sur le logiciel.
Sycorax dit Réintégrer Monica le
2

J'ai donc visité le site du CRAN et téléchargé ce que je pense être la source du paquet glmnet . Dans ./glmnet/R/plot.cv.glmnet.R, il semble que vous trouverez le code source que vous recherchez. C'est assez bref, donc je vais coller ici, mais il est probablement préférable de le vérifier vous-même pour vous assurer que c'est bien le code qui est en cours d'exécution.

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()
}
Diego
la source
1
Les méthodes S3 sont légèrement cachées dans R, mais pour voir exactement ce qui est exécuté, vous pouvez taper getS3method('plot', 'cv.glmnet')sans vous soucier de télécharger le paquet source. (En interne, glmnetvient de définir une fonction appelée plot.cv.glmnetmais ne l'a pas exportée. Vous pouvez toujours la voir en jetant un œil à l'intérieur de l'espace de nom avec l' :::opérateur :) glmnet:::plot.cv.glmnet.
Andrew M
(+1) Merci pour la réponse, Diego. Cela me pointe dans la bonne direction et indique implicitement où je me suis trompé. Cependant, je vais m'arrêter d'accepter pour le moment car cela ne répond pas à la question statistique spécifique (vice-programmation), qui est énoncée au bas de mon message.
Sycorax dit Réintégrer Monica le