Làm thế nào để thực hiện hồi quy sườn không âm?


10

Làm thế nào để thực hiện hồi quy sườn không âm? Lasso không âm có sẵn trong scikit-learn, nhưng đối với sườn núi, tôi không thể thực thi phi âm của betas, và thực sự, tôi đang nhận được hệ số âm. Có ai biết tại sao điều này?

Ngoài ra, tôi có thể thực hiện sườn núi theo bình phương tối thiểu thông thường không? Đã chuyển câu hỏi này sang câu hỏi khác: Tôi có thể thực hiện hồi quy sườn theo phương pháp hồi quy OLS không?


1
Có hai câu hỏi khá trực giao ở đây, tôi xem xét việc chia ra "tôi có thể thực hiện sườn núi theo bình phương tối thiểu" như một câu hỏi riêng biệt.
Matthew Drury

Câu trả lời:


8

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đâ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=2x1x2+ϵ,ϵ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:x1x2xpN(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:

  1. 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.
  2. Điều tương tự cũng xảy ra đối với việc không chuẩn hóa đánh chặn.
  3. 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.
  4. 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.
  5. 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.
  6. 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 .
  7. Để 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

1
Điều này có phần sai lệch. Hồi quy sườn không âm là không đáng kể để thực hiện: người ta có thể viết lại hồi quy sườn như hồi quy thông thường trên dữ liệu mở rộng (xem bình luận cho stats.stackexchange.com/questions/203687 ) và sau đó sử dụng các thói quen hồi quy không âm.
amip

Tôi đồng ý nó rất đơn giản để thực hiện (+1 cho điều đó). (Tôi đã nâng cấp nhận xét trước đó của bạn và Glen về chủ đề khác). Câu hỏi là tại sao không được thực hiện mặc dù không phải là khó khăn. Về vấn đề đó, tôi hoàn toàn nghi ngờ rằng việc trực tiếp xây dựng nhiệm vụ NNRR này, một vấn đề tối ưu hóa thậm chí còn đơn giản hơn trước tiên là xây dựng nó như một hồi quy dữ liệu mở rộng và sau đó sử dụng Quad. Ăn xin. tối ưu hóa để giải quyết hồi quy này. Tôi đã không nói điều này trong câu trả lời của mình vì nó sẽ mạo hiểm trong phần thực hiện.
usεr11852

Hoặc chỉ viết nó trong stan.
Sycorax nói phục hồi Monica

À được rồi; Tôi hiểu Q là chủ yếu hỏi làm thế nào để thực hiện sườn núi không âm (và chỉ hỏi về lý do tại sao nó không được thực hiện khi đi qua); Tôi thậm chí đã chỉnh sửa để đặt điều này vào tiêu đề. Trong mọi trường hợp, làm thế nào để làm điều đó đối với tôi là một câu hỏi thú vị hơn. Nếu bạn có thể cập nhật câu trả lời của mình với các giải thích về cách triển khai sườn núi không âm, tôi nghĩ nó sẽ rất hữu ích cho những người đọc trong tương lai (và tôi sẽ rất vui khi được upvote :).
amip

1
Thật tuyệt, tôi sẽ làm điều đó sau (Tôi không nhận thấy tiêu đề mới, xin lỗi về điều đó). Tôi có thể sẽ đưa ra cách thực hiện theo quan sát OLS / giả để chúng tôi cũng trả lời câu hỏi khác.
usεr11852

4

Gói glmnet R thực hiện lưới đàn hồi và do đó lasso và sườn cho phép điều này. Với các tham số lower.limitsupper.limits, bạn có thể đặt giá trị tối thiểu hoặc tối đa cho từng trọng số riêng biệt, vì vậy nếu bạn đặt giới hạn thấp hơn thành 0, nó sẽ thực hiện lưới đàn hồi không âm (lasso / sườn).

Ngoài ra còn có một trình bao bọc python https://pypi.python.org/pypi/glmnet/2.0.0


2

Nhớ lại chúng tôi đang cố gắng giải quyết:

minimizexAxy22+λx22s.t. x>0

tương đương với:

minimizexAxy22+λxIxs.t. x>0

với một số đại số nữa:

minimizexxT(ATA+λI)x+(2ATy)Txs.t. x>0

Giải pháp trong pseudo-python chỉ đơn giản là làm:

Q = A'A + lambda*I
c = - A'y
x,_ = scipy.optimize.nnls(Q,c)

xem: Làm thế nào để người ta thực hiện các bình phương tối thiểu không âm thưa thớt bằng cách sử dụng thường xuyên có dạng ?KxRkx

cho một câu trả lời chung chung hơn một chút.


Dòng c = - A'y không nên đọc c = A'y? Tôi nghĩ điều này là chính xác, mặc dù người ta cần lưu ý rằng giải pháp hơi khác so với scipy.optizes.nnls (newMatX, newVecY), trong đó newMatX là hàng X được tăng cường với ma trận đường chéo với sqrt (lambda) dọc theo đường chéo và NewVecY là Y tăng cường với số không nvar. Tôi nghĩ rằng giải pháp bạn đề cập là giải pháp chính xác ...
Tom Wenseleers
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.