*! version 6.0.0 17feb2000 (STB-52 sg120) program define roccomp, rclass version 6 syntax varlist(numeric min=2) [if] [in] [fweight] [, * ] local vars: word count `varlist' if `vars'==2 { _roccom1 `0' /* independent samples */ } else { ROCcomp `0' /* correlated samples */ } return scalar p = `r(p)' return scalar df = `r(df)' return scalar chi2 = `r(chi2)' return scalar N_g = `r(groups)' tempname V mat `V'=r(V) return matrix V `V' end program define ROCcomp, sclass /* Dependent (correlated) ROC curves */ syntax varlist(numeric min=3) [if] [in] [fweight] /* */ [, BINormal Connect(string) Level(integer $S_level) /* */ Symbol(string) Bands(string) XLAbel(string) YLAbel(string) /* */ XLIne(string) YLIne(string) noGraph SEParate TEST(string) /* */ noREFline * ] marksample touse tempvar w spec sens local bymax: word count `varlist' local bymax= `bymax' - 1 gettoken D 0:0 unab D : `D' tokenize `varlist' local i 1 local j 2 while `j'<=`bymax'+1 { local C`i'="``j''" local i=`i'+1 local j=`j'+1 } local grplist="`varlist'" 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 } 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 } } qui summ `D' if `touse', meanonly if r(min) == r(max) { di in red "Outcome does not vary" exit 198 } tempfile gphfile tempfile corfile local sensgr=" " tempvar id order qui gen long `id'=_n qui compress `id' if `"`weight'"' =="" { tempvar wv qui gen int `wv' = 1 if `touse' local weight="fweight" } else { tempvar wv qui gen double `wv' `exp' } local wt=`"[fweight=`wv']"' tempvar bygrp x N area se lb ub qui gen str12 `bygrp'= "" qui gen double `x' = . qui gen long `N'=. qui gen double `area'=. qui gen double `se'=. qui gen double `lb'=. qui gen double `ub'=. local i 1 while `i' <= `bymax' { preserve qui keep if `touse' tempvar C gen double `C'=`C`i'' qui compress `C' tokenize `grplist' qui keep `D' `C' `wv' `bygrp' `C`i'' /* */ `id' `x' `N' `area' `se' `lb' `ub' 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 replace `N'=r(N) qui replace `area'=r(area) qui replace `se'=r(se) qui replace `lb'=r(lb) qui replace `ub'=r(ub) local group="`C`i''" qui replace `bygrp'= `"`group'"' gen `order'=`i' rename `sens' sens`i' local troc="0"+string(round(`area',0.0001)) local aroc=`"`group' ROC area: `troc'"' label var sens`i' `"`aroc'"' qui replace `x' = 1-`spec' local sensgr="`sensgr' sens`i'" qui keep `bygrp' `x' sens`i' `N' `area' `se' /* */ `lb' `ub' `D' `C' `wv' `id' `order' qui gen int keep=1 if `"`binormal'"'~= "" { di in gr "Fitting binormal model for: " in ye "`group'" 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'" } sum `wv' if `D'==0, meanonly local nn = r(sum) sum `wv' if `D'==1, meanonly local na = r(sum) local mgrp= `bygrp' if `i'~=1 { qui append using `"`gphfile'"' } qui save `"`gphfile'"', replace qui keep if `bygrp'==`"`mgrp'"' qui keep `id' `D' `C' `area' `wv' `order' tempvar v01 v10 qui gen double `v01'=. qui gen double `v10'=. COMparea `D' `C' `wv' `na' `nn' `area' `v01' `v10' rename `v01' v01`i' rename `v10' v10`i' rename `wv' wv qui keep `D' `id' v01`i' v10`i' wv `order' sort `id' if `i'~=1 { qui merge `id' using `"`corfile'"' qui drop _merge } sort `id' qui save `"`corfile'"', 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' drop `w' } if `"`binormal'"'~="" { qui keep if keep==1 } qui keep if `bygrp'~="" sort `bygrp' qui by `bygrp':keep if _n==1 qui gen double p=round(`area'*`N', 1) sort `order' 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'"' } MYTEst `bymax' `D' `nn' `na' `area' `"`test'"' `"`corfile'"' end prog def COMparea, sclass args D C wv na nn area v01 v10 tempvar Phi qui gen double `Phi'=. sort `D' `C' local i=1 while `i'<=_N { tempvar phi local x=`C'[`i'] if `D'[`i']==1 { qui gen float `phi'=`wv' if `C'<`x' & `D'==0 qui replace `phi'= 0.5*`wv' if `C'==`x' & `D'==0 qui replace `phi'= 0 if `C'>`x' & `D'==0 qui sum `phi', meanonly qui replace `Phi'=r(sum) if _n==`i' } else { qui gen float `phi'=`wv' if `C'>`x' & `D'==1 qui replace `phi'= 0.5*`wv' if `C'==`x' & `D'==1 qui replace `phi'= 0 if `C'<`x' & `D'==1 qui sum `phi', meanonly qui replace `Phi'=r(sum) if _n==`i' } qui drop `phi' local i=`i'+1 } qui replace `v10'=`Phi'/(`nn') if `D'==1 qui replace `v01'=`Phi'/(`na') if `D'==0 qui drop `Phi' qui replace `v01'=(`v01'-`area') qui replace `v10'=(`v10'-`area') end prog def MYTEst, rclass gettoken bymax 0:0 gettoken D 0:0 gettoken nn 0:0 gettoken na 0:0 gettoken area 0:0 gettoken test 0:0 local corfile `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 } qui use `"`corfile'"', clear tempname S10 S01 S mat `S10'=J(`bymax',`bymax',1) mat `S01'=J(`bymax',`bymax',1) local r 1 while `r'<=`bymax' { local c 1 while `c'<=`bymax' { tempvar pd01 pd10 sd01 sd10 qui gen double `pd01'=v01`r'*v01`c' qui gen double `pd10'=v10`r'*v10`c' qui egen double `sd01'=sum(`pd01'*wv) qui egen double `sd10'=sum(`pd10'*wv) qui replace `sd10'=`sd10'/(`na'-1) qui replace `sd01'=`sd01'/(`nn'-1) local d10=`sd10' local d01=`sd01' mat `S10'[`r',`c'] = `d10' mat `S01'[`r',`c'] = `d01' local c=`c'+1 } local r=`r'+1 } mat `S'=(1/`na')*`S10' + (1/`nn')*`S01' tempname Cont L V R x2 iV mat `L'=`test' mat `Cont'=`L'*`T'' 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 groups=`bymax' return local chi2=`x2' return local df=`df' return local p=chiprob(`df',`x2') return matrix V `S' end