Je ne pense pas que vous ayez fait une erreur dans le code. Il s'agit d'interpréter la sortie.
Le Lasso n'indique pas quels régresseurs individuels sont "plus prédictifs" que d'autres. Il a simplement une tendance intégrée à estimer les coefficients à zéro. Plus le coefficient de pénalité est élevélog(λ) est, plus cette tendance est grande.
Votre graphique de validation croisée montre qu'à mesure que de plus en plus de coefficients sont forcés à zéro, le modèle fait de mieux en mieux la prédiction de sous-ensembles de valeurs qui ont été supprimés de manière aléatoire de l'ensemble de données. Lorsque les meilleures erreurs de prédiction à validation croisée (mesurées ici comme la «déviance binomiale») sont obtenues lorsque tous les coefficients sont nuls, vous devez suspecter qu'aucune combinaison linéaire d'aucun sous-ensemble des régresseurs ne peut être utile pour prédire les résultats.
Vous pouvez le vérifier en générant des réponses aléatoires indépendantes de tous les régresseurs et en leur appliquant votre procédure d'ajustement. Voici un moyen rapide d'émuler votre jeu de données:
n <- 570
k <- 338
set.seed(17)
X <- data.frame(matrix(floor(runif(n*(k+1), 0, 2)), nrow=n,
dimnames=list(1:n, c("y", paste0("x", 1:k)))))
Le bloc de données X
a une colonne binaire aléatoire nommée "y" et 338 autres colonnes binaires (dont les noms n'ont pas d'importance). J'ai utilisé votre approche pour régresser "y" par rapport à ces variables, mais - juste pour être prudent - je me suis assuré que le vecteur de réponse y
et la matrice du modèle x
correspondent (ce qu'ils pourraient ne pas faire en cas de valeurs manquantes dans les données) :
f <- y ~ . - 1 # cv.glmnet will include its own intercept
M <- model.frame(f, X)
x <- model.matrix(f, M)
y <- model.extract(M, "response")
fit <- cv.glmnet(x, y, family="binomial")
Le résultat est remarquablement semblable au vôtre:
plot(fit)
En effet, avec ces données complètement aléatoires, le Lasso renvoie toujours neuf estimations de coefficient non nul (même si nous savons, par construction, que les valeurs correctes sont toutes nulles). Mais il ne faut pas s'attendre à la perfection. De plus, comme l'ajustement est basé sur la suppression aléatoire de sous-ensembles de données pour la validation croisée, vous n'obtiendrez généralement pas la même sortie d'une exécution à l'autre. Dans cet exemple, un deuxième appel à cv.glmnet
produit un ajustement avec un seul coefficient non nul. Pour cette raison, si vous avez le temps, c'est toujours une bonne idée de relancer la procédure d'ajustement plusieurs fois et de garder une trace des estimations de coefficient qui sont systématiquement non nulles. Pour ces données - avec des centaines de régresseurs - cela prendra quelques minutes pour répéter neuf fois de plus.
sim <- cbind(as.numeric(coef(fit)),
replicate(9, as.numeric(coef(cv.glmnet(x, y, family="binomial")))))
plot(1:k, rowMeans(sim[-1,] != 0) + runif(k, -0.025, 0.025),
xlab="Coefficient Index", ylab="Frequency not zero (jittered)",
main="Results of Repeated Cross-Validated Lasso Fits")
Huit de ces régresseurs ont des estimations non nulles dans environ la moitié des ajustements; les autres n'ont jamais d'estimations non nulles. Cela montre dans quelle mesure le Lasso inclura toujours des estimations de coefficient non nul même lorsque les coefficients eux-mêmes sont vraiment nuls.