Moo*_*ter 3 r lasso-regression cross-validation
在函数的文档中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)
Run Code Online (Sandbox Code Playgroud)
而出来的价值cv.lasso$lambda.min是:
> cv.lasso$lambda.min
[1] 0.05630926
Run Code Online (Sandbox Code Playgroud)
并且,值cv.lasso$lambda.1se是:
> cv.lasso$lambda.1se
[1] 3.375651
Run Code Online (Sandbox Code Playgroud)
现在,看看这个:
> std(cv.lasso$cvm)
[1] 0.7177808
Run Code Online (Sandbox Code Playgroud)
std函数是哪里,它返回插入其中的值的标准错误。1
的最小值cvm可以找到:
> cv.lasso$cvm[cv.lasso$lambda==cv.lasso$lambda.min]
[1] 42.95009
Run Code Online (Sandbox Code Playgroud)
因此,我们将标准误差添加到的值,cvm 得到:
> 42.95009+0.7177808
[1] 43.66787
Run Code Online (Sandbox Code Playgroud)
即使没有lambda与此值对应的cvm值,我们也可以根据现有数据得出一个想法:

这意味着lambda.1se应该在0.4784899和0.4359821之间。但这绝对不是。因此,有种直觉表明我在这里犯了一个错误。你能帮我指出这一点吗?
1:定义std:
std<-function(x)
sd(x)/sqrt(length(x))
Run Code Online (Sandbox Code Playgroud)
我将添加一个种子,以便可以复制以下结果:
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)
Run Code Online (Sandbox Code Playgroud)
交叉验证的最小MSE为min(cv.lasso$cvm) = 43.51256。对应的lambda为cv.lasso$lambda.min = 0.01843874。该lambda.1se是cv.lasso$lambda.1se = 3.375651。这对应于交叉验证的MSE
cv.lasso$cvm[which(cv.lasso$lambda == cv.lasso$lambda.1se)] = 57.5393
Run Code Online (Sandbox Code Playgroud)
我们可以直接从GLMNET的输出访问经过交叉验证的标准错误,如下所示:
cv.lasso$cvsd[which(cv.lasso$lambda == cv.lasso$lambda.min)] = 15.40236
Run Code Online (Sandbox Code Playgroud)
因此,交叉验证的MSE一个标准错误是
43.51256 + 15.40236 = 58.91492
Run Code Online (Sandbox Code Playgroud)
这仅仅是稍微在比交叉验证MSE更高lambda.1se以上(即57.5393)。如果我们在lambda之前查看交叉验证的MSE lambda.1se,则为:
cv.lasso$cvm[which(cv.lasso$lambda == cv.lasso$lambda.1se)-1] = 59.89079
Run Code Online (Sandbox Code Playgroud)
现在,我们可以协调GLMNET的输出了,让我解释一下为什么使用您的计算不能得到相同的结果:
cv.lasso$cvm包含的每个值的经过交叉验证的平均MSE lambda。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)
Run Code Online (Sandbox Code Playgroud)
注意
> min(cv.lasso$cvm)
[1] 42.76584
> cv.lasso$cvsd[which.min(cv.lasso$cvm)]
[1] 17.89725
Run Code Online (Sandbox Code Playgroud)
(这些与上面的示例不同,因为我们定义了自己的折叠)
还要注意,我keep = T在cv.glmnet调用中还有一个附加参数。这将返回每个lambda的折叠预测。您可以通过执行以下操作提取它们以获得最佳的lambda:
cv.lasso$fit.preval[,which.min(cv.lasso$cvm)]
Run Code Online (Sandbox Code Playgroud)
在继续之前,让我们创建一个包含响应,折叠预测以及相应折叠的数据框:
library(data.table)
OOSPred = data.table(y = y,
predictions = cv.lasso$fit.preval[,which.min(cv.lasso$cvm)],
folds = folds)
Run Code Online (Sandbox Code Playgroud)
这是前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
Run Code Online (Sandbox Code Playgroud)
例如,对于的情况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
Run Code Online (Sandbox Code Playgroud)
最后,我们返回所有MSE的平均MSE和标准误
> OOSPredSum[, list("Mean MSE" = mean(MSE), "Standard Error" = sd(MSE)/sqrt(3))]
Mean MSE Standard Error
1: 41.05932 17.47213
Run Code Online (Sandbox Code Playgroud)
GLMNET可能正在执行加权均值和标准误(通过每次折叠的观察数加权),这就是为什么收盘价上方的数字不完全匹配的原因。