3

在函数的文档中cv.glmnet(),给出了:

lambda.1se :
lambda 的最大值,使得误差在最小值的 1 个标准误差之内。

这意味着lambda.1se给出lambda,它给出一个误差 ( cvm),它与最小误差相差一个标准误差。

因此,在尝试检查这个事实时:库中
有一个数据集。我使用套索执行了交叉验证:BostonMASS

x = model.matrix(crim~.-1,data=Boston)#-1 for removing the intercept column
y = Boston$crim
cv.lasso = cv.glmnet(x,y,type.measure = "mse",alpha=1)

的值cv.lasso$lambda.min是:

> cv.lasso$lambda.min
[1] 0.05630926

并且, 的值为cv.lasso$lambda.1se

> cv.lasso$lambda.1se
[1] 3.375651

现在,看看这个:

> std(cv.lasso$cvm)
[1] 0.7177808

Wherestd是一个函数,它返回插入其中的值的标准错误。1
的最小值cvm可以找到:

> cv.lasso$cvm[cv.lasso$lambda==cv.lasso$lambda.min]
[1] 42.95009

因此,我们将标准误差添加到 的值中cvm ,我们得到:

> 42.95009+0.7177808
[1] 43.66787

虽然没有lambda对应这个cvm值的值,但是我们可以根据已有的数据有个思路:
在此处输入图像描述

这意味着lambda.1se应该在 0.4784899 和 0.4359821 之间。但事实并非如此。所以,有一种直觉说我在这里犯了一个错误。你能帮我指出这一点吗?


1:定义std

std<-function(x)
  sd(x)/sqrt(length(x))
4

2 回答 2

8

我将添加一个种子,以便可以复制以下结果:

library(glmnet)
library(MASS)
data("Boston")
x = model.matrix(crim~.-1,data=Boston)#-1 for removing the intercept column
y = Boston$crim
set.seed(100)
cv.lasso = cv.glmnet(x,y,type.measure = "mse",alpha=1)

最小交叉验证的 MSE 是min(cv.lasso$cvm) = 43.51256. 对应的 lambda 是cv.lasso$lambda.min = 0.01843874lambda.1secv.lasso$lambda.1se = 3.375651。_ 这对应于交叉验证的 MSE

cv.lasso$cvm[which(cv.lasso$lambda == cv.lasso$lambda.1se)] = 57.5393

我们可以直接从 GLMNET 的输出中访问经过交叉验证的标准错误,如下所示:

cv.lasso$cvsd[which(cv.lasso$lambda == cv.lasso$lambda.min)] = 15.40236

所以交叉验证的 MSE 一个标准错误是

43.51256 + 15.40236 = 58.91492 

这仅略高于上述交叉验证的 MSE lambda.1se(即57.5393)。lambda如果我们在之前查看交叉验证的 MSE lambda.1se,它是:

cv.lasso$cvm[which(cv.lasso$lambda == cv.lasso$lambda.1se)-1] = 59.89079

因此,现在我们可以协调 GLMNET 的输出,让我解释一下为什么使用您的计算没有得到相同的结果:

  1. cv.lasso$cvm包含 的每个值的交叉验证平均 MSE lambda
  2. 当我们说 1 个标准错误时,我们不是在谈论跨 lambda 的标准错误,而是跨给定 lambda 折叠的标准错误。
  3. 继续上述观点,在 处lambda.min,我们有 10 次折叠。我们拟合了 10 个模型并有 10 个样本外 MSE。这 10 个 MSE 的平均值由 给出cv.lasso$cvm[which(cv.lasso$lambda == cv.lasso$lambda.min)]。这 10 个 MSE 的标准偏差由 给出cv.lasso$cvsd[which(cv.lasso$lambda == cv.lasso$lambda.min)]。GLMNET 输出中没有给出的是 10 个 MSE lambda.min。如果我们有这个,那么我们应该能够通过使用上面的公式来复制标准误差。

让我知道这是否有帮助。

编辑:让我们做一个例子,我们预先定义三个折叠

