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?
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.
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)))
Vérifiez balai paquet. Il a la fonction tidy
qui convertit la sortie de différents objets R (y compris glmnet
) en data.frames.
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.
# 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)
}
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
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.
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.