O laço é ajustado através do LARS (um processo iterativo, que começa com uma estimativa inicial ). Por padrão β 0 = 0 p mas você pode mudar isso em mais de implementação (e substituí-lo pelo ótimo β * o l d você já tem). O mais próximo β * o l d é p * n e w , quanto menor o número de LARS iteração você terá que passo para chegar ao p * n e w .β0 0β0 0= 0pβ∗o l dβ∗ol dβ∗n e wβ∗n e w
EDITAR:
Devido aos comentários de, user2763361
eu adiciono mais detalhes à minha resposta original.
A partir dos comentários abaixo, concluo que o user2763361 sugere complementar minha resposta original para transformá-la em uma que possa ser usada diretamente (fora das prateleiras), além de ser muito eficiente.
Para fazer a primeira parte, ilustrarei a solução que proponho passo a passo em um exemplo de brinquedo. Para satisfazer a segunda parte, farei isso usando um solucionador de pontos interior recente e de alta qualidade. Isso ocorre porque, é mais fácil obter uma implementação de alto desempenho da solução que proponho, usando uma biblioteca que pode resolver o problema do laço pela abordagem do ponto interior, em vez de tentar invadir o algoritmo LARS ou simplex para iniciar a otimização a partir de um método não- ponto de partida padrão (embora esse segundo local também seja possível).
Observe que algumas vezes é reivindicado (em livros antigos) que a abordagem do ponto interior para resolver programas lineares é mais lenta que a abordagem simplex e que pode ter sido verdade há muito tempo, mas geralmente não é verdadeira hoje e certamente não é verdadeira para problemas de grande escala (é por isso que a maioria das bibliotecas profissionais como cplex
usa o algoritmo de ponto interior) e a pergunta é pelo menos implicitamente sobre problemas de grande escala. Observe também que o solucionador de pontos interno que eu uso lida totalmente com matrizes esparsas, então não acho que haverá uma grande diferença de desempenho com o LARS (uma motivação original para usar o LARS era que muitos solucionadores de LP populares da época não estavam lidando bem com matrizes esparsas e estas são características do problema do LASSO).
Uma (muito) boa implementação de código aberto do algoritmo de ponto interior é ipopt
, na COIN-OR
biblioteca. Outra razão que eu vou usar ipopt
é que ele tem uma interface R ipoptr
,. Você encontrará um guia de instalação mais completo aqui , abaixo eu dou os comandos padrão para instalá-loubuntu
.
no bash
, faça:
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
Então, como root, em R
do (suponho svn
que copiei o arquivo de subversão ~/
como faz por padrão):
install.packages("~/CoinIpopt/Ipopt/contrib/RInterface",repos=NULL,type="source")
A partir daqui, estou dando um pequeno exemplo (principalmente do exemplo de brinquedo dado por Jelmer Ypma como parte de seu R
wraper para 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 ) )
O que quero dizer é que, se você tiver novos dados, precisará apenas
- atualizar ( não substituir) a matriz de restrição e o vetor de função objetivo para dar conta das novas observações.
altere os pontos de partida do ponto interior de
x0 = c (rep (0, m), rep (1, m))
βn e wβo ldβi n i tx0
| βi n i t- βn e w|1> | βn e w- βo l d|1( 1 )
βn e w muito mais rápido iniciando o ponto interior de
βo l d ao invés de ingênuo βi n i t. O ganho será ainda mais importante quando as dimensões do conjunto de dados (n e p) são maiores.
Quanto às condições sob as quais a desigualdade (1) se aplica, elas são:
- quando λ é grande comparado a | βO L S|1 (esse geralmente é o caso quando p, o número de variáveis de design é grande em comparação com n, o número de observações)
- quando as novas observações não são patologicamente influentes, por exemplo, quando são consistentes com o processo estocástico que gerou os dados existentes.
- quando o tamanho da atualização for pequeno em relação ao tamanho dos dados existentes.