web-dev-qa-db-fra.com

Extraction des noms de variables de coefficient de glmnet dans un data.frame

Je voudrais extraire les coefficients du modèle généré par glmnet et créer une requête SQL à partir d'eux. La fonction coef(cv.glmnet.fit) donne un objet 'dgCMatrix'. Quand je le convertis en matrice en utilisant as.matrix, les noms des variables sont perdus et seules les valeurs de coefficient sont laissées.

Je sais que l'on peut imprimer les coefficients à l'écran, mais est-il possible d'écrire les noms dans une trame de données?

Quelqu'un peut-il aider à extraire ces noms?

25
David Eborall

MISE À JOUR: Les deux premiers commentaires de ma réponse sont corrects. J'ai gardé la réponse sous la ligne juste pour la postérité.

La réponse suivante est courte, elle fonctionne et ne nécessite aucun autre package:

tmp_coeffs <- coef(cv.glmnet.fit, s = "lambda.min")
data.frame(name = tmp_coeffs@Dimnames[[1]][tmp_coeffs@i + 1], coefficient = tmp_coeffs@x)

La raison de +1 est que le @i index de méthode à partir de 0 pour l'interception mais @Dimnames[[1]] commence à 1.


ANCIENNE RÉPONSE: (conservé uniquement pour la postérité) Essayez ces lignes:

Les coefficients non nuls:

coef(cv.glmnet.fit, s = "lambda.min")[which(coef(cv.glmnet.fit, s = "lambda.min") != 0)]

Les fonctionnalités sélectionnées:

colnames(regression_data)[which(coef(cv.glmnet.fit, s = "lambda.min") != 0)]

Ensuite, les assembler en tant que trame de données est très simple, mais faites-moi savoir si vous souhaitez également cette partie du code.


23
Mehrad Mahmoudian

Les noms doivent être accessibles en tant que dimnames(coef(cv.glmnet.fit))[[1]], les éléments suivants doivent donc mettre à la fois les noms et les valeurs des coefficients dans un data.frame: data.frame(coef.name = dimnames(coef(GLMNET))[[1]], coef.value = matrix(coef(GLMNET)))

6
Peter

Vérifiez balai paquet. Il a la fonction tidy qui convertit la sortie de différents objets R (y compris glmnet) en data.frames.

4
Tim

En s'appuyant sur la solution de Mehrad ci-dessus, voici une fonction simple pour imprimer un tableau contenant uniquement les coefficients non nuls:

print_glmnet_coefs <- function(cvfit, s="lambda.min") {
    ind <- which(coef(cvfit, s=s) != 0)
    df <- data.frame(
        feature=rownames(coef(cvfit, s=s))[ind],
        coeficient=coef(cvfit, s=s)[ind]
    )
    kable(df)
}

La fonction ci-dessus utilise la fonction kable() de knitr pour produire une table prête pour Markdown.

4
Keith Hughitt
# requires tibble.
tidy_coef <- function(x){
    coef(x) %>%
    matrix %>%   # Coerce from sparse matrix to regular matrix.
    data.frame %>%  # Then dataframes.
    rownames_to_column %>%  # Add rownames as explicit variables.
    setNames(c("term","estimate"))
}

Sans tibble:

tidy_coef2 <- function(x){
    x <- coef(x)
    data.frame(term=rownames(x),
               estimate=matrix(x)[,1],
               stringsAsFactors = FALSE)
}
2
Michael Rice

Ici, j'ai écrit un exemple reproductible et ajusté un exemple binaire (logistique) en utilisant cv.glmnet. Un ajustement de modèle glmnet fonctionnera également. À la fin de cet exemple, j'ai assemblé des coefficients non nuls et des fonctionnalités associées dans un data.frame appelé myResults:

library(glmnet)
X <- matrix(rnorm(100*10), 100, 10);
X[51:100, ] <- X[51:100, ] + 0.5; #artificially introduce difference in control cases
rownames(X) <- paste0("observation", 1:nrow(X));
colnames(X) <- paste0("feature",     1:ncol(X));

