我不认为你在代码中犯了错误。这是解释输出的问题。
Lasso 没有指出哪些个体回归变量比其他回归变量“更具预测性”。它只是具有将系数估计为零的内在趋势。惩罚系数越大log(λ)就是,这种倾向越大。
您的交叉验证图显示,随着越来越多的系数被强制为零,该模型在预测已从数据集中随机删除的值子集方面做得越来越好。当所有系数都为零时达到最佳交叉验证预测误差(此处测量为“二项式偏差”)时,您应该怀疑回归变量的任何子集的线性组合都可能对预测结果有用。
您可以通过生成独立于所有回归变量的随机响应并将您的拟合程序应用于它们来验证这一点。这是模拟数据集的快速方法:
n <- 570
k <- 338
set.seed(17)
X <- data.frame(matrix(floor(runif(n*(k+1), 0, 2)), nrow=n,
dimnames=list(1:n, c("y", paste0("x", 1:k)))))
数据框X
有一个名为“y”的随机二进制列和 338 个其他二进制列(其名称无关紧要)。我使用你的方法对这些变量进行回归“y”,但是——只是要小心——我确保响应向量y
和模型矩阵x
匹配(如果数据中有任何缺失值,他们可能不会这样做) :
f <- y ~ . - 1 # cv.glmnet will include its own intercept
M <- model.frame(f, X)
x <- model.matrix(f, M)
y <- model.extract(M, "response")
fit <- cv.glmnet(x, y, family="binomial")
结果与您的结果非常相似:
plot(fit)
事实上,对于这些完全随机的数据,Lasso 仍然返回九个非零系数估计值(尽管我们通过构造知道正确的值都是零)。但我们不应该期望完美。此外,由于拟合是基于随机删除数据子集以进行交叉验证,因此您通常不会从一次运行到下一次得到相同的输出。在此示例中,第二次调用cv.glmnet
生成只有一个非零系数的拟合。因此,如果您有时间,最好多次重新运行拟合过程并跟踪哪些系数估计值始终非零。对于这些包含数百个回归变量的数据,这将需要几分钟才能再重复 9 次。
sim <- cbind(as.numeric(coef(fit)),
replicate(9, as.numeric(coef(cv.glmnet(x, y, family="binomial")))))
plot(1:k, rowMeans(sim[-1,] != 0) + runif(k, -0.025, 0.025),
xlab="Coefficient Index", ylab="Frequency not zero (jittered)",
main="Results of Repeated Cross-Validated Lasso Fits")
这些回归变量中有八个在大约一半的拟合中具有非零估计值;其余的从来没有非零估计。这表明即使系数本身确实为零,Lasso 仍将在多大程度上包括非零系数估计。