如何执行非负岭回归?


10

如何执行非负岭回归?非负套索可在中找到scikit-learn,但对于ridge,我无法强制beta的非负性,实际上,我得到的是负系数。有人知道为什么吗?

另外,我可以按照规则的最小二乘法实施ridge吗?将此问题移至另一个问题:我可以根据OLS回归实现岭回归吗?


1
这里有两个非常正交的问题,我考虑将“我可以用最小二乘法实现岭”作为一个单独的问题。
马修·德鲁里

Answers:


8

对“ 有人知道这是为什么吗? ” 的相当反气候的答案是,根本没有人足够在意实施非负岭回归例程。主要原因之一是人们已经开始实现 非负弹性网例程(例如herehere)。弹性网包括脊回归作为一种特殊情况(本质上是将LASSO部分设置为零权重)。这些作品相对较新,因此尚未纳入scikit-learn或类似的通用软件包中。您可能想咨询这些论文的作者以获得代码。

编辑:

正如@amoeba和我在评论中讨论的那样,此方法的实际实现相对简单。说一个人有以下回归问题:

ÿ=2X1个-X2+ϵϵñ00.22

其中X 2均为标准法线如:X pÑ 0 1 。注意,我使用标准化的预测变量,因此以后无需进行标准化。为简单起见,我也不包含拦截器。我们可以使用标准线性回归立即解决此回归问题。因此在R中应该是这样的:X1个X2Xpñ01个

rm(list = ls()); 
library(MASS); 
set.seed(123);
N = 1e6;
x1 = rnorm(N)
x2 = rnorm(N)
y = 2 * x1 - 1 * x2 + rnorm(N,sd = 0.2)

simpleLR = lm(y ~ -1 + x1 + x2 )
matrixX = model.matrix(simpleLR); # This is close to standardised
vectorY = y
all.equal(coef(simpleLR), qr.solve(matrixX, vectorY), tolerance = 1e-7)  # TRUE

注意最后一行。几乎所有的线性回归程序都使用QR分解来估计。我们想对我们的岭回归问题使用相同的方法。此时,请阅读@whuber的这篇文章;我们将实施正是这一程序。简而言之,我们将使用扩充我们的原始设计矩阵XβX对角矩阵和我们的响应向量ýp为零。这样,我们就能够重新表达原岭回归问题X牛逼X+λ - 1 X牛逼Ÿ ˉ X牛逼 ˉ X - 1 ˉ X牛逼 ˉ Ÿ ¯λ一世pÿpXŤX+λ一世-1个XŤÿX¯ŤX¯-1个X¯Ťÿ¯¯象征增强版本。还要从这些注释中检查幻灯片18-19 的完整性,我发现它们非常简单。因此,在R中,我们需要以下内容:

myLambda = 100;  
simpleRR = lm.ridge(y ~ -1 + x1 + x2, lambda = myLambda)
newVecY = c(vectorY, rep(0, 2))
newMatX = rbind(matrixX, sqrt(myLambda) * diag(2))
all.equal(coef(simpleRR), qr.solve(newMatX, newVecY), tolerance = 1e-7)  # TRUE

β||ÿ¯-X¯β||22

myRSS <- function(X,y,b){ return( sum( (y - X%*%b)^2 ) ) }
bfgsOptim = optim(myRSS, par = c(1,1), X = newMatX, y= newVecY, 
                  method = 'L-BFGS-B')
all.equal(coef(simpleRR), bfgsOptim$par, check.attributes = FALSE, 
          tolerance = 1e-7) # TRUE

如预期的那样再次起作用。所以现在我们只想:其中。这只是相同的优化问题,但受到约束,因此解决方案是非负的。β||ÿ¯-X¯β||22β0

bfgsOptimConst = optim(myRSS, par = c(1,1), X=newMatX, y= newVecY, 
                       method = 'L-BFGS-B', lower = c(0,0))
all(bfgsOptimConst$par >=0)  # TRUE
(bfgsOptimConst$par) # 2.000504 0.000000

