Lasso được trang bị thông qua LARS (một quá trình lặp lại, bắt đầu từ một số ước tính ban đầu ). Theo mặc định β 0 = 0 p nhưng bạn có thể thay đổi điều này trong hầu hết các thực hiện (và thay thế nó bằng cách tối ưu β * o l d bạn đã có). Gần nhất β * o l d là beta * n e w , nhỏ hơn số lượng LARS lặp bạn sẽ phải bước để có được beta * n e w .β0β0=0pβ∗oldβ∗oldβ∗newβ∗new
BIÊN TẬP:
Do các ý kiến từ user2763361
tôi thêm chi tiết cho câu trả lời ban đầu của tôi.
Từ các bình luận bên dưới, tôi tập hợp rằng user2763361 gợi ý để bổ sung cho câu trả lời ban đầu của tôi để biến nó thành câu trả lời có thể được sử dụng trực tiếp (ngoài giá) trong khi cũng rất hiệu quả.
Để làm phần đầu tiên, tôi sẽ minh họa giải pháp tôi đề xuất từng bước trên một ví dụ về đồ chơi. Để đáp ứng phần thứ hai, tôi sẽ làm như vậy bằng cách sử dụng một bộ giải điểm nội thất chất lượng cao gần đây. Điều này là do, dễ dàng hơn để có được triển khai hiệu suất cao cho giải pháp mà tôi đề xuất bằng cách sử dụng thư viện có thể giải quyết vấn đề Lasso bằng cách tiếp cận điểm bên trong thay vì cố gắng hack thuật toán LARS hoặc Simplex để bắt đầu tối ưu hóa từ một phi điểm bắt đầu tiêu chuẩn (mặc dù địa điểm thứ hai cũng có thể).
Lưu ý rằng đôi khi người ta khẳng định (trong các sách cũ) rằng cách tiếp cận điểm bên trong để giải các chương trình tuyến tính chậm hơn so với cách tiếp cận đơn giản và điều đó có thể đúng trong một thời gian dài nhưng ngày nay nó không đúng và chắc chắn không đúng với các vấn đề quy mô lớn (đây là lý do tại sao hầu hết các thư viện chuyên nghiệp thích cplex
sử dụng thuật toán điểm bên trong) và câu hỏi ít nhất là ngầm về các vấn đề quy mô lớn. Cũng lưu ý rằng bộ giải điểm bên trong tôi sử dụng xử lý đầy đủ các ma trận thưa thớt nên tôi không nghĩ sẽ có một khoảng cách hiệu suất lớn với LARS (một động lực ban đầu để sử dụng LARS là nhiều bộ giải LP phổ biến tại thời điểm đó không xử lý tốt các ma trận thưa thớt và đây là một tính năng đặc trưng của vấn đề LASSO).
Một triển khai mã nguồn mở rất tốt của thuật toán điểm bên trong là ipopt
trong COIN-OR
thư viện. Một lý do khác tôi sẽ sử dụng ipopt
là nó có giao diện R ipoptr
,. Bạn sẽ tìm thấy hướng dẫn cài đặt đầy đủ hơn ở đây , bên dưới tôi đưa ra các lệnh tiêu chuẩn để cài đặt nó trongubuntu
.
trong bash
, làm:
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
Sau đó, với quyền root, in R
do (tôi giả sử svn
đã sao chép tệp subversion ~/
theo mặc định):
install.packages("~/CoinIpopt/Ipopt/contrib/RInterface",repos=NULL,type="source")
Từ đây, tôi đưa ra một ví dụ nhỏ (chủ yếu là từ ví dụ đồ chơi do Jelmer Ypma như một phần của mình R
wraper đến 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 ) )
Quan điểm của tôi là, nếu bạn có dữ liệu mới, bạn chỉ cần
- cập nhật ( không thay thế) ma trận ràng buộc và vectơ hàm mục tiêu để giải thích cho các quan sát mới.
thay đổi điểm bắt đầu của điểm bên trong từ
x0 = c (rep (0, m), rep (1, m))
βnewβoldβinitx0
|βinit−βnew|1>|βnew−βold|1(1)
βnewβoldβinitnp
Đối với các điều kiện theo đó bất đẳng thức (1) giữ, chúng là:
- λ|βOLS|1pn
- khi các quan sát mới không có ảnh hưởng bệnh lý, ví dụ như khi chúng phù hợp với quy trình ngẫu nhiên đã tạo ra dữ liệu hiện có.
- khi kích thước của bản cập nhật nhỏ so với kích thước của dữ liệu hiện có.