为什么glmnet岭回归给我的答案与手动计算不同?


28

我正在使用glmnet计算岭回归估计值。我得到了一些结果,使我对glmnet确实在做我认为做的事情感到怀疑。为了验证这一点,我编写了一个简单的R脚本,在其中比较了Solve和glmnet中进行的岭回归的结果,两者之间的区别非常明显:

n    <- 1000
p.   <-  100
X.   <- matrix(rnorm(n*p,0,1),n,p)
beta <- rnorm(p,0,1)
Y    <- X%*%beta+rnorm(n,0,0.5)

beta1 <- solve(t(X)%*%X+5*diag(p),t(X)%*%Y)
beta2 <- glmnet(X,Y, alpha=0, lambda=10, intercept=FALSE, standardize=FALSE, 
                family="gaussian")$beta@x
beta1-beta2

差异的范数通常约为20,这不可能是由于数值算法不同而引起的,我一定做错了。glmnet为了获得与ridge相同的结果,我必须设置哪些设置?


1
你看到这个问题了吗?
cdeterman 2014年

1
是的,但是使用规范化仍然无法获得相同的结果。
约翰

那你能发表你的代码吗?
shadowtalker 2014年

我刚刚遇到了同样的问题!a = data.frame(a =抖动(1:10),b =抖动(1:10),c =抖动(1:10),d =抖动(1:10),e =抖动(1:10) ,f = jitter(1:10),g = sample(jitter(1:10)),y = seq(10,100,10)); coef(lm.ridge(y〜a + b + c + d + e + f + g,a,lambda = 2.57)); coef(glmnet(as.matrix(a [,1:7]),a $ y,family =“ gaussian”,alpha = 0,lambda = 2.57 / 10))结果相差很多,并且在我为glmnet使用了更高的lambda。
a11msp

有趣的。系数似乎相差大约10
倍。– tomka

Answers:


27

您观察到的差异是由于GLMNET在其目标函数中使用的观察数N的额外除法,以及通过其样本标准偏差对Y的隐式标准化,如下所示。

1个2ñÿsÿ-Xβ22+λβ22/2

在这里我们使用代替为, 1 /ñ - 1 小号Ŷ 小号Ŷ = Σ ÿ - ˉ ÿ21个/ñ1个/ñ-1个sÿ

sÿ=一世ÿ一世-ÿ¯2ñ

通过对beta进行微分,将等式设置为零,

XŤXβ-XŤÿsÿ+ñλβ=0

然后求解beta,我们得到了估算值,

βG大号中号ñËŤ=XŤX+ñλ一世p-1个XŤÿsÿ

为了恢复对Y的原始度量的估计(及其相应的惩罚),GLMNET将估计和lambda乘以并将这些结果返回给用户,sÿ

λùÑ小号d=šÿλ

β^G大号中号ñËŤ=sÿβG大号中号ñËŤ=XŤX+ñλ一世p-1个XŤÿ
λüñsŤd=sÿλ

将此解决方案与岭回归的标准推导进行比较。

β^=XŤX+λ一世p-1个XŤÿ

请注意,的缩放系数为N。此外,当使用or 函数时,代价将隐式缩放为。就是说,当我们使用这些函数获得某个的系数估计时,我们正在有效地获得估计。1 / 小号ý λ * λ = λ * / 小号ÿλpredict()coef()1个/sÿλλ=λ/sÿ

基于这些观察,需要将的因数缩放到GLMNET中使用的惩罚。sÿ/ñ

set.seed(123)

n    <- 1000
p   <-  100
X   <- matrix(rnorm(n*p,0,1),n,p)
beta <- rnorm(p,0,1)
Y    <- X%*%beta+rnorm(n,0,0.5)

sd_y <- sqrt(var(Y)*(n-1)/n)[1,1]

beta1 <- solve(t(X)%*%X+10*diag(p),t(X)%*%(Y))[,1]

fit_glmnet <- glmnet(X,Y, alpha=0, standardize = F, intercept = FALSE, thresh = 1e-20)
beta2 <- as.vector(coef(fit_glmnet, s = sd_y*10/n, exact = TRUE))[-1]
cbind(beta1[1:10], beta2[1:10])

           [,1]        [,2]
[1,]  0.23793862  0.23793862
[2,]  1.81859695  1.81859695
[3,] -0.06000195 -0.06000195
[4,] -0.04958695 -0.04958695
[5,]  0.41870613  0.41870613
[6,]  1.30244151  1.30244151
[7,]  0.06566168  0.06566168
[8,]  0.44634038  0.44634038
[9,]  0.86477108  0.86477108
[10,] -2.47535340 -2.47535340

结果概括为包含截距和标准化的X变量。我们修改了标准化的X矩阵以包括一列1和对角矩阵,使其在[1,1]位置具有一个附加的零项(即,不对截距进行惩罚)。然后,您可以通过它们各自的样本标准偏差来使估算值标准化(再次确保在计算标准偏差时使用1 / n)。

β^Ĵ=βĴsXĴ

β^0=β0-X¯Ťβ^
mean_x <- colMeans(X)
sd_x <- sqrt(apply(X,2,var)*(n-1)/n)
X_scaled <- matrix(NA, nrow = n, ncol = p)
for(i in 1:p){
    X_scaled[,i] <- (X[,i] - mean_x[i])/sd_x[i] 
}
X_scaled_ones <- cbind(rep(1,n), X_scaled)

beta3 <- solve(t(X_scaled_ones)%*%X_scaled_ones+1000*diag(x = c(0, rep(1,p))),t(X_scaled_ones)%*%(Y))[,1]
beta3 <- c(beta3[1] - crossprod(mean_x,beta3[-1]/sd_x), beta3[-1]/sd_x)