这表明原始的非负岭回归任务可以通过重新公式化为简单的约束优化问题来解决。一些警告:

  1. 我(实际上)使用了标准化的预测变量。您将需要自己考虑归一化。
  2. 对于截距的规范化也有同样的事情。
  3. 我用optimL-BFGS-B参数。它是接受边界的最原始的R解算器。我相信您会找到许多更好的求解器。
  4. 一般而言,线性最小二乘问题被提出为二次优化任务。这对这篇文章来说是一个过大的杀伤力,但请记住,如果需要,您可以提高速度。
  5. 如评论中所述,您可以跳过岭回归作为增强线性回归部分,而直接将岭成本函数编码为优化问题。这将简单得多,并且此帖子显着减少。为了争辩,我也附上了第二个解决方案。
  6. 我对Python的讨论并不全面,但是基本上您可以使用NumPy的linalg.solve和SciPy的optimize函数来复制此工作。
  7. 要选择超参数等,您只需执行通常的CV步骤(无论如何);没有什么变化。λ

第5点的代码:

myRidgeRSS <- function(X,y,b, lambda){ 
                return( sum( (y - X%*%b)^2 ) + lambda * sum(b^2) ) 
              }
bfgsOptimConst2 = optim(myRidgeRSS, par = c(1,1), X = matrixX, y = vectorY,
                        method = 'L-BFGS-B', lower = c(0,0), lambda = myLambda)
all(bfgsOptimConst2$par >0) # TRUE
(bfgsOptimConst2$par) # 2.000504 0.000000

1
这有点误导。非负岭回归很容易实现:可以像对扩展数据进行常规回归一样重写岭回归(请参阅stats.stackexchange.com/questions/203687的注释),然后使用非负回归例程。
变形虫

我同意实施起来很简单(+1)。(我也赞成您和Glen在其他主题上的评论)。问题是,为什么不实施,而不是困难。在此问题上,我强烈怀疑直接将这个NNRR任务表述为优化问题,甚至比先将其表述为扩展数据回归然后使用Quad更为简单。编 优化以解决此回归问题。我没有在回答中说这一点,因为它会在实现部分中冒险。
usεr11852

或仅以斯坦语编写。
Sycorax说恢复莫妮卡

啊好吧; 我将Q理解为主要询问如何做非负岭(仅询问为什么未通过传递实现)。我什至进行了编辑,以使其成为标题。无论如何,在我看来,如何做是一个更有趣的问题。如果您可以通过解释如何实现非负脊的方式来更新您的答案,我认为这对将来的读者将非常有用(并且我很乐意赞成:)。
变形虫

1
太好了,我稍后再做(我没注意到新标题,对此感到抱歉)。我可能会以OLS /伪观察的方式给出实现,因此我们也回答了另一个问题。
usεr11852

4

R包glmnet实现了弹性网,因此套索和山脊允许这样做。使用参数lower.limitsupper.limits,您可以分别为每个重量设置一个最小值或最大值,因此,如果将下限设置为0,它将执行非负弹性网(套索/山脊)。

还有一个python包装器https://pypi.python.org/pypi/glmnet/2.0.0


2

回想一下我们正在尝试解决:

最小化X一个X-ÿ22+λX22圣 X>0

等效于:

最小化X一个X-ÿ22+λX一世X圣 X>0

还有更多的代数:

最小化XXŤ一个Ť一个+λ一世X+-2一个ŤÿŤX圣 X>0

伪python中的解决方案只需执行以下操作:

Q = A'A + lambda*I
c = - A'y
x,_ = scipy.optimize.nnls(Q,c)

ķX[RķX

以获得更一般的答案。


行c =-A'y不应该读c = A'y吗?我认为这是正确的,尽管应该注意该解决方案与scipy.optimize.nnls(newMatX,newVecY)略有不同,在scipy.optimize.nnls(newMatX,newVecY)中,X是X行,对角矩阵是对角矩阵,其中sqrt(lambda)沿对角线,NewVecY是Y用nvar零增强。我认为您提到的解决方案是正确的...
Tom Wenseleers
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.