คำตอบที่ต่อต้านภูมิอากาศที่ค่อนข้างจะ " ใครรู้ว่าทำไมนี้คืออะไร? " คือว่าไม่มีใครใส่ใจเพียงพอที่จะดำเนินการตามขั้นตอนการถดถอยสันเขาที่ไม่เป็นลบ หนึ่งในเหตุผลหลักคือคนเริ่มใช้งาน
รูทีน net elastic non-negative (ตัวอย่างเช่นที่นี่และที่นี่ ) ตาข่ายยืดหยุ่นรวมถึงการถดถอยของสันเป็นกรณีพิเศษ (อันที่จริงแล้วส่วนหนึ่งตั้งค่า LASSO ให้มีน้ำหนักเป็นศูนย์) ผลงานเหล่านี้ค่อนข้างใหม่ดังนั้นจึงยังไม่ได้รวมอยู่ใน scikit-Learn หรือชุดการใช้งานทั่วไปที่คล้ายกัน คุณอาจต้องการสอบถามผู้เขียนเอกสารเหล่านี้เพื่อขอรหัส
แก้ไข:
ในฐานะที่เป็น @ amoeba และฉันพูดคุยเกี่ยวกับความคิดเห็นการดำเนินการที่เกิดขึ้นจริงนี้ค่อนข้างง่าย สมมติว่ามีปัญหาการถดถอยต่อไปนี้:
y=2x1−x2+ϵ,ϵ∼N(0,0.22)
ที่และมีทั้งภาวะปกติมาตรฐานเช่น:(0,1) สังเกตุฉันใช้ตัวแปรทำนายมาตรฐานดังนั้นฉันไม่จำเป็นต้องทำให้เป็นมาตรฐานในภายหลัง เพื่อความง่ายฉันไม่รวมถึงการสกัดกั้นอย่างใดอย่างหนึ่ง เราสามารถแก้ปัญหาการถดถอยนี้ได้ทันทีโดยใช้การถดถอยเชิงเส้นมาตรฐาน ดังนั้นใน R มันควรเป็นแบบนี้: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
สังเกตเห็นบรรทัดสุดท้าย เกือบทั้งหมดถดถอยเชิงเส้นการใช้งานประจำการสลายตัว QR เพื่อประเมิน\เราต้องการใช้สิ่งเดียวกันสำหรับปัญหาการถดถอยของสันเขา ณ จุดนี้อ่านโพสต์นี้โดย @whuber; เราจะดำเนินการตามขั้นตอนนี้อย่างแน่นอน ในระยะสั้นเราจะเพิ่มเมทริกซ์การออกแบบต้นฉบับของเราด้วยเมทริกซ์ทแยงมุมและเวกเตอร์การตอบสนองของเราพร้อมศูนย์ ด้วยวิธีนี้เราจะสามารถแสดงปัญหาการถดถอยแนวสันเดิมได้อีกครั้งเป็น โดยที่βXλ−−√Ipyp(XTX+λI)−1XTy(X¯TX¯)−1X¯Ty¯¯สัญลักษณ์รุ่นเติม ตรวจสอบสไลด์ที่ 18-19 จากบันทึกเหล่านี้ด้วยเพื่อความสมบูรณ์ฉันพบว่าตรงไปตรงมาทีเดียว ดังนั้นใน R เราต้องการบางอย่างดังต่อไปนี้:
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
และมันใช้งานได้ ตกลงดังนั้นเราจึงได้ส่วนการถดถอยของสัน เราสามารถแก้ปัญหาด้วยวิธีอื่นได้ แต่เราสามารถกำหนดเป็นปัญหาการหาค่าเหมาะที่สุดที่ผลบวกส่วนที่เหลือของกำลังสองเป็นฟังก์ชันต้นทุนแล้วปรับเทียบกับมันเช่น 2 เราสามารถทำสิ่งนี้ได้: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
ซึ่งเป็นไปตามคาดอีกครั้ง ดังนั้นตอนนี้เราแค่ต้องการ:ที่0 ซึ่งเป็นเพียงปัญหาการเพิ่มประสิทธิภาพเดียวกัน แต่มีข้อ จำกัด เพื่อให้การแก้ปัญหาที่ไม่เป็นเชิงลบ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
ซึ่งแสดงให้เห็นว่างานการถดถอยสันสันที่ไม่เป็นลบสามารถแก้ไขได้โดยการปรับโครงสร้างใหม่ให้เป็นปัญหาการปรับให้เหมาะสมแบบง่าย คำเตือนบางอย่าง:
- ฉันใช้ตัวแปรตัวทำนายปกติ (จริง) คุณจะต้องคำนึงถึงการฟื้นฟูด้วยตนเอง
- สิ่งเดียวกันก็เกิดขึ้นเพื่อการสกัดกั้นที่ไม่เป็นมาตรฐาน
- ผมใช้
optim
ของL-BFGS-Bโต้แย้ง มันเป็นตัวแก้ปัญหาวานิลลา R มากที่สุดที่ยอมรับขอบเขต ฉันแน่ใจว่าคุณจะได้พบกับนักแก้ปัญหาที่ดีกว่าหลายสิบคน
- โดยทั่วไปปัญหาเชิงเส้นกำลังสองน้อยที่สุดเชิงเส้นจะถูกวางเป็นงานการหาค่าเหมาะที่สุดกำลังสอง นี่คือ overkill สำหรับโพสต์นี้ แต่โปรดจำไว้ว่าคุณสามารถรับความเร็วที่ดีขึ้นหากจำเป็น
- ดังที่กล่าวไว้ในความคิดเห็นที่คุณสามารถข้ามสันเขาถดถอยเป็นส่วนเติมเชิงเส้นถดถอยและเข้ารหัสฟังก์ชั่นค่าใช้จ่ายสันเขาโดยตรงเป็นปัญหาการเพิ่มประสิทธิภาพ นี่จะง่ายกว่านี้มากและโพสต์นี้เล็กลงอย่างมาก เพื่อประโยชน์ในการโต้แย้งฉันผนวกโซลูชั่นที่สองนี้ด้วย
- ผมไม่ได้สนทนาได้อย่างเต็มที่ในหลาม แต่เป็นหลักคุณสามารถทำซ้ำงานนี้โดยใช้ NumPy ของlinalg.solveและ SciPy ของการเพิ่มประสิทธิภาพการทำงาน
- ในการเลือกไฮเปอร์พารามิเตอร์ฯลฯ คุณเพียงแค่ทำ CV-step ปกติตามที่คุณต้องการในทุกกรณี ไม่มีอะไรเปลี่ยนแปลงλ
รหัสสำหรับจุดที่ 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