R中glmnet模型的变量重要性计算中的差异

问题描述

我想为R中的glmnet模型计算变量重要性。我正在使用glmnet包来拟合弹性网模型,例如

library(glmnet)
library(caret)
library(vip)

data_y <- as.vector(mtcars$mpg)
data_x <- as.matrix(mtcars[-1])

fit.glmnet <- glmnet(data_x,data_y,family="gaussian")

set.seed(123)
cvfit.glmnet = cv.glmnet(data_x,standardize=T)
cvfit.glmnet$lambda.min
coef(cvfit.glmnet,s = "lambda.min")

然后我使用vip软件包来作为具有不同重要性的软件包

#Using vip package
vip::vi_model(cvfit.glmnet,s = cvfit.glmnet$fit$lambda)

返回我

># A tibble: 10 x 3
   Variable Importance Sign 
   <chr>         <dbl> <chr>
 1 cyl         -0.886  NEG  
 2 disp         0      NEG  
 3 hp          -0.0117 NEG  
 4 drat         0      NEG  
 5 wt          -2.71   NEG  
 6 qsec         0      NEG  
 7 vs           0      NEG  
 8 am           0      NEG  
 9 gear         0      NEG  
10 carb         0      NEG 

变量重要性同时包含变量的正值和负值,其变化范围在0-1或0-100%之间。

然后我尝试使用此answer

自定义功能
#Using function provided in this example
varImp <- function(object,lambda = NULL,...) {
  
  ## skipping a few lines
  
  beta <- predict(object,s = lambda,type = "coef")
  if(is.list(beta)) {
    out <- do.call("cbind",lapply(beta,function(x) x[,1]))
    out <- as.data.frame(out)
  } else out <- data.frame(Overall = beta[,1])
  out <- abs(out[rownames(out) != "(Intercept)",drop = FALSE])
  out
}

varImp(cvfit.glmnet,lambda = cvfit.glmnet$lambda.min)

它在输出后返回我

        Overall
cyl  0.88608541
disp 0.00000000
hp   0.01168438
drat 0.00000000
wt   2.70814703
qsec 0.00000000
vs   0.00000000
am   0.00000000
gear 0.00000000
carb 0.00000000

尽管自定义函数输出不包含负值,但它的变化范围是0-1或0-100%。

我知道caret包具有varImp功能,其重要性在0-100%之间变化。但是我想为cv.glmnet对象而不是caret::train对象实现相同的东西。如何为caret对象的cv.glmnet包实现可变重要性?

解决方法

问题询问如何获取0-100%之间的glmnet变量重要性。

如果希望基于系数幅度以某个(通常为最佳)惩罚来分配重要性。而且,如果这些系数是根据标准化变量(glmnet中的默认值)得出的,则这些系数可以简单地缩放到0-1范围:

给出了稍微修改的功能:

varImp <- function(object,lambda = NULL,...) {
  beta <- predict(object,s = lambda,type = "coef")
  if(is.list(beta)) {
    out <- do.call("cbind",lapply(beta,function(x) x[,1]))
    out <- as.data.frame(out)
  } else out <- data.frame(Overall = beta[,1])
  out <- abs(out[rownames(out) != "(Intercept)",drop = FALSE])
  out <- out/max(out)
  out[order(out$Overall,decreasing = TRUE),drop=FALSE]
}

使用问题中的示例:

varImp(cvfit.glmnet,lambda = cvfit.glmnet$lambda.min)
#output
         Overall
wt   1.000000000
cyl  0.320796270
am   0.004840186
hp   0.004605913
disp 0.000000000
drat 0.000000000
qsec 0.000000000
vs   0.000000000
gear 0.000000000
carb 0.000000000

将变量重要性分配给glmnet模型的另一种方法是根据包含的惩罚为变量评分-如果在较高的惩罚下排除变量,变量将更为重要。此方法将在mlr3软件包中实现:https://github.com/mlr-org/mlr3learners/issues/28在某些时候