lambda.1se 不在错误的一个标准错误中

lambda.1se not being in one standard error of the error

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

lambda.1se :
largest value of lambda such that error is within 1 standard error of the minimum.

这意味着 lambda.1se 给出了 lambda,它给出了一个误差 (cvm),距离最小误差只有一个标准误差。

所以,在尝试检查这个事实时:
MASS中有一个数据集Boston。我使用套索执行了交叉验证:

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

其中 std 是一个函数,即 returns 插入其中的值的标准误差。1
cvm的最小值可以求得为:

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

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

> 42.95009+0.7177808
[1] 43.66787

这个cvm值虽然没有对应的lambda值,但是我们可以根据已有的数据来推测一下:

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


1:std的定义:

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

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

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 

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

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

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

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

如果有帮助请告诉我。

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

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

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

另请注意,我在 cv.glmnet 调用中有一个附加参数 keep = T。这 return 是每个 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

最后,我们return MSE 的平均 MSE 和标准误差

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

GLMNET 可能正在执行加权均值和标准误差(由每次折叠中的观察次数加权),这就是为什么收盘价以上的数字并不完全匹配。

我认为程序是:

  1. 对于每个 ƛ,它创建 x 个模型(x = nº of folds 其中数据集已被分割用于交叉验证算法)
  2. 对于每个 ƛ 和每个模型 x,它计算均值(误差)和 sd(误差),因此,均值( x 错误)和 sd(x 错误)
  3. 假设我们有 ƛminserrorƛmin(在步骤 2 中计算)。现在,ƛse 定义为 "largest value of lambda such that error is within 1 standard error of the minimum"。那么ƛse的条件是:

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

  4. Then ƛ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

希望对您有所帮助!