Câu trả lời khá chống khí hậu cho " Có ai biết tại sao lại như vậy không? " Chỉ đơn giản là không ai quan tâm đủ để thực hiện thói quen hồi quy sườn không âm. Một trong những lý do chính là mọi người đã bắt đầu thực hiện
các thói quen mạng đàn hồi không âm (ví dụ ở đây và đây ). Lưới đàn hồi bao gồm hồi quy sườn như một trường hợp đặc biệt (về cơ bản người ta đặt phần LASSO có trọng số bằng 0). Các tác phẩm này tương đối mới vì vậy chúng chưa được kết hợp trong scikit-learn hoặc gói sử dụng chung tương tự. Bạn có thể muốn hỏi các tác giả của các giấy tờ cho mã.
BIÊN TẬP:
Như @amoeba và tôi đã thảo luận về các ý kiến, việc thực hiện điều này là tương đối đơn giản. Nói một có vấn đề hồi quy sau đây để:
y=2x1−x2+ϵ,ϵ∼N(0,0.22)
trong đó và đều là các quy tắc chuẩn như: . Lưu ý rằng tôi sử dụng các biến dự đoán được tiêu chuẩn hóa để sau đó tôi không phải bình thường hóa. Để đơn giản, tôi cũng không bao gồm đánh chặn. Chúng ta có thể giải quyết ngay vấn đề hồi quy này bằng phương pháp hồi quy tuyến tính tiêu chuẩn. Vì vậy, trong R nó phải là một cái gì đó như thế này:x1x2xp∼N(0,1)
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
Lưu ý dòng cuối cùng. Hầu như tất cả các quy trình hồi quy tuyến tính đều sử dụng phân tách QR để ước tính . Chúng tôi muốn sử dụng tương tự cho vấn đề hồi quy sườn núi của chúng tôi. Tại thời điểm này đọc bài viết này của @whuber; chúng tôi sẽ thực hiện chính xác thủ tục này. Nói tóm lại, chúng tôi sẽ làm tăng thiết kế ban đầu của chúng tôi ma trận với một chéo ma trận và phản ứng của chúng tôi vector với số không. Bằng cách đó, chúng tôi sẽ có thể diễn đạt lại vấn đề hồi quy sườn ban đầu as trong đóβXλ−−√Ipyp(XTX+λI)−1XTy(X¯TX¯)−1X¯Ty¯¯tượng trưng cho phiên bản tăng cường. Kiểm tra các slide 18-19 từ các ghi chú này cho đầy đủ, tôi thấy chúng khá đơn giản. Vì vậy, trong R chúng tôi sẽ một số như sau:
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
Và nó hoạt động. OK, vì vậy chúng tôi đã có phần hồi quy sườn núi. Mặc dù vậy, chúng ta có thể giải quyết theo một cách khác, chúng ta có thể coi đó là một vấn đề tối ưu hóa trong đó tổng bình phương còn lại là hàm chi phí và sau đó tối ưu hóa chống lại nó, tức là. . Chắc chắn chúng ta có thể làm điều đó:minβ||y¯−X¯β||22
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
mà như mong đợi một lần nữa hoạt động. Vì vậy, bây giờ chúng tôi chỉ muốn: trong đó . Mà đơn giản là cùng một vấn đề tối ưu hóa nhưng bị ràng buộc để giải pháp không âm.minβ||y¯−X¯β||22β≥0
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
trong đó cho thấy rằng nhiệm vụ hồi quy sườn không âm ban đầu có thể được giải quyết bằng cách cải tổ thành một vấn đề tối ưu hóa bị ràng buộc đơn giản. Một số hãy cẩn thận:
- Tôi đã sử dụng (thực tế) các biến dự đoán chuẩn hóa. Bạn sẽ cần phải tự mình chuẩn hóa.
- Điều tương tự cũng xảy ra đối với việc không chuẩn hóa đánh chặn.
- Tôi đã từng
optim
's L-BFGS-B đối số. Nó là bộ giải R vanilla nhất chấp nhận giới hạn. Tôi chắc chắn rằng bạn sẽ tìm thấy hàng tá người giải quyết tốt hơn.
- Trong các hạn chế chung, các bài toán bình phương tuyến tính nhỏ nhất được đặt ra như các nhiệm vụ tối ưu hóa bậc hai . Đây là một quá mức cần thiết cho bài đăng này nhưng hãy nhớ rằng bạn có thể có được tốc độ tốt hơn nếu cần thiết.
- Như đã đề cập trong các ý kiến, bạn có thể bỏ qua hồi quy sườn như phần hồi quy tuyến tính tăng cường và trực tiếp mã hóa hàm chi phí sườn như một vấn đề tối ưu hóa. Điều này sẽ đơn giản hơn rất nhiều và bài đăng này nhỏ hơn đáng kể. Để tranh luận, tôi cũng thêm giải pháp thứ hai này.
- Tôi không hoàn toàn trò chuyện trong Python nhưng về cơ bản, bạn có thể sao chép công việc này bằng cách sử dụng các chức năng tối ưu hóa Numinal của linalg.solve và SciPy .
- Để chọn siêu tham số v.v. bạn chỉ cần thực hiện bước CV thông thường bạn sẽ làm trong mọi trường hợp; không có gì thay đổi.λ
Mã cho điểm 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