ฉันอยากจะแนะนำบทความของ Hanley's & McNeil ในปี 1982 ว่า ' ความหมายและการใช้พื้นที่ภายใต้เส้นโค้งลักษณะการทำงานของเครื่องรับ (ROC) '
ตัวอย่าง
พวกเขามีตารางสถานะของโรคต่อไปนี้และผลการทดสอบ (เช่นที่สอดคล้องกับความเสี่ยงโดยประมาณจากรูปแบบโลจิสติก) หมายเลขแรกทางด้านขวาคือจำนวนผู้ป่วยที่มีสถานะโรคจริง 'ปกติ' และหมายเลขที่สองคือจำนวนผู้ป่วยที่มีสถานะโรคจริง 'ผิดปกติ':
(1) ปกติแน่นอน: 33/3
(2) ปกติน่าจะเป็น: 6/2
(3) ที่น่าสงสัย: 6/2
(4) อาจผิดปกติ: 11/11
(5) ผิดปกติอย่างแน่นอน: 2/33
ดังนั้นจึงมีผู้ป่วย 58 ราย 'ปกติ' และ '51' คนที่ผิดปกติ เราเห็นว่าเมื่อตัวทำนายคือ 1 'ปกติแน่นอน' ผู้ป่วยมักจะปกติ (จริงสำหรับ 33 ของ 36 ผู้ป่วย) และเมื่อมันคือ 5 'ผิดปกติแน่นอน' ผู้ป่วยมักจะผิดปกติ (จริงสำหรับ 33 ของ ผู้ป่วย 35 คน) ดังนั้นผู้ทำนายจึงสมเหตุสมผล แต่เราจะตัดสินผู้ป่วยด้วยคะแนน 2, 3 หรือ 4 ได้อย่างไร สิ่งที่เราตั้งค่าการตัดออกของเราสำหรับการตัดสินผู้ป่วยว่าผิดปกติหรือปกติเพื่อกำหนดความไวและความจำเพาะของผลการทดสอบ
ความไวและความจำเพาะ
เราสามารถคำนวณความไวและความจำเพาะโดยประมาณสำหรับการตัดที่แตกต่างกัน (ฉันจะเขียน 'ความไว' และ 'ความเฉพาะเจาะจง' นับจากนี้ไปเพื่อให้ลักษณะโดยประมาณของค่านั้นเป็นนัย)
หากเราเลือกทางลัดเพื่อจำแนกผู้ป่วยทั้งหมดผิดปกติไม่ว่าผลการทดสอบจะเป็นอย่างไร (เช่นเราเลือกทางลัด 1+) เราจะได้รับความไว 51/51 = 1 ความจำเพาะจะเป็น 0 / 58 = 0. เสียงไม่ดีนัก
ตกลงดังนั้นให้เลือกทางลัดที่เข้มงวดน้อยกว่า เราจำแนกผู้ป่วยว่าผิดปกติเท่านั้นหากพวกเขามีผลการทดสอบ 2 หรือสูงกว่า จากนั้นเราพลาดผู้ป่วยที่ผิดปกติ 3 รายและมีความไว 48/51 = 0.94 แต่เรามีความเฉพาะเจาะจงมากขึ้นจาก 33/58 = 0.57
ตอนนี้เราสามารถดำเนินการต่อไปได้โดยเลือกการตัดต่างๆ (3, 4, 5,> 5) (ในกรณีที่ผ่านมาเราจะไม่แยกประเภทใด ๆผู้ป่วยที่เป็นความผิดปกติถึงแม้ว่าพวกเขามีคะแนนการทดสอบเป็นไปได้สูงสุด 5)
เส้นโค้ง ROC
ถ้าเราทำเช่นนี้สำหรับการตัดที่เป็นไปได้ทั้งหมดและพล็อตความไวต่อ 1 ลบความจำเพาะเราจะได้เส้นโค้ง ROC เราสามารถใช้รหัส R ต่อไปนี้:
# Data
norm = rep(1:5, times=c(33,6,6,11,2))
abnorm = rep(1:5, times=c(3,2,2,11,33))
testres = c(abnorm,norm)
truestat = c(rep(1,length(abnorm)), rep(0,length(norm)))
# Summary table (Table I in the paper)
( tab=as.matrix(table(truestat, testres)) )
ผลลัพธ์คือ:
testres
truestat 1 2 3 4 5
0 33 6 6 11 2
1 3 2 2 11 33
เราสามารถคำนวณสถิติต่าง ๆ :
( tot=colSums(tab) ) # Number of patients w/ each test result
( truepos=unname(rev(cumsum(rev(tab[2,])))) ) # Number of true positives
( falsepos=unname(rev(cumsum(rev(tab[1,])))) ) # Number of false positives
( totpos=sum(tab[2,]) ) # The total number of positives (one number)
( totneg=sum(tab[1,]) ) # The total number of negatives (one number)
(sens=truepos/totpos) # Sensitivity (fraction true positives)
(omspec=falsepos/totneg) # 1 − specificity (false positives)
sens=c(sens,0); omspec=c(omspec,0) # Numbers when we classify all as normal
และการใช้สิ่งนี้เราสามารถพล็อตกราฟ ROC (โดยประมาณ):
plot(omspec, sens, type="b", xlim=c(0,1), ylim=c(0,1), lwd=2,
xlab="1 − specificity", ylab="Sensitivity") # perhaps with xaxs="i"
grid()
abline(0,1, col="red", lty=2)
การคำนวณ AUC ด้วยตนเอง
เราสามารถคำนวณพื้นที่ใต้เส้นโค้ง ROC ได้ง่ายมากโดยใช้สูตรสำหรับพื้นที่ของรูปสี่เหลี่ยมคางหมู:
height = (sens[-1]+sens[-length(sens)])/2
width = -diff(omspec) # = diff(rev(omspec))
sum(height*width)
ผลลัพธ์คือ 0.8931711
มาตรการที่สอดคล้องกัน
AUC สามารถมองเห็นได้ว่าเป็นมาตรการที่สอดคล้องกัน หากเรารับผู้ป่วยที่เป็นไปได้ทุกคู่โดยที่คนหนึ่งเป็นปกติและอีกคนเป็นคนที่ผิดปกติเราสามารถคำนวณได้ว่ามันเป็นคู่ที่ผิดปกติซึ่งมีผลการทดสอบสูงสุด ('ดูผิดปกติ') มากที่สุดหรือไม่ นับว่านี่เป็น 'ครึ่งชัยชนะ'):
o = outer(abnorm, norm, "-")
mean((o>0) + .5*(o==0))
คำตอบคือ 0.8931711 อีกครั้งพื้นที่ใต้เส้นโค้ง ROC นี่จะเป็นกรณีนี้เสมอ
มุมมองแบบกราฟิกของความสอดคล้อง
ตามที่ Harrell ชี้ให้เห็นในคำตอบของเขาสิ่งนี้ก็มีการตีความกราฟิก ลองทำพล็อตคะแนนการทดสอบ (การประเมินความเสี่ยง) ในสถานะy -axis และสถานะโรคจริงของx -axis (ที่นี่ด้วย jittering เพื่อแสดงจุดที่ทับซ้อนกัน):
plot(jitter(truestat,.2), jitter(testres,.8), las=1,
xlab="True disease status", ylab="Test score")
ให้เราวาดเส้นแบ่งระหว่างแต่ละจุดทางด้านซ้าย (ผู้ป่วย 'ปกติ') และแต่ละจุดทางด้านขวา (ผู้ป่วยที่ 'ผิดปกติ') สัดส่วนของเส้นที่มีความชันเป็นบวก (เช่นสัดส่วนของคู่ที่สอดคล้องกัน) คือดัชนีความสอดคล้อง (เส้นแบนนับเป็น 'ความสอดคล้อง 50%')
เป็นการยากที่จะเห็นภาพเส้นที่แท้จริงสำหรับตัวอย่างนี้เนื่องจากจำนวนความสัมพันธ์ (คะแนนความเสี่ยงเท่ากัน) แต่ด้วยความกระวนกระวายใจและความโปร่งใสบางอย่างเราจึงสามารถได้พล็อตที่สมเหตุสมผล:
d = cbind(x_norm=0, x_abnorm=1, expand.grid(y_norm=norm, y_abnorm=abnorm))
library(ggplot2)
ggplot(d, aes(x=x_norm, xend=x_abnorm, y=y_norm, yend=y_abnorm)) +
geom_segment(colour="#ff000006",
position=position_jitter(width=0, height=.1)) +
xlab("True disease status") + ylab("Test\nscore") +
theme_light() + theme(axis.title.y=element_text(angle=0))
เราเห็นว่าเส้นส่วนใหญ่ลาดเอียงขึ้นไปดังนั้นดัชนีความสอดคล้องจะสูง เรายังเห็นการมีส่วนร่วมกับดัชนีจากคู่การสังเกตแต่ละประเภท ส่วนใหญ่มาจากผู้ป่วยปกติที่มีคะแนนความเสี่ยง 1 คู่กับผู้ป่วยผิดปกติที่มีคะแนนความเสี่ยง 5 (1-5 คู่) แต่ค่อนข้างมากเช่นกันมาจาก 1-4 คู่และ 4-5 คู่ และมันง่ายมากที่จะคำนวณดัชนีความสอดคล้องจริงตามคำจำกัดความของความชัน:
d = transform(d, slope=(y_norm-y_abnorm)/(x_norm-x_abnorm))
mean((d$slope > 0) + .5*(d$slope==0))
คำตอบคือ 0.8931711 อีกครั้งนั่นคือ AUC
การทดสอบ Wilcoxon – Mann – Whitney
มีการเชื่อมต่ออย่างใกล้ชิดระหว่างมาตรการความสอดคล้องและการทดสอบ Wilcoxon – Mann – Whitney ที่จริงแล้วการทดสอบครั้งหลังถ้าความน่าจะเป็นของความสอดคล้อง (เช่นว่ามันเป็นผู้ป่วยที่ผิดปกติในคู่แบบปกติ - ผิดปกติที่จะมีผลการทดสอบ และสถิติการทดสอบเป็นเพียงการเปลี่ยนแปลงอย่างง่ายของความน่าจะเป็นที่สอดคล้องกันโดยประมาณ:
> ( wi = wilcox.test(abnorm,norm) )
Wilcoxon rank sum test with continuity correction
data: abnorm and norm
W = 2642, p-value = 1.944e-13
alternative hypothesis: true location shift is not equal to 0
สถิติทดสอบ ( W = 2642
) นับจำนวนคู่ที่สอดคล้องกัน หากเราหารด้วยจำนวนคู่ที่เป็นไปได้เราจะได้จำนวนที่พอเหมาะ:
w = wi$statistic
w/(length(abnorm)*length(norm))
ใช่มันคือ 0.8931711 พื้นที่ใต้เส้นโค้ง ROC
วิธีที่ง่ายกว่าในการคำนวณ AUC (เป็น R)
แต่ขอให้ชีวิตง่ายขึ้นสำหรับตัวเราเอง มีแพ็คเกจหลากหลายที่คำนวณ AUC ให้เราโดยอัตโนมัติ
แพ็คเกจ Epi
Epi
แพคเกจสร้างความสุขโค้ง ROC กับสถิติต่างๆ (รวมทั้ง AUC) ฝังตัว:
library(Epi)
ROC(testres, truestat) # also try adding plot="sp"
แพคเกจ pROC
ฉันชอบpROC
แพคเกจด้วยเนื่องจากสามารถทำให้ ROC ประมาณการได้อย่างราบรื่น (และคำนวณค่าประมาณการ AUC ตาม ROC ที่ราบรื่น):
(เส้นสีแดงคือ ROC ดั้งเดิมและเส้นสีดำคือ ROC ที่ราบเรียบนอกจากนี้ให้สังเกตอัตราส่วนอัตราส่วน 1: 1 ที่เป็นค่าเริ่มต้นมันสมเหตุสมผลที่จะใช้สิ่งนี้เนื่องจากทั้งความไวและความจำเพาะมีช่วง 0-1)
AUC โดยประมาณจากROC ที่ราบรื่นคือ 0.9107 ซึ่งคล้ายกับ แต่มีขนาดใหญ่กว่าAUC จากROC ที่ไม่มีการสั่นเล็กน้อย (ถ้าคุณดูที่ตัวเลขคุณจะเห็นว่าทำไมมันจึงใหญ่กว่า) (แม้ว่าเราจะมีค่าผลการทดสอบที่แตกต่างกันที่เป็นไปได้น้อยมากในการคำนวณ AUC ที่ราบรื่น)
แพ็คเกจ rms
rms
แพ็คเกจของ Harrell สามารถคำนวณสถิติความสอดคล้องต่าง ๆ ที่เกี่ยวข้องโดยใช้rcorr.cens()
ฟังก์ชัน C Index
ในการส่งออกที่เป็น AUC:
> library(rms)
> rcorr.cens(testres,truestat)[1]
C Index
0.8931711
แพ็คเกจ caTools
ในที่สุดเรามีcaTools
แพ็คเกจและcolAUC()
ฟังก์ชั่นของมัน มันมีข้อดีเล็กน้อยกว่าแพ็คเกจอื่น ๆ (ส่วนใหญ่ความเร็วและความสามารถในการทำงานกับข้อมูลหลายมิติ - ดู?colAUC
) ซึ่งบางครั้งอาจมีประโยชน์ แต่แน่นอนมันให้คำตอบเดียวกับที่เราคำนวณซ้ำแล้วซ้ำอีก:
library(caTools)
colAUC(testres, truestat, plotROC=TRUE)
[,1]
0 vs. 1 0.8931711
คำพูดสุดท้าย
หลายคนคิดว่า AUC บอกเราว่าการทดสอบ 'ดี' เป็นอย่างไร และบางคนคิดว่า AUC เป็นความน่าจะเป็นที่การทดสอบจะจำแนกผู้ป่วยอย่างถูกต้อง มันเป็นไม่ได้ ดังที่คุณเห็นได้จากตัวอย่างและการคำนวณข้างต้น AUC จะบอกเราบางอย่างเกี่ยวกับตระกูลการทดสอบหนึ่งการทดสอบสำหรับการตัดแต่ละครั้งที่เป็นไปได้
และ AUC คำนวณจากการตัดทอนอย่างใดอย่างหนึ่งจะไม่ใช้ในทางปฏิบัติ เหตุใดเราจึงต้องใส่ใจเกี่ยวกับความไวและความเฉพาะเจาะจงของค่าตัด 'ไร้สาระ' แต่ถึงกระนั้นก็เป็นสิ่งที่ AUC เป็น (บางส่วน) ขึ้นอยู่กับ (แน่นอนถ้า AUC เป็นมากใกล้กับ 1 เกือบทุกการทดสอบเป็นไปได้ที่จะมีอำนาจการเลือกปฏิบัติที่ดีและเราทุกคนจะมีความสุขมาก.)
การตีความคู่แบบสุ่มปกติผิดปกติของ AUC นั้นดี (และสามารถขยายได้ตัวอย่างเช่นโมเดลการเอาชีวิตรอดที่เราเห็นว่าบุคคลที่มีอันตรายสูงสุด (ญาติ) ที่ตายเร็วที่สุดหรือไม่ แต่ไม่มีใครใช้มันในทางปฏิบัติ มันเป็นกรณีที่หายากที่หนึ่งรู้ว่าใครมีหนึ่งมีสุขภาพดีและหนึ่งในผู้ป่วยไม่ทราบว่าคนป่วยหนึ่งและจะต้องตัดสินใจที่ของพวกเขาในการรักษา (ไม่ว่าในกรณีใดการตัดสินใจทำได้ง่ายจัดการกับความเสี่ยงโดยประมาณที่สูงที่สุด)
ดังนั้นฉันคิดว่าการศึกษาเส้นโค้ง ROC ที่เกิดขึ้นจริงจะมีประโยชน์มากกว่าเพียงแค่ดูที่สรุปมาตรการ AUC และถ้าคุณใช้ ROC พร้อมกับ (ค่าประมาณ) ค่าใช้จ่ายของผลบวกปลอมและค่าลบเชิงลบพร้อมกับอัตราฐานของสิ่งที่คุณกำลังศึกษาอยู่คุณสามารถหาที่อื่นได้
โปรดทราบว่า AUC จะวัดการเลือกปฏิบัติเท่านั้นไม่ใช่การปรับเทียบ นั่นคือมันวัดว่าคุณสามารถแยกแยะระหว่างคนสองคน (คนป่วยและคนที่มีสุขภาพดี) โดยพิจารณาจากคะแนนความเสี่ยง สำหรับสิ่งนี้จะดูเฉพาะค่าความเสี่ยงสัมพัทธ์ (หรืออันดับหากคุณต้องการเปรียบเทียบการตีความการทดสอบของวิลคอกซัน - แมนน์ - วิทนีย์) ไม่ใช่ค่าสัมบูรณ์ที่คุณควรสนใจตัวอย่างเช่นหากคุณแบ่งความเสี่ยงแต่ละอย่าง ประเมินจากแบบจำลองลอจิสติกของคุณด้วย 2 คุณจะได้รับ AUC เดียวกันและ ROC
เมื่อประเมินโมเดลความเสี่ยงการสอบเทียบก็มีความสำคัญเช่นกัน ในการตรวจสอบสิ่งนี้คุณจะดูผู้ป่วยทุกคนที่มีคะแนนความเสี่ยงประมาณ 0.7 และดูว่าประมาณ 70% ของผู้ป่วยเหล่านี้ป่วยจริงหรือไม่ ทำเช่นนี้สำหรับแต่ละคะแนนความเสี่ยงที่เป็นไปได้ (อาจใช้การปรับให้เรียบ / ถดถอยแบบท้องถิ่น) พล็อตผลและคุณจะได้รับมาตรการกราฟิกของการสอบเทียบ
หากมีโมเดลที่มีทั้งการสอบเทียบที่ดีและการเลือกปฏิบัติที่ดีคุณก็จะมีโมเดลที่ดี :)