วิธีการตีความ glmnet?


36

ฉันกำลังพยายามปรับตัวแบบการถดถอยเชิงเส้นหลายตัวแปรที่มีตัวแปรทำนาย 60 ตัวและการสังเกต 30 ครั้งดังนั้นฉันจึงใช้แพ็คเกจglmnetสำหรับการถดถอยแบบปกติเพราะ p> n

ฉันได้อ่านเอกสารและคำถามอื่น ๆ แล้ว แต่ฉันก็ยังไม่สามารถตีความผลลัพธ์ได้นี่คือตัวอย่างโค้ด (ที่มีตัวทำนาย 20 ตัวและตัวสังเกต 10 ข้อเพื่อลดความซับซ้อน):

ฉันสร้างเมทริกซ์ x พร้อมแถว num = การสังเกต num และ num cols = ตัวทำนาย NUM และเวกเตอร์ y ซึ่งแสดงถึงตัวแปรตอบสนอง

> x=matrix(rnorm(10*20),10,20)
> y=rnorm(10)

ฉันพอดีกับรูปแบบ glmnet ที่ปล่อยให้อัลฟาเป็นค่าเริ่มต้น (= 1 สำหรับการลงโทษบ่วงบาศ)

> fit1=glmnet(x,y)
> print(fit1)

ฉันเข้าใจว่าฉันได้รับการทำนายที่แตกต่างจากการลดค่าแลมบ์ดา (เช่นการลงโทษ)

Call:  glmnet(x = x, y = y) 

        Df    %Dev   Lambda
  [1,]  0 0.00000 0.890700
  [2,]  1 0.06159 0.850200
  [3,]  1 0.11770 0.811500
  [4,]  1 0.16880 0.774600
   .
   .
   .
  [96,] 10 0.99740 0.010730
  [97,] 10 0.99760 0.010240
  [98,] 10 0.99780 0.009775
  [99,] 10 0.99800 0.009331
 [100,] 10 0.99820 0.008907

ตอนนี้ฉันคาดการณ์ว่าจะเลือกค่าเบต้าตัวอย่างเช่นค่าแลมบ์ดาที่เล็กที่สุดที่ได้รับ glmnet

> predict(fit1,type="coef", s = 0.008907)

21 x 1 sparse Matrix of class "dgCMatrix"
                  1
(Intercept) -0.08872364
V1           0.23734885
V2          -0.35472137
V3          -0.08088463
V4           .         
V5           .         
V6           .         
V7           0.31127123
V8           .         
V9           .         
V10          .         
V11          0.10636867
V12          .         
V13         -0.20328200
V14         -0.77717745
V15          .         
V16         -0.25924281
V17          .         
V18          .         
V19         -0.57989929
V20         -0.22522859

ถ้าฉันเลือกแลมบ์ดาด้วย

cv <- cv.glmnet(x,y)
model=glmnet(x,y,lambda=cv$lambda.min)

ตัวแปรทั้งหมดจะเป็น (.)

สงสัยและคำถาม:

  1. ฉันไม่แน่ใจเกี่ยวกับวิธีเลือกแลมบ์ดา
  2. ฉันควรใช้ตัวแปรที่ไม่ใช่ (.) เพื่อให้พอดีกับโมเดลอื่นหรือไม่ ในกรณีของฉันฉันต้องการเก็บตัวแปรให้มากที่สุด
  3. ฉันจะรู้ค่า p ได้อย่างไรเช่นตัวแปรใดทำนายการตอบสนองได้อย่างมีนัยสำคัญ

ฉันขอโทษสำหรับความรู้ทางสถิติที่ไม่ดีของฉัน! และขอขอบคุณสำหรับความช่วยเหลือ


อาจจะมีลักษณะที่ CRAN แพคเกจHDIที่หนึ่งให้การอนุมานสำหรับรุ่นที่สูงมิติ ...
ทอม Wenseleers

สำหรับคำอธิบายทั้งหมดของวิธีการที่ใช้ฉันแนะนำคุณไปยังบทความนี้: projecteuclid.org/euclid.ss/1449670857
Tom Wenseleers

