我正在Python / C模块中实现Ridge回归,并且遇到了这个“小”问题。我的想法是,我想或多或少地等距采样有效自由度(例如“统计学习的要素”上第65页的图),即样本:
如标题所示,那么,我需要以一定比例从到采样,以便(大概)对进行采样,例如从到间隔为 ...有没有简单的方法可以做到这一点?我曾想过使用牛顿-拉夫森方法为每个解方程,但这会增加过多的迭代,特别是当大时。有什么建议么?
我正在Python / C模块中实现Ridge回归,并且遇到了这个“小”问题。我的想法是,我想或多或少地等距采样有效自由度(例如“统计学习的要素”上第65页的图),即样本:
如标题所示,那么,我需要以一定比例从到采样,以便(大概)对进行采样,例如从到间隔为 ...有没有简单的方法可以做到这一点?我曾想过使用牛顿-拉夫森方法为每个解方程,但这会增加过多的迭代,特别是当大时。有什么建议么?
Answers:
这是一个很长的答案。因此,让我们在这里给出一个简短的版本。
R
没有进行任何优化尝试的脑残代码也可以计算p = 100的大小为100的网格在几秒钟内达到 000。精心编写的代码至少可以减少2-3个数量级。C
为保证单调收敛,下面给出了两种方案。一个使用如下所示的边界,这似乎有时可以帮助保存一两个牛顿步。
示例:和大小为100的自由度的统一网格。特征值是帕累托分布的,因此高度偏斜。下表列出了查找每个根的牛顿步骤数。
# Table of Newton iterations per root.
# Without using lower-bound check.
1 3 4 5 6
1 28 65 5 1
# Table with lower-bound check.
1 2 3
1 14 85
不会有此一封闭形式解,在一般情况,但也有是很多结构当前可用于生产使用标准求根方法是非常有效和安全的解决方案。
在深入研究事物之前,让我们收集函数d f(λ )= p ∑ i = 1 d 2 i的一些性质和结果。
特性0:是λ的有理函数。(这是从定义显而易见。)
后果0:无一般代数解将存在用于找到根d ˚F(λ )- ý = 0。这是因为存在度为p的等效多项式求根问题,因此,如果p不是非常小(即小于5),则不会存在一般解。因此,我们需要一种数值方法。
属性1:函数是凸的和减小λ ≥ 0。(取导数。)
结果1(a):在这种情况下,牛顿的寻根算法将表现得非常好。让ÿ是所需的自由度,并且λ 0对应的根,即ÿ = d ˚F(λ 0)。特别是,如果我们在开始时任何初始值λ 1 < λ 0(因此,d ˚F(λ 1
),则牛顿步迭代的序列 λ 1,λ 2,...将收敛单调的独特的解决方案 λ 0。
结果如图1(b) :此外,如果我们用开出 λ 1 > λ 0,则第一步骤将产生 λ 2 ≤ λ 0
,从那里开始,它将根据先前的结果单调增加到解(请参见下面的警告)。直观地看,这最后的事实如下,因为如果我们开始到根权,衍生为“太”浅由于凸等第一牛顿步将带我们的地方,左侧是根。注意:由于d f通常不为负λ凸,因此有充分的理由倾向于选择从所需根的左侧开始。否则,我们需要仔细检查牛顿步长是否未导致估计根的负值,这可能会使我们处于d f的非凸部分。
结果如图1(c) :一旦我们已经找到了根一些,然后从一些搜索根ÿ 2 < Ý 1,采用λ 1,使得d ˚F(λ 1)= ÿ 1作为我们的初始猜测保证我们从第二个根的左边开始。因此,从那里开始,我们的收敛被保证是单调的。
特性2:存在合理的界限以给出“安全”的起点。使用凸性参数和詹森不等式,我们有以下边界 结果2:这告诉我们,根 λ 0满足 d ˚F(λ 0)= ÿ服从 1
假设所有i的。如果不是这种情况,则结合相同保持通过考虑只在正d 我和更换p由正的数量d 我。NB:由于d ˚F(0 )= p假设所有d 我 > 0,则ÿ ∈ (0 ,p ],从那里边界总是非平凡(例如,下限是总是非负的)。
这里是一个“典型”的例子的曲线图与p = 400。我们已经为自由度叠加了一个大小为10的网格。这些是图中的水平线。垂直的绿线对应于(⋆ )中的下限。
一个算法和一些R代码示例
给定期望的自由度 in (0 ,p ]的网格时,一种非常有效的算法是按照降序对它们进行排序,然后使用前一个根作为该根的起点,依次找到每个根。我们可以通过检查每个根是否大于下一个根的下限来进一步优化,如果不是,则可以从下限开始下一个迭代。
这是中的一些示例代码R
,未尝试对其进行优化。如下图所示,尽管R
礼貌地说,尽管循环令人恐惧,可怕,极其缓慢,但它仍然相当快。
# Newton's step for finding solutions to regularization dof.
dof <- function(lambda, d) { sum(1/(1+lambda / (d[d>0])^2)) }
dof.prime <- function(lambda, d) { -sum(1/(d[d>0]+lambda / d[d>0])^2) }
newton.step <- function(lambda, y, d)
{ lambda - (dof(lambda,d)-y)/dof.prime(lambda,d) }
# Full Newton step; Finds the root of y = dof(lambda, d).
newton <- function(y, d, lambda = NA, tol=1e-10, smart.start=T)
{
if( is.na(lambda) || smart.start )
lambda <- max(ifelse(is.na(lambda),0,lambda), (sum(d>0)/y-1)/mean(1/(d[d>0])^2))
iter <- 0
yn <- Inf
while( abs(y-yn) > tol )
{
lambda <- max(0, newton.step(lambda, y, d)) # max = pedantically safe
yn <- dof(lambda,d)
iter = iter + 1
}
return(list(lambda=lambda, dof=y, iter=iter, err=abs(y-yn)))
}
newton.grid <- function(ygrid, d, lambda=NA, tol=1e-10, smart.start=TRUE)
{
p <- sum(d>0)
if( any(d < 0) || all(d==0) || any(ygrid > p)
|| any(ygrid <= 0) || (!is.na(lambda) && lambda < 0) )
stop("Don't try to fool me. That's not nice. Give me valid inputs, please.")
ygrid <- sort(ygrid, decreasing=TRUE)
out <- data.frame()
lambda <- NA
for(y in ygrid)
{
out <- rbind(out, newton(y,d,lambda, smart.start=smart.start))
lambda <- out$lambda[nrow(out)]
}
out
}
样本函数调用
set.seed(17)
p <- 100000
d <- sqrt(sort(exp(rexp(p, 10)),decr=T))
ygrid <- p*(1:100)/100
# Should take ten seconds or so.
out <- newton.grid(ygrid,d)
根据以下来源,可能的替代方法似乎是:
封闭式解决方案:
如果您使用正态方程作为求解器或计算方差-协方差估计,则您应该已经计算了 。如果您要估算各个参数的系数,则此方法最有效。
资料来源:https : //onlinecourses.science.psu.edu/stat857/node/155