y <- factor( c(rep(1,50), rep(0,50)) ); #binary outcome class label
y
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [51] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## Levels: 0 1

## Perform logistic model fit:
fit1 <- cv.glmnet(X, y, family="binomial", nfolds=5, type.measure="auc"); #with K-fold cross validation
# fit1 <- glmnet(X, y, family="binomial") #without cross validation also works

## Adapted from @Mehrad Mahmoudian:
myCoefs <- coef(fit1, s="lambda.min");
myCoefs[which(myCoefs != 0 ) ]               #coefficients: intercept included
## [1]  1.4945869 -0.6907010 -0.7578129 -1.1451275 -0.7494350 -0.3418030 -0.8012926 -0.6597648 -0.5555719
## [10] -1.1269725 -0.4375461
myCoefs@Dimnames[[1]][which(myCoefs != 0 ) ] #feature names: intercept included
## [1] "(Intercept)" "feature1"    "feature2"    "feature3"    "feature4"    "feature5"    "feature6"   
## [8] "feature7"    "feature8"    "feature9"    "feature10"  

## Asseble into a data.frame
myResults <- data.frame(
  features = myCoefs@Dimnames[[1]][ which(myCoefs != 0 ) ], #intercept included
  coefs    = myCoefs              [ which(myCoefs != 0 ) ]  #intercept included
)
myResults
##       features      coefs
## 1  (Intercept)  1.4945869
## 2     feature1 -0.6907010
## 3     feature2 -0.7578129
## 4     feature3 -1.1451275
## 5     feature4 -0.7494350
## 6     feature5 -0.3418030
## 7     feature6 -0.8012926
## 8     feature7 -0.6597648
## 9     feature8 -0.5555719
## 10    feature9 -1.1269725
## 11   feature10 -0.4375461
2
David C.

Il existe une approche en utilisant coef () à glmnet () objet (votre modèle). Dans un cas ci-dessous, l'indice [[1]] indique le nombre de classes de résultats dans la régression logistique multinomiale, peut-être pour d'autres modèles, vous devez le supprimer.

coef_names_GLMnet <- coef(GLMnet, s = 0)[[1]]
row.names(coef_names_GLMnet)[coef_names_GLMnet@i+1]

row.names () les index dans ce cas doivent être incrémentés (+1) car la numération des variables (caractéristiques des données) dans coef () objet commençant à 0, mais après le caractère de transformation numération vectorielle à partir de 1.

2
Bem Ostap

En supposant que vous sachiez comment obtenir votre lambda, j'ai trouvé deux façons différentes de montrer les prédicteurs nécessaires dans le modèle sélectionné pour ce lambda particulier. L'un d'eux comprend l'interception. Le lambda peut être obtenu en utilisant la validation croisée par la moyenne de cv.glmnet à partir de la bibliothèque "glmnet". Vous voudrez peut-être regarder uniquement les dernières lignes de chaque méthode:

 myFittedLasso = glmnet(x=myXmatrix, y=myYresponse, family="binomial")
 myCrossValidated = cv.glmnet(x=myXmatrix, y=myYresponse, family="binomial")
 myLambda = myCrossValidated$lambda.1se  # can be simply lambda

 # Method 1 without the intercept
 myBetas = myFittedLasso$beta[, which(myFittedLasso$lambda == myLambda)]
 myBetas[myBetas != 0]
 ## myPredictor1    myPredictor2    myPredictor3
 ##   0.24289802      0.07561533      0.18299284


 # Method 2 with the intercept
 myCoefficients = coef(myFittedLasso, s=myLambda)
 dimnames(myCoefficients)[[1]][which(myCoefficients != 0)]
 ## [1] "(Intercept)"    "myPredictor1"    "M_myPredictor2"    "myPredictor3"

 myCoefficients[which(myCoefficients != 0)]
 ## [1] -4.07805560  0.24289802  0.07561533  0.18299284

Notez que l'exemple ci-dessus implique une distribution binomiale mais les étapes peuvent être appliquées à tout autre type.

1
Khoubeib Bouthour