|
楼主

楼主 |
发表于 2011-3-16 11:20:09
|
只看该作者
ROC Hard? No, ROC Made Easy!
From LCChien's blog on blogspot
<div class="separator" style="clear: both; text-align: left;">原文載點: http://support.sas.com/resources/papers/proceedings10/222-2010.pdf</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">SAS 裡面並沒有內建繪製 ROC 曲線的程序和語法,這和目前其他統計軟體都已經內建繪製 ROC 曲線的功能的情況比較起來,顯得相當奇怪。使用者在 SAS 的環境底下,必須先用 PROC LOGISTIC 程序將模型估計出來,再將一些報表另存新的檔案,然後才能根據這些新的資料來繪製 ROC 曲線並且計算 AUC 面積。SAS 官網有一段教學,詳情可參照 <a href="http://support.sas.com/kb/25/018.html"><!-- m --><a class="postlink" href="http://support.sas.com/kb/25/018.html">http://support.sas.com/kb/25/018.html</a><!-- m --></a>,但繪製出來的圖形不甚美觀。Kriss Harris 在 SAS Global Forum 2010 發表了一篇技術文件,提供了一個相當實用的巨集程式 %ROC_CUTOFF 讓使用者可以在 SAS 裡面迅速且美觀地畫出 ROC 曲線。</div><div class="separator" style="clear: both; text-align: left;"></div><a name='more'></a>首先,利用一段模擬的資料來當作本篇的範例:<br /><code><pre><div class="separator" style="clear: both; text-align: left;">data blood_for_roc;</div><div class="separator" style="clear: both; text-align: left;">CALL STREAMINIT(400); </div><div class="separator" style="clear: both; text-align: left;">do i = 1 to 40;</div><div class="separator" style="clear: both; text-align: left;">Sputum_Eosinophils = RAND('NORMAL',3, 1); </div><div class="separator" style="clear: both; text-align: left;">cht = 1;</div><div class="separator" style="clear: both; text-align: left;">output;</div><div class="separator" style="clear: both; text-align: left;">end;</div><div class="separator" style="clear: both; text-align: left;">do i = 41 to 80;</div><div class="separator" style="clear: both; text-align: left;">Sputum_Eosinophils = RAND('NORMAL',10, 5); </div><div class="separator" style="clear: both; text-align: left;">cht = 2;</div><div class="separator" style="clear: both; text-align: left;">output;</div><div class="separator" style="clear: both; text-align: left;">end;</div><div class="separator" style="clear: both; text-align: left;">run;</div></pre></code><br /><div class="separator" style="clear: both; text-align: left;">%ROC_CUTOFF 的格式如下所示:</div><code><pre><div class="separator" style="clear: both; text-align: left;">%macro roc_cutoff(DATASET = ,</div><div class="separator" style="clear: both; text-align: left;"> OUTCOME = , </div><div class="separator" style="clear: both; text-align: left;"> OUTCOME_LEV = , </div><div class="separator" style="clear: both; text-align: left;"> XVAR = ,</div><div class="separator" style="clear: both; text-align: left;"> XVAR_LABEL = ,</div><div class="separator" style="clear: both; text-align: left;"> AUC_TABLE = ,</div><div class="separator" style="clear: both; text-align: left;"> CONFUSION = ,</div><div class="separator" style="clear: both; text-align: left;"> CUTOFF = );</div></pre></code><br /><div class="separator" style="clear: both; text-align: left;">每個參數的定義如下:</div><div class="separator" style="clear: both; text-align: left;"></div><ul><li>DATASET = SAS 資料集名稱</li><li>OUTCOME = 類別型的依變數名稱</li><li>OUTCOME_LEV = 依變數內的類別數</li><li>XVAR = 連續型的應變數名稱</li><li>XVAR_LABEL = 應變數的標籤</li><li>AUC_TABLE = 要不要顯示 AUC 表 (Y/N)</li><li>CONFUSION = 要不要顯示 confusion 表 (Y/N)</li><li>CUTOFF = 指定 cutoff 的數字(可留空白不填)</li></ul><br /><div class="separator" style="clear: both; text-align: left;">以模擬的資料來跑 ROC:</div><code><pre>%macro roc_cutoff(DATASET = blood_for_roc ,<br /><div class="separator" style="clear: both; text-align: left;"> OUTCOME = cht , </div><div class="separator" style="clear: both; text-align: left;"> OUTCOME_LEV = 2 /* Number */ , </div><div class="separator" style="clear: both; text-align: left;"> XVAR = Sputum_Eosinophils,</div><div class="separator" style="clear: both; text-align: left;"> XVAR_LABEL = Sputum Eosinophils,</div><div class="separator" style="clear: both; text-align: left;"> AUC_TABLE = Y,</div><div class="separator" style="clear: both; text-align: left;"> CONFUSION = N,</div><div class="separator" style="clear: both; text-align: left;"> CUTOFF = );</div></pre></code><br /><div class="separator" style="clear: both; text-align: left;">結果如下所示:</div><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://www.webpagescreenshot.info/img/806169-32201170649pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.webpagescreenshot.info/img/806169-32201170649pm.png" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">若將CUTOFF 設定成 5,結果如下所示:</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.webpagescreenshot.info/img/258357-32201170742pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.webpagescreenshot.info/img/258357-32201170742pm.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">若將 AUC_TABLE 和 CONFUSION 都設定為 N,則一開頭的兩個表格就不會被秀出來:</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.webpagescreenshot.info/img/29462-32201170811pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.webpagescreenshot.info/img/29462-32201170811pm.png" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">原始碼如下:</div><code><pre><div class="separator" style="clear: both; text-align: left;">/***********************************************************************/</div><div class="separator" style="clear: both; text-align: left;">AUTHOR : KRISS HARRIS</div><div class="separator" style="clear: both; text-align: left;">AUTHOR EMAIL: <!-- e --><a href="mailto:KRISS.5.HARRIS@GSK.COM">KRISS.5.HARRIS@GSK.COM</a><!-- e --></div><div class="separator" style="clear: both; text-align: left;">DATE WRITTEN: JUNE 2009</div><div class="separator" style="clear: both; text-align: left;">MACRO NAME : ROC_CUT-OFF</div><div class="separator" style="clear: both; text-align: left;">PURPOSE : CREATES A PANEL OF GRAPHS WHICH ASSESS THE SENSITIVITY,</div><div class="separator" style="clear: both; text-align: left;"> AND SPECIFICITY OF THE CLASSIFIER, AND THE RAW DATA.</div><div class="separator" style="clear: both; text-align: left;">SAS VERSION : VERSION 9.2</div><div class="separator" style="clear: both; text-align: left;">PARAMETERS :</div><div class="separator" style="clear: both; text-align: left;">-----------------------------------------------------------------------</div><div class="separator" style="clear: both; text-align: left;">NAME TYPE DEFAULT DESCRIPTION AND VALID VALUES</div><div class="separator" style="clear: both; text-align: left;">----------------------------------------- -------- -------- ---------</div><div class="separator" style="clear: both; text-align: left;">DATASET REQUIRED : SOURCE DATASET</div><div class="separator" style="clear: both; text-align: left;">OUTCOME REQUIRED : RESPONSE VARIABLE (CATEGORICAL)</div><div class="separator" style="clear: both; text-align: left;">OUTCOME_LEV REQUIRED : EVENT OF INTEREST. A NUMERICAL LEVEL OF THE OUTCOME</div><div class="separator" style="clear: both; text-align: left;">PARAMETER THAT DEFINES THE EVENT</div><div class="separator" style="clear: both; text-align: left;">(E.G., OUTCOME_LEV=1)</div><div class="separator" style="clear: both; text-align: left;">XVAR REQUIRED : CONTINUOUS PREDICTOR</div><div class="separator" style="clear: both; text-align: left;">XVAR_LABEL OPTIONAL : LABEL OF PREDICTOR IN GRAPHICAL OUTPUT</div><div class="separator" style="clear: both; text-align: left;">AUC_TABLE OPTIONAL Y : Y/N. DISPLAY AREA UNDER CURVE</div><div class="separator" style="clear: both; text-align: left;">CONFUSION OPTIONAL Y : Y/N. DISPLAY CONFUSION MATRIX</div><div class="separator" style="clear: both; text-align: left;">CUTOFF OPTIONAL Y : NUMERICAL VALUE WHICH CALCULATES THE CONFUSION MATRIX</div><div class="separator" style="clear: both; text-align: left;">BASED ON THE INPUTTED CUTOFF</div><div class="separator" style="clear: both; text-align: left;">/**************************************************************************</div><div class="separator" style="clear: both; text-align: left;">/* Data */</div><div class="separator" style="clear: both; text-align: left;">data blood_for_roc;</div><div class="separator" style="clear: both; text-align: left;">CALL STREAMINIT(400); </div><div class="separator" style="clear: both; text-align: left;">do i = 1 to 40;</div><div class="separator" style="clear: both; text-align: left;">Sputum_Eosinophils = RAND('NORMAL',3, 1); </div><div class="separator" style="clear: both; text-align: left;">cht = 1;</div><div class="separator" style="clear: both; text-align: left;">output;</div><div class="separator" style="clear: both; text-align: left;">end;</div><div class="separator" style="clear: both; text-align: left;">do i = 41 to 80;</div><div class="separator" style="clear: both; text-align: left;">Sputum_Eosinophils = RAND('NORMAL',10, 5); </div><div class="separator" style="clear: both; text-align: left;">cht = 2;</div><div class="separator" style="clear: both; text-align: left;">output;</div><div class="separator" style="clear: both; text-align: left;">end;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">%macro roc_cutoff(DATASET = blood_for_roc ,</div><div class="separator" style="clear: both; text-align: left;">OUTCOME = cht , </div><div class="separator" style="clear: both; text-align: left;">OUTCOME_LEV = 2 /* Number */ , </div><div class="separator" style="clear: both; text-align: left;">XVAR = Sputum_Eosinophils,</div><div class="separator" style="clear: both; text-align: left;">XVAR_LABEL = Sputum Eosinophils,</div><div class="separator" style="clear: both; text-align: left;">AUC_TABLE = Y,</div><div class="separator" style="clear: both; text-align: left;">CONFUSION = N,</div><div class="separator" style="clear: both; text-align: left;">CUTOFF = </div><div class="separator" style="clear: both; text-align: left;">;(</div><div class="separator" style="clear: both; text-align: left;">;*****************************************************************%</div><div class="separator" style="clear: both; text-align: left;">%* GETTING ROC OUTPUT FROM MODEL *;</div><div class="separator" style="clear: both; text-align: left;">;*****************************************************************%</div><div class="separator" style="clear: both; text-align: left;">%LET OUTCOME_LEV = %SYSFUNC(TRANWRD(&OUTCOME_LEV,%STR(%"),));</div><div class="separator" style="clear: both; text-align: left;">%LET OUTCOME_LEV = %SYSFUNC(TRANWRD(&OUTCOME_LEV,%STR(%'),)); </div><div class="separator" style="clear: both; text-align: left;">ods output Association = roc_association (WHERE = (UPCASE(LABEL2) = "C")); </div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">proc logistic data=&dataset outest = outest;</div><div class="separator" style="clear: both; text-align: left;">model &OUTCOME. (event = "&OUTCOME_LEV.") = &XVAR./EXPB outroc=ROCData;</div><div class="separator" style="clear: both; text-align: left;">output out = roctest p = p ;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">DATA ROCData;</div><div class="separator" style="clear: both; text-align: left;">SET ROCData; </div><div class="separator" style="clear: both; text-align: left;">INDEX =1;</div><div class="separator" style="clear: both; text-align: left;">RUN;</div><div class="separator" style="clear: both; text-align: left;">DATA Outest (KEEP=INTERCEPT &XVAR. INDEX);</div><div class="separator" style="clear: both; text-align: left;">SET Outest; </div><div class="separator" style="clear: both; text-align: left;">INDEX =1;</div><div class="separator" style="clear: both; text-align: left;">RUN;</div><div class="separator" style="clear: both; text-align: left;">/* Calculating X value */</div><div class="separator" style="clear: both; text-align: left;">DATA _merge;</div><div class="separator" style="clear: both; text-align: left;">MERGE ROCData Outest;</div><div class="separator" style="clear: both; text-align: left;">BY INDEX;</div><div class="separator" style="clear: both; text-align: left;">SPEC = 1-_1MSPEC_;</div><div class="separator" style="clear: both; text-align: left;">YI = (_SENSIT_ + SPEC) - 1;</div><div class="separator" style="clear: both; text-align: left;">N = _POS_+ _NEG_+ _FALPOS_+ _FALNEG_;</div><div class="separator" style="clear: both; text-align: left;">TA = (_POS_ + _NEG_)/N;</div><div class="separator" style="clear: both; text-align: left;">X_VALUE = (LOG(_PROB_/(1-_PROB_))-INTERCEPT)/&XVAR.;</div><div class="separator" style="clear: both; text-align: left;">IF (_NEG_+_FALNEG_) NE 0 THEN DO;</div><div class="separator" style="clear: both; text-align: left;">NPV = _NEG_/(_NEG_ +_FALNEG_);</div><div class="separator" style="clear: both; text-align: left;">END;</div><div class="separator" style="clear: both; text-align: left;">IF (_POS_+_FALPOS_) NE 0 THEN DO;</div><div class="separator" style="clear: both; text-align: left;">PPV = _POS_/(_POS_ +_FALPOS_);</div><div class="separator" style="clear: both; text-align: left;">END;</div><div class="separator" style="clear: both; text-align: left;">IF</div><div class="separator" style="clear: both; text-align: left;">((_POS_+_FALPOS_)*(_POS_+_FALNEG_)*(_NEG_+_FALPOS_)*(_NEG_+_FALNEG_)) NE 0</div><div class="separator" style="clear: both; text-align: left;">THEN DO;</div><div class="separator" style="clear: both; text-align: left;">MCC = ((_POS_*_NEG_)-(_FALPOS_*_FALNEG_))/</div><div class="separator" style="clear: both; text-align: left;">SQRT(((_POS_+_FALPOS_)*(_POS_+_FALNEG_)*(_NEG_+_FALPOS_)*(_NEG_+_FALNEG_)));</div><div class="separator" style="clear: both; text-align: left;">END;</div><div class="separator" style="clear: both; text-align: left;">RUN;</div><div class="separator" style="clear: both; text-align: left;">/* Merging in the original data, so that this can be plotted to */</div><div class="separator" style="clear: both; text-align: left;">proc sql;</div><div class="separator" style="clear: both; text-align: left;">create table merge2 as</div><div class="separator" style="clear: both; text-align: left;">select a.*, b.&XVAR. as XVAR1, b.&OUTCOME., b.p,</div><div class="separator" style="clear: both; text-align: left;">case when b.&OUTCOME. = &OUTCOME_LEV. then 3</div><div class="separator" style="clear: both; text-align: left;">else 4 end as Index1</div><div class="separator" style="clear: both; text-align: left;">from _merge as a right join Roctest as b</div><div class="separator" style="clear: both; text-align: left;">on a._PROB_ = b.p ;</div><div class="separator" style="clear: both; text-align: left;">quit;</div><div class="separator" style="clear: both; text-align: left;">data merge3;</div><div class="separator" style="clear: both; text-align: left;">set merge2;</div><div class="separator" style="clear: both; text-align: left;">string_check = anyalpha(&OUTCOME.);</div><div class="separator" style="clear: both; text-align: left;">if string_check = 0 then &OUTCOME._char = strip(put(&OUTCOME., best.))</div><div class="separator" style="clear: both; text-align: left;">;</div><div class="separator" style="clear: both; text-align: left;">else &OUTCOME. = &OUTCOME._char;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">;*****************************************************************%</div><div class="separator" style="clear: both; text-align: left;">%* CALCULATING X Value CUT-OFFS for Particular Specificities and </div><div class="separator" style="clear: both; text-align: left;">Sensitivities and Vice Versa *;</div><div class="separator" style="clear: both; text-align: left;">;*****************************************************************%</div><div class="separator" style="clear: both; text-align: left;">proc sql;</div><div class="separator" style="clear: both; text-align: left;">create table One_Hundred_PC_Sens as</div><div class="separator" style="clear: both; text-align: left;">select max(X_VALUE) as max_x format 10.2</div><div class="separator" style="clear: both; text-align: left;">from _merge</div><div class="separator" style="clear: both; text-align: left;">where _SENSIT_ = 1;</div><div class="separator" style="clear: both; text-align: left;">quit;</div><div class="separator" style="clear: both; text-align: left;">proc sql;</div><div class="separator" style="clear: both; text-align: left;">create table sens_spec as</div><div class="separator" style="clear: both; text-align: left;">select *, abs(_SENSIT_ - SPEC) as abs_sens_spec, min(calculated abs_sens_spec) as min</div><div class="separator" style="clear: both; text-align: left;">from _merge;</div><div class="separator" style="clear: both; text-align: left;">quit;</div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;">proc sql;</div><div class="separator" style="clear: both; text-align: left;">create table sens_spec_intersection as</div><div class="separator" style="clear: both; text-align: left;">select X_VALUE format 10.2</div><div class="separator" style="clear: both; text-align: left;">from sens_spec </div><div class="separator" style="clear: both; text-align: left;">where abs_sens_spec = min;</div><div class="separator" style="clear: both; text-align: left;">quit;</div><div class="separator" style="clear: both; text-align: left;">proc sql;</div><div class="separator" style="clear: both; text-align: left;">create table One_Hundred_PC_Spec as</div><div class="separator" style="clear: both; text-align: left;">select min(X_VALUE) as min_x format 10.2</div><div class="separator" style="clear: both; text-align: left;">from _merge</div><div class="separator" style="clear: both; text-align: left;">where spec = 1;</div><div class="separator" style="clear: both; text-align: left;">quit;</div><div class="separator" style="clear: both; text-align: left;">/* Fetching the values */</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(Roc_association,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_AUC=%sysfunc(varnum(&dsid,nValue2));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let AUC=%sysfunc(getvarn(&dsid,&num_AUC));</div><div class="separator" style="clear: both; text-align: left;">%let AUC_format=%sysfunc(putn(&AUC,bestd10.2));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(One_Hundred_PC_Sens,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_Sens=%sysfunc(varnum(&dsid,max_x));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let Sens=%sysfunc(getvarn(&dsid,&num_Sens));</div><div class="separator" style="clear: both; text-align: left;">%let Sens_format=%sysfunc(putn(&Sens,bestd10.2));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(One_Hundred_PC_Spec,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_Spec=%sysfunc(varnum(&dsid,min_x));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let Spec=%sysfunc(getvarn(&dsid,&num_Spec));</div><div class="separator" style="clear: both; text-align: left;">%let Spec_format=%sysfunc(putn(&Spec,bestd10.2));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(sens_spec_intersection,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_section=%sysfunc(varnum(&dsid,X_VALUE));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let section=%sysfunc(getvarn(&dsid,&num_section));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%if &CUTOFF = %NRSTR() %then %do;</div><div class="separator" style="clear: both; text-align: left;">%let section2 = §ion;</div><div class="separator" style="clear: both; text-align: left;">%let section_format=%sysfunc(putn(&section2,bestd10.2));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%end;</div><div class="separator" style="clear: both; text-align: left;">%else %do;</div><div class="separator" style="clear: both; text-align: left;">%let section2 = &CUTOFF;</div><div class="separator" style="clear: both; text-align: left;">%let section_format = &CUTOFF;</div><div class="separator" style="clear: both; text-align: left;">%end;</div><div class="separator" style="clear: both; text-align: left;">;*****************************************************************%</div><div class="separator" style="clear: both; text-align: left;">%* 2*2 Tables *;</div><div class="separator" style="clear: both; text-align: left;">;*****************************************************************%</div><div class="separator" style="clear: both; text-align: left;">data freq_input;</div><div class="separator" style="clear: both; text-align: left;">set merge3;</div><div class="separator" style="clear: both; text-align: left;">if XVAR1 ne .;</div><div class="separator" style="clear: both; text-align: left;">if XVAR1 <= &section2 then new_result = 1;</div><div class="separator" style="clear: both; text-align: left;">else new_result = 0;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">ods output CrossTabFreqs = CrossTabFreqs;</div><div class="separator" style="clear: both; text-align: left;">proc freq data = freq_input;</div><div class="separator" style="clear: both; text-align: left;">tables new_result * &OUTCOME._char / NOROW NOCOL;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">data crossTabFreqs_ref;</div><div class="separator" style="clear: both; text-align: left;">set CrossTabFreqs;</div><div class="separator" style="clear: both; text-align: left;">if &OUTCOME._char ne "";</div><div class="separator" style="clear: both; text-align: left;">if new_result ne .;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;">data TP;</div><div class="separator" style="clear: both; text-align: left;">set CrossTabFreqs_ref;</div><div class="separator" style="clear: both; text-align: left;">if new_result = 0 and &OUTCOME._char = &OUTCOME_LEV.;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">data FP;</div><div class="separator" style="clear: both; text-align: left;">set CrossTabFreqs_ref;</div><div class="separator" style="clear: both; text-align: left;">if new_result = 0 and &OUTCOME._char ne &OUTCOME_LEV.;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">data FN;</div><div class="separator" style="clear: both; text-align: left;">set CrossTabFreqs_ref;</div><div class="separator" style="clear: both; text-align: left;">if new_result = 1 and &OUTCOME._char = &OUTCOME_LEV.;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">data TN;</div><div class="separator" style="clear: both; text-align: left;">set CrossTabFreqs_ref;</div><div class="separator" style="clear: both; text-align: left;">if new_result = 1 and &OUTCOME._char ne &OUTCOME_LEV.;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">/* Fetching the values */</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(TP,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_TP=%sysfunc(varnum(&dsid,Frequency));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let TP=%sysfunc(getvarn(&dsid,&num_TP));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(FP,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_FP=%sysfunc(varnum(&dsid,Frequency));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let FP=%sysfunc(getvarn(&dsid,&num_FP));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(FN,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_FN=%sysfunc(varnum(&dsid,Frequency));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let FN=%sysfunc(getvarn(&dsid,&num_FN));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(TN,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_TN=%sysfunc(varnum(&dsid,Frequency));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let TN=%sysfunc(getvarn(&dsid,&num_TN));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(TP,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_TP_per=%sysfunc(varnum(&dsid,Percent));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let TP_per=%sysfunc(getvarn(&dsid,&num_TP_per));</div><div class="separator" style="clear: both; text-align: left;">%let TP_format=%sysfunc(putn(&TP_per,best3.0));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(FP,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_FP_per=%sysfunc(varnum(&dsid,Percent));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let FP_per=%sysfunc(getvarn(&dsid,&num_FP_per));</div><div class="separator" style="clear: both; text-align: left;">%let FP_format=%sysfunc(putn(&FP_per,best3.0));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(FN,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_FN_per=%sysfunc(varnum(&dsid,Percent));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let FN_per=%sysfunc(getvarn(&dsid,&num_FN_per));</div><div class="separator" style="clear: both; text-align: left;">%let FN_format=%sysfunc(putn(&FN_per,best3.0));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(TN,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_TN_per=%sysfunc(varnum(&dsid,Percent));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let TN_per=%sysfunc(getvarn(&dsid,&num_TN_per));</div><div class="separator" style="clear: both; text-align: left;">%let TN_format=%sysfunc(putn(&TN_per,best3.0));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">/* Selecting distinct OUTCOME values */</div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;">proc sql;</div><div class="separator" style="clear: both; text-align: left;">create table distinct_values as</div><div class="separator" style="clear: both; text-align: left;">select distinct &OUTCOME.</div><div class="separator" style="clear: both; text-align: left;">from &dataset;</div><div class="separator" style="clear: both; text-align: left;">quit; </div><div class="separator" style="clear: both; text-align: left;">data LEVEL NOTLEVEL;</div><div class="separator" style="clear: both; text-align: left;"> set distinct_values;</div><div class="separator" style="clear: both; text-align: left;"> if &OUTCOME. = UPCASE(&OUTCOME_LEV.) then output LEVEL;</div><div class="separator" style="clear: both; text-align: left;">else OUTPUT NOTLEVEL; </div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">/* Turning it to character if it's not */</div><div class="separator" style="clear: both; text-align: left;">data level_char;</div><div class="separator" style="clear: both; text-align: left;">set level;</div><div class="separator" style="clear: both; text-align: left;">string_check = anyalpha(&OUTCOME.);</div><div class="separator" style="clear: both; text-align: left;">if string_check = 0 then &OUTCOME._char2 = strip(put(&OUTCOME., best.))</div><div class="separator" style="clear: both; text-align: left;">;</div><div class="separator" style="clear: both; text-align: left;">else &OUTCOME. = &OUTCOME._char2;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">data notlevel_char;</div><div class="separator" style="clear: both; text-align: left;">set notlevel;</div><div class="separator" style="clear: both; text-align: left;">string_check = anyalpha(&OUTCOME.);</div><div class="separator" style="clear: both; text-align: left;">if string_check = 0 then &OUTCOME._char2 = strip(put(&OUTCOME., best.))</div><div class="separator" style="clear: both; text-align: left;">;</div><div class="separator" style="clear: both; text-align: left;">else &OUTCOME. = &OUTCOME._char2;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">/* Fetching the distinct levels */</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(level_char,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_level=%sysfunc(varnum(&dsid,&OUTCOME._char2));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let level=%sysfunc(getvarc(&dsid,&num_level));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">%let dsid=%sysfunc(open(notlevel_char,i));</div><div class="separator" style="clear: both; text-align: left;">%let num_notlevel=%sysfunc(varnum(&dsid,&OUTCOME._char2));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(fetch(&dsid,1));</div><div class="separator" style="clear: both; text-align: left;">%let notlevel=%sysfunc(getvarc(&dsid,&num_notlevel));</div><div class="separator" style="clear: both; text-align: left;">%let rc=%sysfunc(close(&dsid));</div><div class="separator" style="clear: both; text-align: left;">/* Plot */</div><div class="separator" style="clear: both; text-align: left;">ods html style = statistical;</div><div class="separator" style="clear: both; text-align: left;">proc template;</div><div class="separator" style="clear: both; text-align: left;">define statgraph sgplot;</div><div class="separator" style="clear: both; text-align: left;">mvar OUTCOME_TITLE OUTCOME_LEV OUTCOME AUC Sens Section2 Specif level notlevel confusion </div><div class="separator" style="clear: both; text-align: left;">auc_table</div><div class="separator" style="clear: both; text-align: left;">XVAR_LABEL TP FP FN TN TP_per FP_per FN_per TN_per Sensitivity Specificity; </div><div class="separator" style="clear: both; text-align: left;">dynamic XVAR1 YVAR1;</div><div class="separator" style="clear: both; text-align: left;">begingraph;</div><div class="separator" style="clear: both; text-align: left;">EntryTitle "Operating Characterisitcs for " OUTCOME_TITLE " = " OUTCOME_LEV /;</div><div class="separator" style="clear: both; text-align: left;">if (confusion = "Y") </div><div class="separator" style="clear: both; text-align: left;">EntryFootnote textattrs=(color = red )"*" textattrs=()"Confusion Matrix is for the "</div><div class="separator" style="clear: both; text-align: left;">XVAR_LABEL " at the cutoff = " textattrs=(color = blue ) Section2 ; </div><div class="separator" style="clear: both; text-align: left;">*EntryFootnote "At cutoff, Sensitivity = " textattrs=(color = blue ) Sensitivity " and </div><div class="separator" style="clear: both; text-align: left;">Specificity = " textattrs=(color = blue ) Specificity ;</div><div class="separator" style="clear: both; text-align: left;">endif;</div><div class="separator" style="clear: both; text-align: left;">layout lattice / columns=1 rows=2 rowgutter=2px columngutter=2px</div><div class="separator" style="clear: both; text-align: left;"> rowweights=(.7 .3 );</div><div class="separator" style="clear: both; text-align: left;"> columnaxes;</div><div class="separator" style="clear: both; text-align: left;"> columnaxis / label=XVAR_LABEL;</div><div class="separator" style="clear: both; text-align: left;">endcolumnaxes;</div><div class="separator" style="clear: both; text-align: left;"> sidebar / align=right; </div><div class="separator" style="clear: both; text-align: left;"> layout gridded / border = false; </div><div class="separator" style="clear: both; text-align: left;">layout overlay;</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;">DiscreteLegend "SERIES" "SERIES1" / location = outside ACROSS = 1 down </div><div class="separator" style="clear: both; text-align: left;">= 2; </div><div class="separator" style="clear: both; text-align: left;">endlayout; </div><div class="separator" style="clear: both; text-align: left;">layout overlay;</div><div class="separator" style="clear: both; text-align: left;">*DiscreteLegend "SERIES3" / location = outside;</div><div class="separator" style="clear: both; text-align: left;">endlayout; </div><div class="separator" style="clear: both; text-align: left;">endlayout; </div><div class="separator" style="clear: both; text-align: left;"> </div><div class="separator" style="clear: both; text-align: left;"> endsidebar; </div><div class="separator" style="clear: both; text-align: left;">layout overlay / cycleattrs=true xaxisopts = (Label = XVAR_LABEL) yaxisopts=( </div><div class="separator" style="clear: both; text-align: left;">Label="Proportion" type=linear linearopts=( tickvaluelist=( 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8</div><div class="separator" style="clear: both; text-align: left;">0.9 1 ) viewmin=0 viewmax=1 ) );</div><div class="separator" style="clear: both; text-align: left;"> StepPlot X=X_VALUE Y=SPEC / primary=true LegendLabel="Specificity" NAME="SERIES";</div><div class="separator" style="clear: both; text-align: left;">StepPlot X=X_VALUE Y=_SENSIT_ / LegendLabel="Sensitivity" NAME="SERIES1";</div><div class="separator" style="clear: both; text-align: left;">Referenceline x = Section2 / LINEATTRS = (color = black pattern = 2);</div><div class="separator" style="clear: both; text-align: left;">if (confusion = "Y") </div><div class="separator" style="clear: both; text-align: left;">/* 2 by 2 */</div><div class="separator" style="clear: both; text-align: left;">layout gridded / columns=3 rows = 3</div><div class="separator" style="clear: both; text-align: left;"> halign = CENTER valign = top border=true </div><div class="separator" style="clear: both; text-align: left;">opaque=true backgroundcolor=GraphWalls:color location = outside; </div><div class="separator" style="clear: both; text-align: left;">entry halign=center " " / textattrs=GraphValueText; </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center level / textattrs=(WEIGHT=bold) /* Setting the titles to bold */ </div><div class="separator" style="clear: both; text-align: left;"> ;</div><div class="separator" style="clear: both; text-align: left;">entry halign=center notlevel / textattrs=(WEIGHT=bold); </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center "Event" / textattrs=(WEIGHT=bold) ; </div><div class="separator" style="clear: both; text-align: left;">entry halign=center TP textattrs=(STYLE=ITALIC color = blue )"(" TP_per "%)" /* </div><div class="separator" style="clear: both; text-align: left;">Formatting the percentages */ ; </div><div class="separator" style="clear: both; text-align: left;">entry halign=center FP textattrs=(STYLE=ITALIC color = blue )"(" FP_per "%)" ; </div><div class="separator" style="clear: both; text-align: left;">entry halign=center "Non Event" / textattrs=(WEIGHT=bold); </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center FN textattrs=(STYLE=ITALIC color = blue )"(" FN_per "%)"; </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center TN textattrs=(STYLE=ITALIC color = blue )"(" TN_per "%)"; </div><div class="separator" style="clear: both; text-align: left;"> </div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;">endif;</div><div class="separator" style="clear: both; text-align: left;">if (auc_table = "Y") </div><div class="separator" style="clear: both; text-align: left;">layout gridded / columns=4 rows = 1</div><div class="separator" style="clear: both; text-align: left;"> halign = center valign = top border=true </div><div class="separator" style="clear: both; text-align: left;">opaque=true backgroundcolor=GraphWalls:color location = outside; </div><div class="separator" style="clear: both; text-align: left;">entry halign=center "AUC " / textattrs=(WEIGHT=bold); </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center "100% Sensitivity: " / textattrs=(WEIGHT=bold); </div><div class="separator" style="clear: both; text-align: left;">entry halign=center "Intersection: " / textattrs=(WEIGHT=bold); </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center "100% Specificity: " / textattrs=(WEIGHT=bold) ; </div><div class="separator" style="clear: both; text-align: left;">entry halign=center AUC; </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center Sens; </div><div class="separator" style="clear: both; text-align: left;"> entry halign=center Section2; </div><div class="separator" style="clear: both; text-align: left;">entry halign=center Specif ; </div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;">endif;</div><div class="separator" style="clear: both; text-align: left;">*DiscreteLegend "SERIES" "SERIES1" / location = outside;</div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;">layout lattice / columns=1 rows=2 rowgutter=2px columngutter=2px</div><div class="separator" style="clear: both; text-align: left;"> rowweights=(.5 .5 ) COLUMNDATARANGE = Union;</div><div class="separator" style="clear: both; text-align: left;">columnaxes;</div><div class="separator" style="clear: both; text-align: left;"> columnaxis / label=XVAR_LABEL;</div><div class="separator" style="clear: both; text-align: left;"> endcolumnaxes;</div><div class="separator" style="clear: both; text-align: left;"> layout gridded / AUTOALIGN=NONE columns=3 rows = 3</div><div class="separator" style="clear: both; text-align: left;"> halign = right valign = top border=true </div><div class="separator" style="clear: both; text-align: left;">opaque=true backgroundcolor=GraphWalls:color location = outside; </div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;">layout overlay / yaxisopts=( Label=" " );</div><div class="separator" style="clear: both; text-align: left;">Scatterplot x=XVAR1 y = OUTCOME / group = OUTCOME INDEX = Index1 NAME = </div><div class="separator" style="clear: both; text-align: left;">"SERIES3";</div><div class="separator" style="clear: both; text-align: left;">Referenceline x = Section2 / LINEATTRS = (color = black pattern = 2);</div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;">layout overlay / yaxisopts=( Label=" " );</div><div class="separator" style="clear: both; text-align: left;">Boxplot y = XVAR1 x = OUTCOME / ORIENT = horizontal;</div><div class="separator" style="clear: both; text-align: left;">Referenceline x = Section2 / LINEATTRS = (color = black pattern = 2);</div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;">endlayout;</div><div class="separator" style="clear: both; text-align: left;">endgraph;</div><div class="separator" style="clear: both; text-align: left;">end;</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">%let OUTCOME_TITLE = &OUTCOME;</div><div class="separator" style="clear: both; text-align: left;">%let OUTCOME_LEV = &OUTCOME_LEV;</div><div class="separator" style="clear: both; text-align: left;">%let OUTCOME = &OUTCOME._char;</div><div class="separator" style="clear: both; text-align: left;">%let AUC = &AUC_format;</div><div class="separator" style="clear: both; text-align: left;">%let Sens = &Sens_format;</div><div class="separator" style="clear: both; text-align: left;">%let Section2 = &Section_format;</div><div class="separator" style="clear: both; text-align: left;">%let Specif = &Spec_format;</div><div class="separator" style="clear: both; text-align: left;">%let level = &level;</div><div class="separator" style="clear: both; text-align: left;">%let notlevel = ¬level;</div><div class="separator" style="clear: both; text-align: left;">%let confusion = &confusion;</div><div class="separator" style="clear: both; text-align: left;">%let auc_table = &auc_table;</div><div class="separator" style="clear: both; text-align: left;">%let XVAR_LABEL = &XVAR_LABEL;</div><div class="separator" style="clear: both; text-align: left;">%let TP = &TP;</div><div class="separator" style="clear: both; text-align: left;">%let FP = &FP;</div><div class="separator" style="clear: both; text-align: left;">%let FN = &FN;</div><div class="separator" style="clear: both; text-align: left;">%let TN = &TN;</div><div class="separator" style="clear: both; text-align: left;">%let TP_per = &TP_format;</div><div class="separator" style="clear: both; text-align: left;">%let FP_per = &FP_format;</div><div class="separator" style="clear: both; text-align: left;">%let FN_per = &FN_format;</div><div class="separator" style="clear: both; text-align: left;">%let TN_per = &TN_format;</div><div class="separator" style="clear: both; text-align: left;">ods listing sge = on;</div><div class="separator" style="clear: both; text-align: left;">proc sgrender data=merge3 template=sgplot;</div><div class="separator" style="clear: both; text-align: left;">dynamic XVAR1 = "XVAR1" YVAR1 = "YVAR1";</div><div class="separator" style="clear: both; text-align: left;">run;</div><div class="separator" style="clear: both; text-align: left;">ods listing close;</div><div class="separator" style="clear: both; text-align: left;">proc sql;</div><div class="separator" style="clear: both; text-align: left;">drop table roc_association, Roctest, ROCData, Outest, _merge, merge2, merge3, </div><div class="separator" style="clear: both; text-align: left;">One_Hundred_PC_Sens, </div><div class="separator" style="clear: both; text-align: left;">sens_spec, sens_spec_intersection, One_Hundred_PC_Spec, freq_input,</div><div class="separator" style="clear: both; text-align: left;">CrossTabFreqs, crossTabFreqs_ref, TP, FP, FN, TN, distinct_values, </div><div class="separator" style="clear: both; text-align: left;">LEVEL, NOTLEVEL, level_char, notlevel_char;</div><div class="separator" style="clear: both; text-align: left;">quit;</div><div class="separator" style="clear: both; text-align: left;">%mend roc_cutoff;</div></pre></code><br /><div class="separator" style="clear: both; text-align: left;"><b>CONTACT INFORMATION</b></div><div class="separator" style="clear: both; text-align: left;">Your comments and questions are valued and encouraged. Please contact the author at:</div><div class="separator" style="clear: both; text-align: left;">Kriss Harris</div><div class="separator" style="clear: both; text-align: left;">GlaxoSmithKline</div><div class="separator" style="clear: both; text-align: left;">Mail Stop : 1B106003</div><div class="separator" style="clear: both; text-align: left;">Gunnels Wood Road</div><div class="separator" style="clear: both; text-align: left;">Stevenage SG1 2NY</div><div class="separator" style="clear: both; text-align: left;">Phone: 01438 76 4904</div><div class="separator" style="clear: both; text-align: left;">Email: <!-- e --><a href="mailto:Kriss.5.Harris@gsk.com">Kriss.5.Harris@gsk.com</a><!-- e --></div><div class="separator" style="clear: both; text-align: left;">Web: <!-- m --><a class="postlink" href="http://www.krissharris.co.uk">http://www.krissharris.co.uk</a><!-- m --></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-5224678573494442305?l=sugiclub.blogspot.com' alt='' /></div> |
|