คำตอบ:


40

นี่คือข้อเท็จจริงที่ไม่ได้ใช้งานง่าย - คุณไม่ควรให้แลมบ์ดาเป็นค่าเดียวกับ glmnet จากเอกสารที่นี่ :

อย่าระบุค่าเดียวสำหรับแลมบ์ดา (สำหรับการคาดการณ์หลังจาก CV ใช้การทำนาย () แทน) จัดหาแทนค่าแลมบ์ดาที่ลดลงแทน glmnet อาศัยความอบอุ่นเริ่มจากความเร็วและบ่อยครั้งที่เร็วกว่าที่จะหาเส้นทางทั้งหมดมากกว่าการคำนวณเพียงครั้งเดียว

cv.glmnetจะช่วยให้คุณเลือกแลมบ์ดาตามที่คุณพูดถึงในตัวอย่างของคุณ ผู้เขียนของแพ็คเกจ glmnet แนะนำcv$lambda.1seแทนcv$lambda.minแต่ในทางปฏิบัติฉันได้ประสบความสำเร็จกับหลัง

หลังจากเรียกใช้ cv.glmnet คุณไม่ต้องเรียกใช้ glmnet อีกครั้ง! แลมบ์ดาทุกตัวในกริด ( cv$lambda) ได้รับการทำงานแล้ว เทคนิคนี้เรียกว่า "อบอุ่นเริ่มต้น" และคุณสามารถอ่านเพิ่มเติมได้ที่นี่ การถอดความจากการแนะนำเทคนิค Warm Start ช่วยลดเวลาการทำงานของวิธีการวนซ้ำโดยใช้วิธีการแก้ปัญหาการหาค่าเหมาะที่สุดที่แตกต่างกัน (เช่น glmnet กับแลมบ์ดาขนาดใหญ่) เป็นค่าเริ่มต้นสำหรับปัญหาการปรับให้เหมาะสมที่สุดในภายหลัง (เช่น glmnet )

หากต้องการแยกการเรียกใช้ที่ต้องการcv.glmnet.fitให้ลอง:

small.lambda.index <- which(cv$lambda == cv$lambda.min)
small.lambda.betas <- cv$glmnet.fit$beta[, small.lambda.index]

การแก้ไข (1/28/2017)

ไม่จำเป็นต้องแฮ็คไปยังวัตถุ glmnet เหมือนที่ฉันทำไว้ข้างต้น ใช้ @ คำแนะนำ alex23lemm ด้านล่างและผ่านการs = "lambda.min", s = "lambda.1se"หรือหมายเลขอื่น ๆ บางอย่าง (เช่นs = .007) ทั้งสองและcoef predictโปรดทราบว่าค่าสัมประสิทธิ์และการคาดการณ์ของคุณขึ้นอยู่กับค่านี้ซึ่งกำหนดโดยการตรวจสอบข้าม ใช้เมล็ดพันธุ์เพื่อทำซ้ำ! และอย่าลืมว่าถ้าคุณไม่ได้จัดหา"s"ในcoefและคุณจะใช้เริ่มต้นของpredict s = "lambda.1se"ฉันอุ่นขึ้นถึงค่าเริ่มต้นหลังจากเห็นมันทำงานได้ดีขึ้นในสถานการณ์ข้อมูลขนาดเล็กs = "lambda.1se"มีแนวโน้มที่จะให้การทำให้เป็นมาตรฐานมากขึ้นดังนั้นหากคุณทำงานกับอัลฟา> 0 มันก็จะมีแนวโน้มที่จะเป็นรูปแบบที่น่าจดจำมากขึ้น นอกจากนี้คุณยังสามารถเลือกค่าตัวเลขของ s ด้วยความช่วยเหลือของ plot.glmnet เพื่อไปที่ใดที่หนึ่งในระหว่าง (เพียงอย่าลืมที่จะยกกำลังค่าจากแกน x!)


