使用glmnet查找给定数量的预测变量的优化模型

时间:2019-01-09 18:50:17

标签: r statistics glmnet

我正在尝试将LASSO用于与最初设计略有不同的功能。我在测试中有22个不同的任务,平均下来可以得出最终成绩。我想看看有限数量的任务中的哪种组合最能预测总体得分,并希望能创建简短的测试形式。

我正在使用glmnet接下来运行套索,它按预期运行。然后,我可以使用

在给定的lamda上轻松找到模型。
coef(cvfit, s = s)

但是,我想知道是否可以指定n个具有非零系数而不是惩罚参数的预测变量?

我通过从测试lambda的网格中提取模型,建立了一种效率很低的方法,如下所示,但是我想知道是否有一种更有效的方法

nvar <- list()
coeffs <- list()

for(j in 1:20000) {

  s <- j / 20000

  coeffs[j] <- coef(cvfit, s = s) ##Get coefficient list at given lamda

  nvar[j] <- sum(as.vector(coef(cvfit, s = s)) != 0) - 1 ##Count number of variables with non-zero coeff and subtract one because intercept is always non-zero

}

nvar <- unlist(nvar)

getlamda <- function(numvar = 4) {

  min.lambda <- min(lambdas[nvar == numvar]) / 20000 ##Find the smallest lambda which resulted in the given number of non-zero coefficients

  coeffs[min.lambda]

}

2 个答案:

答案 0 :(得分:1)

在使用上述Blended解决方案之后,我意识到有一种更简单的方法可以做到这一点。

使用示例中使用的Boston数据集:

library(dplyr)
library(glmnet)

(boston <- MASS::Boston %>% tbl_df())

tr_x <- model.matrix(medv ~ ., data = boston)[,-1]
tr_y <- boston$medv
cvfit <- glmnet(tr_x, tr_y)

cvfit对象已经具有找到给定数量的变量的答案所需的所有组件。 df是自由度的数量,是我们感兴趣的可变参数的数量。 lambda是每个模型的lambda。

因此我们可以创建一个简单的函数,该函数针对给定数量的变量返回最佳模型。

get_nparam <- function(mod, numvar) {

  coef(mod, s = with(cvfit, min(lambda[df == numvar])))

}

get_nparam(cvfit, 4)

#14 x 1 sparse Matrix of class "dgCMatrix"
#                       1
#(Intercept) 15.468034114
#crim         .          
#zn           .          
#indus        .          
#chas         .          
#nox          .          
#rm           3.816165372
#age          .          
#dis          .          
#rad          .          
#tax          .          
#ptratio     -0.606026131
#black        0.001518042
#lstat       -0.495954410
#

再次感谢Blender提供不同的解决方案,并将我带到了解决之道。

答案 1 :(得分:0)

您可以使用rowSums()

(boston <- MASS::Boston %>% tbl_df())
#> # A tibble: 506 x 14
#>       crim    zn indus  chas   nox    rm   age   dis   rad   tax ptratio
#>  *   <dbl> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <int> <dbl>   <dbl>
#>  1 0.00632  18    2.31     0 0.538  6.58  65.2  4.09     1   296    15.3
#>  2 0.0273    0    7.07     0 0.469  6.42  78.9  4.97     2   242    17.8
#>  3 0.0273    0    7.07     0 0.469  7.18  61.1  4.97     2   242    17.8
#>  4 0.0324    0    2.18     0 0.458  7.00  45.8  6.06     3   222    18.7
#>  5 0.0690    0    2.18     0 0.458  7.15  54.2  6.06     3   222    18.7
#>  6 0.0298    0    2.18     0 0.458  6.43  58.7  6.06     3   222    18.7
#>  7 0.0883   12.5  7.87     0 0.524  6.01  66.6  5.56     5   311    15.2
#>  8 0.145    12.5  7.87     0 0.524  6.17  96.1  5.95     5   311    15.2
#>  9 0.211    12.5  7.87     0 0.524  5.63 100    6.08     5   311    15.2
#> 10 0.170    12.5  7.87     0 0.524  6.00  85.9  6.59     5   311    15.2
#> # ... with 496 more rows, and 3 more variables: black <dbl>, lstat <dbl>,
#> #   medv <dbl>

对于上述数据集(Boston housing),请考虑medv ~ .

library(glmnet)
tr_x <- model.matrix(medv ~ ., data = boston)[,-1]
tr_y <- boston$medv
cvfit <- glmnet(tr_x, tr_y)

head(t(coef(cvfit)))
    #> 6 x 14 sparse Matrix of class "dgCMatrix"
    #>    [[ suppressing 14 column names '(Intercept)', 'crim', 'zn' ... ]]
    #>                                                        
    #> s0 22.53281 . . . . . .         . . . . . .  .         
    #> s1 23.60072 . . . . . .         . . . . . . -0.08439977
    #> s2 23.67264 . . . . . 0.1278413 . . . . . . -0.15358093
    #> s3 21.44649 . . . . . 0.5694424 . . . . . . -0.19698136
    #> s4 19.42057 . . . . . 0.9714620 . . . . . . -0.23654740
    #> s5 17.57464 . . . . . 1.3377669 . . . . . . -0.27259852

我想您已经完成了此过程。


备注

  1. 转置系数矩阵以使每个变量成为每一列可能会很方便。
  2. 对于t(coef(cvfit))rowSums(t(coef(cvfit)) != 0)查找每个变量的非零元素数。
  3. 接下来,我们将numvar与此rowSums进行匹配,然后找到系数的值。

表示从s0s5,lambda s0s5大-受罚更多。

head(cvfit$lambda)
#> [1] 6.777654 6.175546 5.626927 5.127046 4.671574 4.256564

具有numvar的子集系数

基于这些事实,

get_nparam <- function(mod, numvar) {
  beta <- coef(mod)
  non_zero <- rowSums(t(beta)[,-1] != 0) # ignore intercept
  min_lam <- which(non_zero == numvar) # numvar non-zero coef
  t(beta)[dplyr::last(min_lam),] # last index = smallest lambda
}

使用此功能,您可以获得

get_nparam(cvfit, 4)
#>  (Intercept)         crim           zn        indus         chas 
#> 15.468034114  0.000000000  0.000000000  0.000000000  0.000000000 
#>          nox           rm          age          dis          rad 
#>  0.000000000  3.816165372  0.000000000  0.000000000  0.000000000 
#>          tax      ptratio        black        lstat 
#>  0.000000000 -0.606026131  0.001518042 -0.495954410

rmptratioblacklstat非零,而其他零。