%macro MultAUC(version, data=_last_, response=); %let time = %sysfunc(datetime()); %if &data=_last_ %then %let data=&syslast; /* Define macro for checking inputs /---------------------------------------------------------------------*/ %macro existchk(data=, var=, dmsg=e, vmsg=e); %global status; %let status=ok; %if &dmsg=e %then %let dmsg=ERROR; %else %if &dmsg=w %then %let dmsg=WARNING; %else %let dmsg=NOTE; %if &vmsg=e %then %let vmsg=ERROR; %else %if &vmsg=w %then %let vmsg=WARNING; %else %let vmsg=NOTE; %if &data ne %then %do; %if %sysfunc(exist(&data)) ne 1 %then %do; %put &dmsg: Data set %upcase(&data) not found.; %let status=nodata; %end; %else %if &var ne %then %do; %let dsid=%sysfunc(open(&data)); %if &dsid %then %do; %let i=1; %do %while (%scan(&var,&i) ne %str() ); %let var&i=%scan(&var,&i); %if %sysfunc(varnum(&dsid,&&var&i))=0 %then %do; %put &vmsg: Variable %upcase(&&var&i) not found in data %upcase(&data).; %let status=novar; %end; %let i=%eval(&i+1); %end; %let rc=%sysfunc(close(&dsid)); %end; %else %put ERROR: Could not open data set &data.; %end; %end; %else %do; %put &dmsg: Data set not specified.; %let status=nodata; %end; %mend; /* Version and debug options /---------------------------------------------------------------------*/ %let _version = 1.0; %if &version ne %then %put NOTE: &sysmacroname macro Version &_version..; %let _opts = %sysfunc(getoption(notes)); %if %index(%upcase(&version),DEBUG) %then %do; options notes mprint %if %index(%upcase(&version),DEBUG2) %then mlogic symbolgen; ; ods select all; %put _user_; %end; %else %do; options nonotes nomprint nomlogic nosymbolgen; ods exclude all; %end; /* Check for newer version /---------------------------------------------------------------------*/ %let _notfound=0; filename _ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat' termstr=crlf; data _null_; infile _ver end=_eof; input name:$15. ver; if upcase(name)="&sysmacroname" then do; call symput("_newver",ver); stop; end; if _eof then call symput("_notfound",1); run; options notes; %if &syserr ne 0 or &_notfound=1 %then %put NOTE: Unable to check for newer version of &sysmacroname macro.; %else %if %sysevalf(&_newver > &_version) %then %do; %put NOTE: A newer version of the &sysmacroname macro is available at; %put NOTE- this location: http://support.sas.com/ ; %end; %if %index(%upcase(&version),DEBUG)=0 %then options nonotes;; /* Check required data= /---------------------------------------------------------------------*/ %if &response= %then %let response=_from_; %existchk(data=&data, var=&response) %if &status=nodata or &status=novar %then %goto exit; /* Create character response, get levels, and generate all pairs /---------------------------------------------------------------------*/ proc datasets nolist nowarn; delete _Aij; run; quit; data _data; set &data; length _response $ 29; if not missing(&response); _response=cats(&response||''); run; proc freq data=_data; table _response / out=_rvals; run; proc transpose data=_rvals out=_rvals; var _response; run; data _pairs; set _rvals; length L1 L2 $ 29; array col (*) col:; nlvls=dim(col); cmb=comb(nlvls,2); call symput('cmb',cats(cmb)); do j=1 to cmb; call allcomb(j, 2, of col[*]); L1=cats(col1||''); L2=cats(col2||''); if L1>L2 then do; L1tmp=L1; L1=L2; L2=L1tmp; end; keep L1 L2; output; end; run; /* Define & run macro to compute pairwise Aij /---------------------------------------------------------------------*/ %macro Aij; %do k=1 %to &cmb; data _null_; cmb=&k; set _pairs point=cmb; call symput("i",cats(L1)); call symput("j",cats(L2)); stop; run; proc npar1way data=_data wilcoxon; where _response in ("&i","&j"); class _response; var ip_&i ip_&j; ods output wilcoxonscores=_sumranks; run; %if &syserr %then %let status=np1err; data _pairAij; set _sumranks end=eof; length Level1 Level2 $29; retain num logn; by variable; if first.variable then logn=0; logn=logn+log(n); if index(variable,class) then num=sumofscores-n*(n+1)/2; if last.variable then Aij+num/(2*exp(logn)); keep Level: Aij; if eof then do; Level1="&i"; Level2="&j"; output; end; run; %if &syserr %then %let status=aijerr; proc append base=_Aij data=_pairAij; run; %end; %mend Aij; %Aij %if &status=np1err or &status=aijerr %then %goto exit; /* Compute & display multi-level AUC as mean of the Aij /---------------------------------------------------------------------*/ proc summary data=_Aij; var Aij; output out=_MultAUC(keep=AUC) mean=AUC; run; ods select all; proc print data=_MultAUC noobs; title "Multi-level AUC"; run; proc print data=_Aij label; id Level:; var Aij; title "Pairwise AUC"; label Aij="AUC"; run; /* Clean up /---------------------------------------------------------------------*/ %exit: %if %index(%upcase(&version),DEBUG)=0 %then %do; proc datasets nolist nowarn; delete _data _rvals _sumranks _pairs _pairaij; run; quit; %end; %if %index(%upcase(&version),DEBUG) %then %do; options nomprint nomlogic nosymbolgen; %put _user_; %end; title; %let status=; ods select all; options &_opts; %let time = %sysfunc(round(%sysevalf(%sysfunc(datetime()) - &time), 0.01)); %put NOTE: The &sysmacroname macro used &time seconds.; %mend MultAUC;