我想提取 glmnet 生成的模型系数并从中创建一个 SQL 查询。该函数 coef(cv.glmnet.fit)
产生一个“ dgCMatrix
”对象。当我使用 将其转换为矩阵as.matrix
时,变量名称会丢失,只留下系数值。
我知道可以在屏幕上打印系数,但是可以将名称写入数据框吗?
任何人都可以协助提取这些名称吗?
更新: 我回答的前两条评论都是正确的。为了后代,我将答案保留在下面。
以下答案很简短,它可以工作并且不需要任何其他包:
tmp_coeffs <- coef(cv.glmnet.fit, s = "lambda.min")
data.frame(name = tmp_coeffs@Dimnames[[1]][tmp_coeffs@i + 1], coefficient = tmp_coeffs@x)
+1 的原因是该@i
方法从 0 开始索引截距,但从@Dimnames[[1]]
1 开始。
旧答案:(仅供后代使用) 试试这些行:
非零系数:
coef(cv.glmnet.fit, s = "lambda.min")[which(coef(cv.glmnet.fit, s = "lambda.min") != 0)]
选择的功能:
colnames(regression_data)[which(coef(cv.glmnet.fit, s = "lambda.min") != 0)]
然后将它们作为数据框放在一起是直接的,但如果您也想要这部分代码,请告诉我。
这些名称应该可以作为 访问dimnames(coef(cv.glmnet.fit))[[1]]
,因此以下内容应将系数名称和值都放入 data.frame 中:
data.frame(coef.name = dimnames(coef(GLMNET))[[1]], coef.value = matrix(coef(GLMNET)))
检查扫帚包。它具有tidy
将不同 R 对象(包括glmnet
)的输出转换为 data.frames 的功能。
基于上述 Mehrad 的解决方案,这里有一个简单的函数,用于打印仅包含非零系数的表格:
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)
}
上面的kable()
函数使用来自 knitr 的函数来生成 Markdown-ready 表。
在这里,我编写了一个可重现的示例,并使用cv.glmnet
. 模型glmnet
拟合也将起作用。在这个例子的最后,我将非零系数和相关特征组装到一个名为的 data.frame 中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
有一种使用coef()到glmnet()对象(您的模型)的方法。在索引 [[1]] 以下的情况下,表示多项逻辑回归中结果类的数量,也许对于其他模型,您应该删除它。
coef_names_GLMnet <- coef(GLMnet, s = 0)[[1]]
row.names(coef_names_GLMnet)[coef_names_GLMnet@i+1]
在这种情况下, row.names()索引需要递增 (+1),因为coef()对象中的变量(数据特征)的编号从 0 开始,但在转换后字符向量的编号从 1 开始。
假设您知道如何获得您的 lambda,我发现了两种不同的方法来显示该特定 lambda 的所选模型中所需的预测变量。其中之一包括拦截。可以通过“ glmnet ”库中的cv.glmnet的平均值使用交叉验证来获得 lambda 。您可能只想查看每种方法的最后几行:
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
请注意,上面的示例暗示了二项分布,但这些步骤可以应用于任何其他类型。
# 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"))
}
没有小标题:
tidy_coef2 <- function(x){
x <- coef(x)
data.frame(term=rownames(x),
estimate=matrix(x)[,1],
stringsAsFactors = FALSE)
}
I faced a similar issue when using glmnet
from the tidymodels
framework, where the model was trained within a workflow and neither coef()
nor the above solutions worked.
What worked for me though, was part of the glmnet:::coef.glmnet
code:
# taken from glmnet:::coef.glmnet
coefs <- predict(x, "lambda.min", type = "coefficients", exact = FALSE)
dd <- cbind(
data.frame(var = rownames(coefs)),
as.data.table(as.matrix(coefs))
)