*! version 6.0.0 30nov1999 (STB-53: sg120.1) program define _roccom1, rclass /* Independent (uncorrelated) ROC curves */ version 6 syntax varlist(numeric min=2 max=2) [if] [in] [ fweight], by(varname) /* */ [ Connect(string) TEST(string) Level(integer $S_level) /* */ Symbol(string) Bands(string) XLAbel(string) YLAbel(string) /* */ XLIne(string) YLIne(string) noGraph SEParate BINormal noREFline * ] marksample touse tempvar cut p w spec sens ntouse tokenize `varlist' local D = `"`1'"' local C = `"`2'"' tokenize `options' cap assert `D'==0 | `D'==1 if `touse' if _rc~=0 { noi di in red "true status variable `D' must be 0 or 1" exit 198 } qui summ `D' if `touse', meanonly if r(min) == r(max) { di in red "Outcome does not vary" exit 198 } if "`table'"~="" { tabulate `D' `C' [`weight'`exp'] if `touse' } if "`by'"=="" { di in red "must specify by() option" exit 198 } local Gc "`by'" markout `touse' `Gc', strok local type: type `Gc' tempvar bygrp qui egen `bygrp'=group(`Gc') if `touse' qui sum `bygrp' if `touse', meanonly local bymax = r(max) tempfile gphfile local sensgr=" " if "`test'"~= "" { capture di `test'[1,1] if _rc~=0 { noi di in red "matrix `test' not found" exit 198 } local rows = colsof(`test') capture assert `rows'==`bymax' if _rc~=0 { noi di in red "matrix `test' not of correct dimensions" exit 198 } } /* BEGIN-create freq weighted summary data */ if `"`weight'"' =="" { tempvar wv qui gen int `wv' = 1 if `touse' local weight="fweight" } else { tempvar wv qui gen double `wv' `exp' } tempvar newwt sort `touse' `bygrp' `D' `C' qui by `touse' `bygrp' `D' `C': gen `newwt'=sum(`wv') if `touse' qui by `touse' `bygrp' `D' `C': replace `newwt'=. if _n~=_N qui replace `newwt'=. if `newwt'==0 qui replace `touse'=0 if `newwt'==. qui replace `wv'=`newwt' local wt=`"[fweight=`wv']"' tempvar MN sort `touse' `bygrp' `D' `C' qui by `touse' `bygrp' `D' : gen long `MN' = sum(`wv') qui by `touse' `bygrp' `D' : replace `MN' = `MN'[_N] qui replace `MN'=. if `touse'==0 drop `newwt' /* END -create freq weighted summary data */ local i 1 while `i' <= `bymax' { preserve qui keep if `touse' & `bygrp'==`i' qui keep `D' `C' `wv' `by' `bygrp' qui logistic `D' `C' `wt', asis tempvar sens spec qui lsens, nograph gensens(`sens') genspec(`spec') if _b[`C']<0 { tempvar mark qui gen int `mark'=1 if `sens'==1 & `spec'==1 qui replace `mark'=1 if `sens'==0 & `spec'==0 qui replace `sens' = 1 -`sens' if `mark'!=1 qui replace `spec' = 1 -`spec' if `mark'!=1 } qui roctab `D' `C' `wt' , nogr level(`level') qui gen N=r(N) qui gen area=r(area) qui gen se=r(se) qui gen lb=r(lb) qui gen ub=r(ub) local group=`Gc' if substr("`type'",1,3)=="str" { qui gen `type' bygrp= "`group'" } else { qui gen `type' bygrp= `group' } rename `sens' sens`i' local troc="0"+string(round(area,0.0001)) local aroc=`"`group' ROC area: `troc'"' label var sens`i' `"`aroc'"' qui gen double x = 1-`spec' local sensgr="`sensgr' sens`i'" qui keep bygrp x sens`i' N area se lb ub `D' `C' `wv' `by' qui gen int keep=1 if `"`binormal'"'~= "" { di in gr "Fitting binormal model for: " /* */ in ye`"`by'"' "==" in ye `by'[1] qui rocfit `D' `C' `wt' local a=_b[intercep] local b=_b[slope] qui replace area = e(area) qui replace se = e(se_area) local alpha=invnorm(.5+`level'/200) qui replace lb = area - `alpha'*se qui replace ub = area + `alpha'*se qui replace N = e(N) local Nobs=_N local nobs=`Nobs'+300 qui set obs `nobs' tempvar k zfpf qui gen int `k'=1 if _n>`Nobs' qui replace bygrp= bygrp[_n-1] if bygrp==. qui replace x=0 if `k'==1 & _n==`Nobs'+1 qui replace x=x[_n-1]+1/300 if x==. & `k'==1 qui gen double `zfpf'= invnorm(x) if `k'==1 qui gen double yhat`i'=`b'*`zfpf' + `a' qui replace yhat`i'=normprob(yhat`i') qui replace yhat`i'=0 if _n==_N qui replace x=0 if _n==_N qui replace sens`i'=0 if _n==_N qui replace yhat`i'=1 if _n==_N-1 qui replace x=1 if _n==_N-1 qui replace x=1 if sens`i'==1 qui replace sens`i'=1 if x==1 local troc="0"+string(round(area,0.0001)) local aroc=`"`group' ROC area: `troc'"' label var sens`i' `"`aroc'"' local sensgr="`sensgr' yhat`i'" /* save matrices for test */ tempname B`i' V`i' qui mat B`i'=e(b) qui mat V`i'=e(V) } sum `wv' if `D'==0, meanonly local nn = r(sum) sum `wv' if `D'==1, meanonly local na = r(sum) qui drop `D' `C' `wv' `k' `zfpf' `by' if `i'~=1 { append using `gphfile' } qui save `gphfile', replace restore local i=`i'+1 } preserve qui use `gphfile', clear if `"`graph'"' == `""' { /* set graph defaults */ qui tab bygrp local max=r(r) if `"`symbol'"' == `""' { local i 1 while `i'<=`max' { local symbol `"`symbol' o"' if `"`binormal'"'~="" { local symbol `"`symbol' i"' } local i=`i'+1 } } if `"`connect'"' == `""' { local i 1 while `i'<=`max' { if `"`binormal'"'~="" { local connect `"`connect'.l"' } else local connect `"`connect'l"' local i=`i'+1 } } if `"`binormal'"'~="" { local i 1 while `i'<=`max' { local j=`i'+2 local pen=`"`pen'`j'`j'"' local i=`i'+1 } local penopt="pen(2`pen')" } if `"`bands'"' == `""' { local bands `"10"' } if `"`xlabel'"' == `""' { local xlabel `"0,.25,.5,.75,1"' } if `"`ylabel'"' == `""' { local ylabel `"0,.25,.5,.75,1"' } if `"`xline'"' == `""' { local xline `".25,.5,.75"' } if `"`yline'"' == `""' { local yline `".25,.5,.75"' } if `"`l2title'"' == `""' { local l2title `"Sensitivity"' } qui gen `w' = cond(x==0, 0, cond(x==1, 1, .)) label var `w' " " format `sensgr' `w' x %4.2f label var x `"1 - Specificity"' sort x `sensgr' if `"`separate'"'~="" { local byopt="by(bygrp)" sort bygrp x `sensgr' } if `"`refline'"'=="" { local conopt="c(l`connect')" } else { local conopt="c(.`connect')" } noi graph `w' `sensgr' x , `conopt' s(i`symbol') /* */ border t2(`"`t2title'"') bands(`bands') `penopt' /* */ xlabel(`xlabel') ylabel(`ylabel') xline(`xline') /* */ yline(`yline') `options' l2title("`l2title'") `byopt' } if `"`binormal'"'~="" { qui keep if keep==1 } sort bygrp qui by bygrp:keep if _n==1 qui gen double p=round(area*N, 1) if `"`binormal'"'~= "" { di in gr _n _col(31) "ROC" } else { di in gr _n _col(31) /* */ "ROC" _col(54) "-Asymptotic Normal--" } di in gr "`Gc'" _col(17) " Obs Area Std. Err." /* */" [`level'% Conf. Interval]" _n _dup(73) "-" local i 1 while `i' <= `bymax' { di in ye bygrp[`i'] _col(15) in yel %8.0f N[`i'] /* */ _col(26) %8.4f area[`i'] _col(39) %8.4f se[`i'] /* */ _col(54) %8.5f lb[`i'] _col(66) %8.5f ub[`i'] local i=`i'+1 } di in gr _dup(73) "-" if "`test'"=="" { di in gr "Ho: " _c tempname test mat `test'=J(comb(`bymax',2), `bymax', 0) local i 1 /* row */ local j 1 /* col */ local k 1 local mymax=`bymax' while `i' <= comb(`bymax',2) { if `j'<`mymax' { mat `test'[`i',`k'] = 1 mat `test'[`i',`j'+1] = -1 if `i'<`mymax' { di in gr /* */ "area(" in ye bygrp[`i'] in gr ") = " _c } local i=`i'+1 local j=`j'+1 } else { local j=`k'+1 local k=`k'+1 } } di in gr "area(" in ye bygrp[`bymax'] in gr ") } else { di in gr /* */ "Ho: Comparison as defined by contrast matrix: " /* */ in ye `"`test'"' } /* if `"`binormal'"'~="" { BITest `bymax' `D' `nn' `na' `"`test'"' } else { MYTEs1 `bymax' `D' `nn' `na' `"`test'"' } */ MYTEs1 `bymax' `D' `nn' `na' `"`test'"' return local p = `r(p)' return local df = `r(df)' return local chi2= `r(chi2)' return local groups = `bymax' tempname V matrix `V' = r(V) return matrix V `V' end prog def MYTEs1, rclass gettoken bymax 0:0 gettoken D 0:0 gettoken nn 0:0 gettoken na 0:0 gettoken test 0:0 tempname T mat `T'=J(1, `bymax',1) local i 1 while `i'<=`bymax' { mat `T'[1,`i']=area[`i'] local i=`i'+ 1 } tempname S10 S01 S mat `S10'=J(`bymax',`bymax',0) mat `S01'=J(`bymax',`bymax',0) mat `S'=J(`bymax',`bymax',0) local r 1 while `r'<=`bymax' { mat `S'[`r',`r'] = (se[`r'])^2 local r=`r'+1 } tempname Cont L V R x2 iV mat `L'=`test' mat `Cont'=`T'*`L'' mat `V'=`L'*`S'*`L'' mat `iV'=syminv(`V') local df=colsof(`V')-diag0cnt(`iV') mat `R'=`Cont'*`iV'*`Cont'' scalar `x2'=`R'[1,1] di in gr "chi2(" in ye `df' in gr ") = " in ye %8.2f `x2' /* */ in gr " Pr>chi2 = " in ye %8.4f chiprob(`df',`x2') return local chi2=`x2' return local df=`df' return local p = chiprob(`df',`x2') return matrix V `S' end prog define BITest, sclass gettoken bymax 0:0 gettoken D 0:0 gettoken nn 0:0 gettoken na 0:0 gettoken test 0:0 tempname sS B mat `sS' = J(`bymax',`bymax',0) mat `B' = J(1,`bymax',0) local i 1 while `i'<=`bymax' { tempname B`i' S`i' sS`i' mat `B`i''= B`i'[1, 1..`bymax'] mat `S`i''= V`i'[1..`bymax', 1..`bymax'] mat `sS'= `sS' + syminv(`S`i'') mat `B' = `B' + `B`i''*syminv(`S`i'') local i=`i'+1 } tempname AoBo mat `AoBo' = `B'* syminv(`sS') tempname X2 mat `X2' = J(1,1,0) local i 1 while `i'<=`bymax' { tempname X2`i' mat `X2`i''= (`B`i''-`AoBo')*syminv(`S`i'')*(`B`i'''-`AoBo'') mat `X2'= `X2' + `X2`i'' local i=`i'+1 } tempname x2 scalar `x2'=`X2'[1,1] local df=2*(`bymax'-1) di in gr "chi2(" in ye `df' in gr ") = " in ye %8.2f `x2' /* */ in gr " Pr>chi2 = " in ye %8.4f chiprob(`df',`x2') sreturn local chi2=`x2' sreturn local df=`df' sreturn local p = chiprob(`df',`x2') end