set.seed(100)
folds = sample(1:3, nrow(x), replace = T)
cv.lasso = cv.glmnet(x,y,type.measure = "mse",alpha=1, keep =T, foldid = folds)

注意

> min(cv.lasso$cvm)
[1] 42.76584
> cv.lasso$cvsd[which.min(cv.lasso$cvm)]
[1] 17.89725

(这些与前面的示例不同,因为我们已经定义了自己的折叠)

另请注意,我keep = Tcv.glmnet调用中有一个附加参数。这将返回每个 lambda 的折叠预测。您可以通过执行以下操作提取它们以获得最佳 lambda:

cv.lasso$fit.preval[,which.min(cv.lasso$cvm)]

在我们继续之前,让我们创建一个包含响应、折叠预测和相应折叠的数据框:

library(data.table)
OOSPred = data.table(y = y, 
                     predictions = cv.lasso$fit.preval[,which.min(cv.lasso$cvm)], 
                     folds = folds)

这是前 10 行的预览:

> head(OOSPred, 10)
          y predictions folds
 1: 0.00632  -0.7477977     1
 2: 0.02731  -1.3823830     1
 3: 0.02729  -3.4826143     2
 4: 0.03237  -4.4419795     1
 5: 0.06905  -3.4373021     2
 6: 0.02985  -2.5256505     2
 7: 0.08829   0.7343478     3
 8: 0.14455   1.1262462     2
 9: 0.21124   4.0507847     2
10: 0.17004   0.5859587     1

例如,对于 的情况folds = 1,模型建立在折叠 #2 和 #3 上,然后对折叠 #1 中的观察结果进行预测。我们现在按倍计算 MSE:

OOSPredSum = OOSPred[, list(MSE = mean((y - predictions)^2)), by = folds]

   folds      MSE
1:     1 27.51469
2:     2 75.72847
3:     3 19.93480

最后,我们返回折叠中 MSE 的平均 MSE 和标准误差

> OOSPredSum[, list("Mean MSE" = mean(MSE), "Standard Error" = sd(MSE)/sqrt(3))]
   Mean MSE Standard Error
1: 41.05932       17.47213

GLMNET 可能正在执行加权平均值和标准误差(由每个折叠中的观察数加权),这就是为什么上面的数字接近但不完全匹配的原因。

于 2017-08-26T16:59:00.383 回答
2

我认为程序是:

  1. 对于每个ƛ,它会创建x 个模型(x = nº 的折叠,其中数据集已被拆分以用于交叉验证算法)
  2. 对于每个ƛ和每个模型x,它计算均值(误差)和 sd(误差),因此,均值(x 误差)和 sd(x 误差)
  3. 假设我们有ƛminserrorƛmin(在步骤 2 中计算)。现在,ƛse被定义为“lambda 的最大值,使得误差在最小值的 1 个标准误差之内”。那么ƛse的条件是:

    ƛse in [ ƛmin - seƛmin , ƛmin + seƛmin ]

  4. 然后ƛse = max(ƛ),ƛ 其中满足上述条件。

我可以给你看一个例子:

lasso_cv <- cv.glmnet(x = x, y= endpoint, alpha = 1, lambda = lambdas_to_try,
                  standardize = TRUE, nfolds = 10,type.measure="auc",
                  family="binomial")

请注意,ƛmin是:

lasso_cv$lambda.min
[1] 0.007742637

serrorƛmin是:

serrorlmin <- lasso_cv$cvsd[which(lasso_cv$lambda == lasso_cv$lambda.min)]
serrorlmin

[1] 0.01058009

那么,选择ƛse的范围是:

rang <- c(lasso_cv$lambda.min - serrorlmin,lasso_cv$lambda.min + serrorlmin)
[1] -0.002837457  0.018322731

并找到它:

max(lasso_cv$lambda[lasso_cv$lambda>=rang[1] & lasso_cv$lambda<=rang[2]])
[1] 0.01629751

这个值与ƛse匹配!

lasso_cv$lambda.1se # 0.01629751

我希望它有帮助!

于 2020-01-17T12:49:20.387 回答