fit_glmnet2 <- glmnet(X,Y, alpha=0, thresh = 1e-20)
beta4 <- as.vector(coef(fit_glmnet2, s = sd_y*1000/n, exact = TRUE))

cbind(beta3[1:10], beta4[1:10])
             [,1]        [,2]
 [1,]  0.24534485  0.24534485
 [2,]  0.17661130  0.17661130
 [3,]  0.86993230  0.86993230
 [4,] -0.12449217 -0.12449217
 [5,] -0.06410361 -0.06410361
 [6,]  0.17568987  0.17568987
 [7,]  0.59773230  0.59773230
 [8,]  0.06594704  0.06594704
 [9,]  0.22860655  0.22860655
[10,]  0.33254206  0.33254206

添加了代码以显示标准X且没有拦截:

set.seed(123)

n <- 1000
p <-  100
X <- matrix(rnorm(n*p,0,1),n,p)
beta <- rnorm(p,0,1)
Y <- X%*%beta+rnorm(n,0,0.5)

sd_y <- sqrt(var(Y)*(n-1)/n)[1,1]

mean_x <- colMeans(X)
sd_x <- sqrt(apply(X,2,var)*(n-1)/n)

X_scaled <- matrix(NA, nrow = n, ncol = p)
for(i in 1:p){
    X_scaled[,i] <- (X[,i] - mean_x[i])/sd_x[i] 
}

beta1 <- solve(t(X_scaled)%*%X_scaled+10*diag(p),t(X_scaled)%*%(Y))[,1]

fit_glmnet <- glmnet(X_scaled,Y, alpha=0, standardize = F, intercept = 
FALSE, thresh = 1e-20)
beta2 <- as.vector(coef(fit_glmnet, s = sd_y*10/n, exact = TRUE))[-1]
cbind(beta1[1:10], beta2[1:10])

             [,1]        [,2]
 [1,]  0.23560948  0.23560948
 [2,]  1.83469846  1.83469846
 [3,] -0.05827086 -0.05827086
 [4,] -0.04927314 -0.04927314
 [5,]  0.41871870  0.41871870
 [6,]  1.28969361  1.28969361
 [7,]  0.06552927  0.06552927
 [8,]  0.44576008  0.44576008
 [9,]  0.90156795  0.90156795
[10,] -2.43163420 -2.43163420

3
+6。欢迎来到简历,并感谢您以如此清晰的方式回答这个老问题。
变形虫说莫妮卡(Reonica Monica)

1
在的解决方案中,它应该是单位矩阵而不是,对吗?βββ
user1769197

我还注意到,在第二部分中,您说的是“结果推广到包含截距和标准化X变量”;对于这一部分,如果排除了截距,则按照相同的计算,glmnet的结果将不同于手动计算。
user1769197

正确,我已根据需要更新了身份矩阵代替的解决方案。我检查了标准X的解决方案,没有任何拦截,但仍然获得了相同的结果(请参见上面的其他代码)。β
skijunkie

3

根据https://web.stanford.edu/~hastie/glmnet/glmnet_alpha.html,当家庭gaussianglmnet()应将

(1)1个2ñ一世=1个ñÿ一世-β0-X一世Ťβ2+λĴ=1个pα|βĴ|+1个-αβĴ2/2

当使用标准化glmnet(x, y, alpha=1)的列来拟合套索时,报告的惩罚的解决方案是最小化 但是,至少在中,当用于拟合岭回归时,所报告的惩罚的解决方案是最小化 其中是的标准偏差。在这里,惩罚应该报告为。Xλ

1个2ñ一世=1个ñÿ一世-β0-X一世Ťβ2+λĴ=1个p|βĴ|
glmnet_2.0-13glmnet(x, y, alpha=0)λ
1个2ñ一世=1个ñÿ一世-β0-X一世Ťβ2+λ1个2sÿĴ=1个pβĴ2
sÿÿλ/sÿ

可能发生的情况是该函数首先将标准化为,然后最小化 ,实际上是将最小化 或等效地,将最小化 ÿÿ0

(2)1个2ñ一世=1个ñÿ0一世-X一世Ťγ2+ηĴ=1个pα|γĴ|+1个-αγĴ2/2
1个2ñsÿ2一世=1个ñÿ一世-β0-X一世Ťβ2+ηαsÿĴ=1个p|βĴ|+η1个-α2sÿ2Ĵ=1个pβĴ2
1个2ñ一世=1个ñÿ一世-β0-X一世Ťβ2+ηsÿαĴ=1个p|βĴ|+η1个-αĴ=1个pβĴ2/2。

对于套索(),将缩小以报告惩罚,因为有意义。然后,对于所有,必须将报告为惩罚,以保持结果的连续性。这可能是导致上述问题的原因。部分原因是使用(2)求解(1)。仅当或,问题(1)和(2)之间才存在某些等价关系(即,(1)中的与(2)中的之间的对应关系)。对于任何其他α=1个ηηsÿαηsÿαα=0α=1个ληα01个,问题(1)和(2)是两个不同的优化问题,并且(1)中的和(2)中的没有一对一的对应关系。λη


1
我看不出您的答案与上一个答案有何不同。你能解释一下吗?
Firebug

1
@Firebug我想阐明为什么函数以这种方式报告lambda,仅从岭回归的角度来看,这似乎是不自然的,但从整个光谱的角度来看,这是有意义的(或必须是这种方式)包括山脊和套索。
春丽
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.