1
ขอขอบคุณ! สิ่งนี้จะช่วย ... คุณอาจมีคำตอบสำหรับคำถามที่ 2 และ 3 หรือไม่?
อลิซ

3
ไม่ต้องกังวลหรอก เครื่องหมาย (.) s เป็นศูนย์ เมื่อคุณไปกับ Lasso คุณได้ระบุว่าคุณต้องการโซลูชัน "เบาบาง" (เช่นศูนย์จำนวนมาก) หากคุณต้องการให้ค่าทั้งหมดตั้งค่า alpha = 0 ทีนี้คุณก็เปลี่ยนจาก Lasso เป็น Ridge regression ค่า p สำหรับ glmnet นั้นซับซ้อนมาก หากคุณค้นหาโดยใช้ google "p-values ​​for lasso" คุณจะเห็นการวิจัยและการอภิปรายจำนวนมาก ฉันได้อ่านบัญชีหนึ่ง (แหล่งความจำเสื่อม) ซึ่งผู้เขียนแย้งว่าค่า p ไม่สมเหตุสมผลสำหรับการถดถอยแบบเอนเอียงเช่นการถดถอยแบบ lasso และ ridge
Ben Ogorek

6
อีกทางเลือกหนึ่งในการแยกสัมประสิทธิ์ที่เกี่ยวข้องกับค่าแลมบ์ดาที่ให้ค่า cvm ขั้นต่ำมีดังนี้:small.lambda.betas <- coef(cv, s = "lambda.min")
alex23lemm

1
@ BenOgorek การปรับปรุงที่ยอดเยี่ยม! การอ้างอิงที่มีประโยชน์อีกอย่างคือ Friedman J, Hastie T, Hoefling H, Tibshirani R. การเพิ่มประสิทธิภาพการประสานงานที่เหมาะสม พงศาวดารของสถิติประยุกต์ 2007; 2 (1): 302-332 ( arxiv.org/pdf/0708.1485.pdf )
dv_bn

1
@erosennin ตรวจสอบอาร์กิวเมนต์ lambda ของ cv.glmnet: "ลำดับแลมบ์ดาที่ผู้ใช้ระบุเป็นตัวเลือกค่าเริ่มต้นคือ NULL และ glmnet เลือกลำดับของตนเอง" คุณจะต้องใช้หลักการเริ่มต้นที่อบอุ่นและเริ่มต้นลำดับด้วยแลมบ์ดาที่มีขนาดใหญ่ขึ้นก่อนที่จะลดลงในช่วงที่คุณสนใจ
เบ็นโอโกเร

2

Q1) ฉันไม่แน่ใจเกี่ยวกับวิธีเลือกแลมบ์ดา Q2) ฉันควรใช้ตัวแปรที่ไม่ใช่ (.) เพื่อให้พอดีกับโมเดลอื่นหรือไม่ ในกรณีของฉันฉันต้องการเก็บตัวแปรให้มากที่สุด

ตามคำตอบที่ยอดเยี่ยมของ @ BenOgorek โดยทั่วไปแล้วคุณควรปล่อยให้เหมาะสมใช้ลำดับแลมบ์ดาทั้งหมดจากนั้นเมื่อทำการแยกสัมประสิทธิ์ที่เหมาะสมที่สุดให้ใช้ค่าแลมบ์ดา 1

