β0β0= 0pβ∗Ò 升dβ∗Ò 升dβ∗ñ Ë W ^β∗ñ Ë W ^
编辑:
由于user2763361
我的评论, 我在原始答案中添加了更多详细信息。
从下面的评论中,我收集到user2763361建议补充我的原始答案,以将其转换为可以直接使用(现成的),同时也非常有效的方法。
为了完成第一部分,我将逐步说明我在一个玩具示例中提出的解决方案。为了满足第二部分的要求,我将使用最近的高质量内点求解器来实现。这是因为,相对于试图破解LARS或单纯形算法从非优化开始的优化,使用我可以使用内点方法解决套索问题的库更容易获得我建议的解决方案的高性能实现。标准起点(尽管也可以使用第二个地点)。
请注意,有时候(在较早的书籍中)有人声称,求解线性程序的内点方法要比单纯形方法慢,这可能在很久以前就适用,但今天通常不适用,对于大规模问题当然也不适用(这就是为什么大多数专业图书馆都喜欢cplex
使用内部点算法的原因),而问题至少隐含地涉及到大规模问题。还要注意,我使用的内部点求解器可以完全处理稀疏矩阵,因此我认为LARS不会出现较大的性能差距(使用LARS的最初动机是当时许多流行的LP求解器不能很好地处理稀疏矩阵,并且这些是LASSO问题的特征。
内点算法的(非常)优秀的开源实现ipopt
,在COIN-OR
库中。我将使用的另一个原因ipopt
是它具有R接口ipoptr
。您将在此处找到更详尽的安装指南,下面我给出了将其安装到其中的标准命令ubuntu
。
在中bash
,请执行以下操作:
sudo apt-get install gcc g++ gfortran subversion patch wget
svn co https://projects.coin-or.org/svn/Ipopt/stable/3.11 CoinIpopt
cd ~/CoinIpopt
./configure
make
make install
然后,以root身份R
执行(我假定svn
已~/
默认复制副本文件):
install.packages("~/CoinIpopt/Ipopt/contrib/RInterface",repos=NULL,type="source")
从这里,我给一个小例子(主要是由Jelmer Ypma给出了他的部分玩具例子 R
wraper到ipopt
):
library('ipoptr')
# Experiment parameters.
lambda <- 1 # Level of L1 regularization.
n <- 100 # Number of training examples.
e <- 1 # Std. dev. in noise of outputs.
beta <- c( 0, 0, 2, -4, 0, 0, -1, 3 ) # "True" regression coefficients.
# Set the random number generator seed.
ranseed <- 7
set.seed( ranseed )
# CREATE DATA SET.
# Generate the input vectors from the standard normal, and generate the
# responses from the regression with some additional noise. The variable
# "beta" is the set of true regression coefficients.
m <- length(beta) # Number of features.
A <- matrix( rnorm(n*m), nrow=n, ncol=m ) # The n x m matrix of examples.
noise <- rnorm(n, sd=e) # Noise in outputs.
y <- A %*% beta + noise # The outputs.
# DEFINE LASSO FUNCTIONS
# m, lambda, y, A are all defined in the ipoptr_environment
eval_f <- function(x) {
# separate x in two parts
w <- x[ 1:m ] # parameters
u <- x[ (m+1):(2*m) ]
return( sum( (y - A %*% w)^2 )/2 + lambda*sum(u) )
}
# ------------------------------------------------------------------
eval_grad_f <- function(x) {
w <- x[ 1:m ]
return( c( -t(A) %*% (y - A %*% w),
rep(lambda,m) ) )
}
# ------------------------------------------------------------------
eval_g <- function(x) {
# separate x in two parts
w <- x[ 1:m ] # parameters
u <- x[ (m+1):(2*m) ]
return( c( w + u, u - w ) )
}
eval_jac_g <- function(x) {
# return a vector of 1 and minus 1, since those are the values of the non-zero elements
return( c( rep( 1, 2*m ), rep( c(-1,1), m ) ) )
}
# ------------------------------------------------------------------
# rename lambda so it doesn't cause confusion with lambda in auxdata
eval_h <- function( x, obj_factor, hessian_lambda ) {
H <- t(A) %*% A
H <- unlist( lapply( 1:m, function(i) { H[i,1:i] } ) )
return( obj_factor * H )
}
eval_h_structure <- c( lapply( 1:m, function(x) { return( c(1:x) ) } ),
lapply( 1:m, function(x) { return( c() ) } ) )
# The starting point.
x0 = c( rep(0, m),
rep(1, m) )
# The constraint functions are bounded from below by zero.
constraint_lb = rep( 0, 2*m )
constraint_ub = rep( Inf, 2*m )
ipoptr_opts <- list( "jac_d_constant" = 'yes',
"hessian_constant" = 'yes',
"mu_strategy" = 'adaptive',
"max_iter" = 100,
"tol" = 1e-8 )
# Set up the auxiliary data.
auxdata <- new.env()
auxdata$m <- m
auxdata$A <- A
auxdata$y <- y
auxdata$lambda <- lambda
# COMPUTE SOLUTION WITH IPOPT.
# Compute the L1-regularized maximum likelihood estimator.
print( ipoptr( x0=x0,
eval_f=eval_f,
eval_grad_f=eval_grad_f,
eval_g=eval_g,
eval_jac_g=eval_jac_g,
eval_jac_g_structure=eval_jac_g_structure,
constraint_lb=constraint_lb,
constraint_ub=constraint_ub,
eval_h=eval_h,
eval_h_structure=eval_h_structure,
opts=ipoptr_opts,
ipoptr_environment=auxdata ) )
我的意思是,如果您有新数据,则只需
- 更新(而不是替换)约束矩阵和目标函数向量以说明新的观察结果。
将内部点的起点从
x0 = c(rep(0,m),rep(1,m))
βñ Ë W ^βoldβinitx0
|βinit−βnew|1>|βnew−βold|1(1)
βnewβoldβinitnp
至于不等式(1)成立的条件,它们是:
- λ|βOLS|1pn
- 当新的观察结果在病理上没有影响时,例如当它们与产生现有数据的随机过程一致时。
- 当更新的大小相对于现有数据的大小较小时。