如何执行非负岭回归?非负套索可在中找到scikit-learn
,但对于ridge,我无法强制beta的非负性,实际上,我得到的是负系数。有人知道为什么吗?
另外,我可以按照规则的最小二乘法实施ridge吗?将此问题移至另一个问题:我可以根据OLS回归实现岭回归吗?
如何执行非负岭回归?非负套索可在中找到scikit-learn
,但对于ridge,我无法强制beta的非负性,实际上,我得到的是负系数。有人知道为什么吗?
另外,我可以按照规则的最小二乘法实施ridge吗?将此问题移至另一个问题:我可以根据OLS回归实现岭回归吗?
Answers:
对“ 有人知道这是为什么吗? ” 的相当反气候的答案是,根本没有人足够在意实施非负岭回归例程。主要原因之一是人们已经开始实现 非负弹性网例程(例如here和here)。弹性网包括脊回归作为一种特殊情况(本质上是将LASSO部分设置为零权重)。这些作品相对较新,因此尚未纳入scikit-learn或类似的通用软件包中。您可能想咨询这些论文的作者以获得代码。
编辑:
正如@amoeba和我在评论中讨论的那样,此方法的实际实现相对简单。说一个人有以下回归问题:
其中和X 2均为标准法线如:X p〜Ñ (0 ,1 )。注意,我使用标准化的预测变量,因此以后无需进行标准化。为简单起见,我也不包含拦截器。我们可以使用标准线性回归立即解决此回归问题。因此在R中应该是这样的:
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对角矩阵和我们的响应向量ý与p为零。这样,我们就能够重新表达原岭回归问题(X牛逼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
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
如预期的那样再次起作用。所以现在我们只想:其中。这只是相同的优化问题,但受到约束,因此解决方案是非负的。
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
这表明原始的非负岭回归任务可以通过重新公式化为简单的约束优化问题来解决。一些警告:
optim
的L-BFGS-B参数。它是接受边界的最原始的R解算器。我相信您会找到许多更好的求解器。第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
R包glmnet实现了弹性网,因此套索和山脊允许这样做。使用参数lower.limits
和upper.limits
,您可以分别为每个重量设置一个最小值或最大值,因此,如果将下限设置为0,它将执行非负弹性网(套索/山脊)。
还有一个python包装器https://pypi.python.org/pypi/glmnet/2.0.0
回想一下我们正在尝试解决:
等效于:
还有更多的代数:
伪python中的解决方案只需执行以下操作:
Q = A'A + lambda*I
c = - A'y
x,_ = scipy.optimize.nnls(Q,c)
以获得更一般的答案。