ตราบใดที่คุณทำตามคำเตือนทั้งสามข้อด้านล่างอย่าต่อสู้กับการทำให้เป็นมาตรฐานหรือปรับโมเดล: ถ้าตัวแปรถูกละไว้แล้วมันเป็นเพราะมันให้โทษโดยรวมที่ต่ำกว่า คำเตือนคือ:

  1. เพื่อให้ค่าสัมประสิทธิ์ปกติมีความหมายตรวจสอบให้แน่ใจว่าคุณได้ปรับค่าเฉลี่ยของตัวแปรและ stdev ให้ชัดเจนก่อนด้วยscale(); glmnet(standardize=T)ไม่ต้องพึ่งพา สำหรับเหตุผลดูที่มาตรฐานก่อน Lasso จำเป็นจริงๆ? ; โดยทั่วไปตัวแปรที่มีค่ามากอาจถูกลงโทษอย่างไม่ยุติธรรมในการทำให้เป็นมาตรฐาน

  2. หากต้องการทำซ้ำได้ให้รันพร้อมset.seedกับเมล็ดสุ่มหลาย ๆ อันและตรวจสอบค่าสัมประสิทธิ์ปกติเพื่อความเสถียร

  3. หากคุณต้องการการทำให้เป็นมาตรฐานที่รุนแรงน้อยกว่านั่นคือมีตัวแปรเพิ่มเติมให้ใช้อัลฟ่า <1 (เช่นอีลาสติกที่เหมาะสม - ตาข่าย) แทนที่จะเป็นสันง่าย ฉันขอแนะนำให้คุณกวาดอัลฟาตั้งแต่ 0 ถึง 1 หากคุณกำลังจะทำเช่นนั้นดังนั้นเพื่อหลีกเลี่ยงการตั้งค่าพารามิเตอร์อัลฟาและพารามิเตอร์การถดถอยที่มากเกินไปคุณต้องใช้ crossvalidation เช่นใช้cv.glmnet()ง่ายกว่าglmnet():

.

for (alpha in c(0,.1,.3,.5,.7,.9,1)) {
  fit <- cv.glmnet(..., alpha=alpha, nfolds=...)
  # Look at the CVE at lambda.1se to find the minimum for this alpha value...
}

ถ้าคุณต้องการทำการค้นหากริดอัตโนมัติด้วย CV คุณสามารถเขียนโค้ดด้วยตัวคุณเองหรือใช้ caret package ที่ด้านบนของ glmnet caret ทำได้ดี สำหรับcv.glmnet nfoldsค่าพารามิเตอร์ให้เลือก 3 (ขั้นต่ำ) หากชุดข้อมูลของคุณมีขนาดเล็กหรือ 5 หรือ 10 หากมีขนาดใหญ่

Q3) ฉันจะรู้ได้อย่างไรว่าค่า p คือตัวแปรใดที่ทำนายการตอบสนองได้อย่างมีนัยสำคัญ

ทำไม่ได้พวกเขาไม่ได้มีความหมาย ตามที่อธิบายในรายละเอียดในเหตุใดจึงไม่สามารถรับข้อมูลสรุปเชิงสถิติสำหรับสัมประสิทธิ์การถดถอยจากโมเดล glmnet ได้?

เพียงแค่ให้cv.glmnet()ทำการเลือกตัวแปรโดยอัตโนมัติ ด้วยข้อแม้ข้างต้น และแน่นอนว่าการกระจายตัวของตัวแปรตอบกลับควรเป็นปกติ (สมมติว่าคุณใช้อยู่family='gaussian')


ขอบคุณสำหรับความคิดเห็นที่เป็นประโยชน์มาก! ฉันยังพบว่าการทำให้ตัวแปรมาตรฐานตัวเองดูเหมือนว่าจะทำงานได้ดีกว่าการใช้ glmnet (standardize = T)
มิเชล

ฉันมีคำถาม @smci เกี่ยวกับค่าเบต้าที่ส่งคืนโดย cvglmnet ว่า ฉันเข้าใจว่ามันเป็นค่าเบต้าในแต่ละจุดของค่าแลมบ์ดาที่พยายาม อย่างไรก็ตามมีค่าเบต้าที่ส่งกลับสำหรับแต่ละค่าแลมบ์ดา (1) ค่าสัมประสิทธิ์เฉลี่ยจาก 10 เท่า (สมมติว่าฉันใช้ 10 เท่า CV) (2) ค่าเบต้าจากครึ่งที่ให้ความแม่นยำที่ดีที่สุดหรือ (3) ค่าสัมประสิทธิ์จาก เรียกใช้โมเดลซ้ำบนชุดข้อมูลทั้งหมดหรือไม่
มิเชล
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.