*! version 6.0.0  30nov1999   (STB-52 sg120)
prog def roctab, rclass
version 6
	syntax varlist(numeric min=2 max=2) [if] [in] [ fweight] [, BAMber /*
	*/ noBIASadj Detail Level(integer $S_level) LORenz TABle noGraph /*
	*/ HANley noSUMAREA BINOmial * ]
	marksample touse
	tokenize `varlist'
	local D = `"`1'"'
	local C = `"`2'"'
	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 "`bamber'"~="" & "`hanley'"~="" {
		di in red "bamber and hanley not allowed together"
                exit 198
	}
	if `"`lorenz'"'~="" {
	        local graph="nograph"
		if "`bamber'"~="" | "`hanley'"~="" {
			di in red "lorenz not allowed with bamber or hanley"
                	exit 198
		}
	}
	qui summ `D' if `touse', meanonly
	if r(min) == r(max) {
		di in red "Outcome does not vary"
		exit 198
	}
	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' `D' `C'
	qui by `touse' `D' `C': gen `newwt'=sum(`wv') if `touse'
	qui by `touse' `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' `D' `C'
	qui by `touse' `D' : gen long `MN' = sum(`wv')
	qui by `touse' `D' : replace `MN' = `MN'[_N]
	qui replace `MN'=. if `touse'==0
	if "`table'"~="" {
		noi cap tabulate `D' `C' `wt' if `touse'
		if _rc~=0 {
			tabulate `C' `D' `wt' if `touse'
		}
		else {
			tabulate `D' `C' `wt' if `touse'
		}
		noi di _n
	}
	tempvar p
	qui logistic `D' `C' `wt' if `touse', asis
	tempname b
	mat `b'=e(b)
	local bc= colsof(`b')
	qui predict double `p' if e(sample), p
	if `bc'>1 {
		if _b[`C']<0 {
			qui MYLRoc, `options' `graph' class
		}
		else {
        		qui MYLRoc , `options' `graph'
		}
	}
	else {
       		qui MYLRoc , `options' `graph'
	}
	tempname area
	scalar `area'= r(area)
	local N=r(N)
	qui sum `D' `wt' if `touse', meanonly
	local na=r(sum)
	local nn=`N'-`na'
	if `"`detail'"'~="" {
	        tempvar prob sens spec
	        qui sum `p', meanonly
	        cap assert reldif(`p', r(min))<1e-12 if `p'~=.
	        if _rc==0 {
	                qui _rocsen if `touse', class(`C') genprob(`prob') /*
			*/ gensens(`sens') genspec(`spec')
		}
		else {
			qui lsens if `touse', nograph genprob(`prob') /*
			*/ 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
		}
		sort `prob'
		MYDETail `prob' `sens' `spec' `D' `C' `touse' `wt'
		qui replace `sens'=. if `prob'==0 | `prob'==1
		qui replace `spec'=. if `prob'==0 | `prob'==1
		qui replace `prob'=. if `sens'==. | `spec'==.
		sort `prob'
		qui replace `prob'=. if `sens'==1 & `spec'==0 & _n==1
	}
	if `"`lorenz'"'~="" {
		tempvar cuma cumn
		qui gen double `cuma'=.
		qui gen double `cumn'=.
		LORenz `cuma' `cumn' `C' `D' `area' `touse' `na' `nn' `wv'
		nobreak {
			local Nmax=_N+2
			qui set obs `Nmax'
			tempvar drp
			qui gen `drp'=1 if _n>`Nmax'-2
			qui replace `cuma'=0 if _n==`Nmax'-1
			qui replace `cumn'=0 if _n==`Nmax'-1
			qui replace `cuma'=1 if _n==`Nmax'
			qui replace `cumn'=1 if _n==`Nmax'
			label var `cuma' "cumulative % of `D'=1"
			label var `cumn' "cumulative % of `D'=0"
			if `"`t1title'"'=="" {
				local t1opt="t1title(Lorenz curve)"
			}
			noi graph `cuma' `cumn' `cumn' , c(ll) s(oi) sort /*
			*/ `t1opt' xlab(0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1) /*
			*/ border ylab(0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1) `options'
			qui drop if `drp'==1
		}
		GIni `cuma' `cumn' `C'
		noi di _n in gr " Lorenz Curve "
		noi di in gr "---------------------------"
		noi di in gr "  Pietra index = " in ye %8.4f `s(pietra)'
		noi di in gr "  Gini index   = " in ye %8.4f `s(gini)'
		return scalar gini=`s(gini)'
		return scalar pietra=`s(pietra)'
	}
	else if "`sumarea'"=="" {
		if `"`bamber'"'~= "" | `"`biasadj'"'~="" {
			BAMberSE `C' `D' `area' `touse' `na' `nn' `wv' `biasadj'
			local SEtype="Bamber"
		}
		else if `"`hanley'"' ~="" {
			HANleySE `C' `D' `area' `touse' `na' `nn' `wv'
			local SEtype="Hanley"
		}
		else {
			tempvar v01 v10
			qui gen double `v01'=.
			qui gen double `v10'=.
			preserve
			qui keep if `touse'
			DeLongSE `D' `C' `wv' `na' `nn' `area' `v01' `v10'
			*rename `v01' v01`i'
			*rename `v10' v10`i'
			local SEtype="      "
			restore

		}
		if `"`binomial'"'~="" {
			local CItype="binom"
		}
		tempname se
		scalar `se'= `s(se)'
		MYDIspl `N' `area' `se' `level' `SEtype' `CItype'
		return scalar ub = `s(ub)'
		return scalar lb = `s(lb)'
		return scalar se = `se'
		return scalar area = `area'
		return scalar N = `N'
	}
end
prog def MYLRoc, rclass
	tempvar touse p w spec sens
	lfit_p `touse' `p' `w' `0'
	local y `"`s(depvar)'"'
	ret scalar N = `s(N)'
	local 0 `", `s(options)'"'
	sret clear
	syntax [, noGraph T2title(string) Symbol(string) class /*
	*/ Bands(string) XLAbel(string) YLAbel(string) XLIne(string) /*
	*/ YLIne(string) noREFline *]
	if `"`graph'"' == `""' {
		if `"`symbol'"' == `""' { local symbol `"o"' }
		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"' }
	}
	local old_N = _N
	capture {
		lsens_x `touse' `p' `w' `y' `sens' `spec' one
		replace `p' = sum((`spec'-`spec'[_n-1])*(`sens'+`sens'[_n-1]))
		if `"`class'"'~="" {
			return scalar area = 1 - `p'[_N]/2
		}
		else {
			return scalar area = `p'[_N]/2
		}
		global S_2 `"`return(area)'"'
		if `"`t2title'"' == `""' {
			local area : di %6.4f return(area)
			local t2title `"Area under ROC curve = `area'"'
		}
		if `"`graph'"' == `""' {
			if `"`refline'"'=="" {
				replace `w' = /*
				*/ cond(`spec'==0, 0, cond(`spec'==1, 1, .))
			}
			else {
				replace `w'=.
			}
			if `"`class'"'~="" {
				tempvar mark
				qui gen int `mark'=1 if `sens'==1 & `spec'==1
				qui replace `mark'=1 if `sens'==0 & `spec'==0
				replace `sens' = 1 -`sens' if `mark'!=1
				replace `spec' = 1 -`spec' if `mark'!=1
			}
			format `sens' `w' `spec' %4.2f
			noi graph `sens' `w' `spec', c(ll) s(`symbol'i) /*
			*/ border t2(`"`t2title'"') bands(`bands') /*
			*/ xlabel(`xlabel') ylabel(`ylabel') xline(`xline') /*
			*/  yline(`yline') sort `options'
		}
	}
	nobreak {
		local rc = _rc
		if _N > `old_N' {
			qui drop if `touse' == .
		}
		if `rc' { error `rc' }
	}
end
prog def LORenz, sclass
	args cuma cumn C D area touse na nn wv
	tempvar lr numb cum lr1 lr2
	quietly {
		sort `touse' `D' `C'
		by `touse' `D' `C': gen double `numb' = sum(`touse'*`wv')
		qui replace `numb' = . if `touse' == 0
		by `touse' `D' `C': replace `numb'= `numb'[_N]
		qui gen double `lr1' = `numb'/`nn' if `D'==0
		qui gen double `lr2' = `numb'/`na' if `D'==1
		sort `touse' `C' `D'
		by `touse' `C' : replace `lr1' = `lr1'[_n-1] if `lr1'==.
		qui by `touse' `C' : replace `lr2' = `lr2'[_n+1] if `lr2'==.
		qui gen double `lr' = `lr2'/`lr1'
		drop `lr1' `lr2'
		replace `lr'=. if `touse'~=1
		sort `touse' `C' `D'
		by `touse' `C' `D': replace `lr'=. if _n~=_N
		sort `touse' `C' `lr'
		by `touse' `C': replace `lr'=`lr'[_n-1] if `lr'==.
		tempvar cum1 cum0
		sort `touse' `lr' `D' `C'
		tempvar order
		qui gen long `order'=_n
		compress `order'
		replace `order'=. if `lr'==.
		cumul `order' [fw=`wv'] if `touse' & `D'==0, gen(`cum0')
		sort `order'
		cumul `order' [fw=`wv'] if `touse' & `D'==1, gen(`cum1')
		qui gen double `cum'=`cum0' if `D'==0
		qui replace `cum'=`cum1' if `D'==1
		drop `cum0' `cum1' `order'
		sort `touse' `C' `D' `cum'
		by `touse' `C' `D': replace `cum'=`cum'[_N]
		replace `cumn'=`cum' if `D'==0
		replace `cuma'=`cum' if `D'==1
		sort `touse' `C' `D'
		by `touse' `C': replace `cumn'=`cumn'[_n-1] if `cumn'==.
		sort `touse' `C' `cumn'
		by `touse' `C': replace `cumn'=. if _n~=_N
		by `touse' `C': replace `cuma'=. if _n~=_N
	}
end
prog def GIni, sclass
	args cuma cumn C
	tempvar diff
	qui gen double `diff'=`cumn'-`cuma'
	qui sum `diff', meanonly
	sreturn local pietra=r(max)
	qui replace `cumn'=. if `cuma'==.
	qui replace `cuma'=. if `cumn'==.
	sort `cuma' `C'
	tempvar g
	qui gen double `g'=(`cumn'*`cuma'[_n+1])-(`cuma'*`cumn'[_n+1])
	qui replace `g'=sum(`g')
	sreturn local gini=`g'[_N]
end
prog def MYLR, sclass
	args C sens spec prob touse i max
	tempvar g
	qui egen `g'=group(`C') if `touse'
	local space =12-length("`C'")
	sort `prob' `sens'
	tempvar lrp lrn lrnp
	qui gen double `lrp'=`sens'/(100-`spec')
	qui gen double `lrn'=(100-`sens')/`spec'
	qui gen double `lrnp'=(`sens'[_n-1]-`sens')/(`spec'-`spec'[_n-1])
	sret local lrn=`lrn'[`i']
	sret local lrp=`lrp'[`i']
	sret local lrnp=`lrnp'[`i']
end
prog def MYDETail
	args prob sens spec D C touse wt
	qui replace `prob'=. in 1
	tempvar g
	qui egen `g'=group(`C') if `touse'
	noi di in gr _n "Detailed report of Sensitivity and Specificity"
	noi di in gr _dup(78) `"-"'
	noi di in gr  _col(43) " Correctly"
	noi di in gr "Cut point     " "Sensitivity   Specificity" /*
	*/ "   Classified          LR+          LR-"
	noi di in gr _dup(78) `"-"'
	qui sum `g', meanonly
	local max=r(max)
	local min=r(min)
	qui replace `sens'=`sens'*100
	qui replace `spec'=`spec'*100
	qui sum `D' `wt' if `D'==1 & `touse'
	local N1=r(N)
	qui sum `D' `wt' if `D'==0 & `touse'
	local N0=r(N)
	local i 1
	while `i'<= `max' + 1 {
		tempvar np A name1 name2
		qui gen `A'=1 if `touse'
		qui replace `A'=2 if `g'>`i'-1 & `touse'
		qui tab `D' `A' if `touse'
		qui gen `name1'= `C' if `g'==`i'-1 & `touse'
		qui gen `name2'= `C' if `g'==`i' & `touse'
		qui sum `A' `wt' if `touse' & `A'==1, meanonly
		local n1=r(N)
		qui sum `A' `wt' if `touse' & `A'==2, meanonly
		local n2=r(N)
		qui replace `name1'=`name1'[_n-1] if `name1'==.
		qui replace `name2'=`name2'[_n-1] if `name2'==.
		qui replace `name1'=`name1'[_N] if `name1'==.
		qui replace `name2'=`name2'[_N] if `name2'==.
		if `i' == `min' {
			local sim1 "  "
			local cut=`name2'[`i']
			local cut =`"( >= `cut' )"'
		}
		else if `i'== `max'+1 {
			local sim2 "  "
			local cut=`name1'[`i']
			local cut =`"( >  `cut' )"'
		}
		else {
			local cut=`name1'[`i']
			local cut2=`name2'[`i']
			local cut ="(<=`cut', >=`cut2')"
			local cut ="( >= `cut2' )"
		}

		sort `prob' `sens'
		local corr (`sens'[`i']*`N1' + `spec'[`i']*`N0') /(`N1'+`N0')
		MYLR `C' `sens' `spec' `prob' `touse' `i' `max'
		local lrn=`s(lrn)'
		local lrp=`s(lrp)'
		local lrnp=`s(lrnp)'
		if `lrp'==. {
			local lrp="         "
		}
		if `lrn'==. {
			local lrn="         "
		}
		di in ye "`cut'" _col(17) /*
		*/ %8.2f `sens'[`i'] `"%"' _col(31) %8.2f `spec'[`i'] `"%"' /*
		*/  _col(44) %8.2f `corr' `"%"' _col(58) %8.4f `lrp' /*
		*/ _col(71) %8.4f `lrn'
		local i= `i'+1
	}
	noi di in gr _dup(78) `"-"'
	qui replace `sens'=`sens'/100
	qui replace `spec'=`spec'/100
end
prog def MYDIspl, sclass
	args N area nse level SEtype CItype
	if `"`CItype'"'=="" & `"`SEtype'"'=="binom"{
		local CItype="binom"
		local SEtype=""
	}
	tempname ub lb
	if `"`CItype'"'== "binom" {
		qui cii `N' `area', level(`level')
		scalar `ub'=r(ub)
		scalar `lb'=r(lb)
		local citype = "-- Binomial Exact --"
	}
	else {
		local alpha=invnorm(.5+`level'/200)
		scalar `ub' = `area' + `alpha'*`nse'
		scalar `lb' = `area' - `alpha'*`nse'
		if `ub'>1 {
			scalar `ub' = 1
		}
		if `lb'<0 {
			scalar `lb' = 0
		}
		local citype = "-Asymptotic Normal--"
	}
	di in gr _n _col(23) "ROC" _col(32) "`SEtype'" _col(46) "`citype'"
	di in gr "           Obs       Area     Std. Err." /*
	*/ "      [`level'% Conf. Interval]" _n "         " _dup(56) "-"
	di in gr _col(7) in yel %8.0f `N' _col(18) %8.4f `area' _col(31) /*
	*/ %8.4f `nse' _col(46) %8.5f `lb' _col(58) %8.5f `ub'
	sreturn local lb=`lb'
	sreturn local ub=`ub'
end
prog def HANleySE, sclass
	args C D W touse na nn wv
	tempvar row1 row2 row3 row4 row5 row6 row7 temp
	tempname Q1 Q2 SE_W
	quietly {
	sort `touse' `C'
	by `touse' `C': gen `row1' = sum(`touse'*(1-`D')*`wv')
	by `touse' `C': replace `row1' = . if _n != _N | `touse' == 0
	by `touse' `C': gen `row3' = sum(`touse'*`D'*`wv')
	by `touse' `C': replace `row3' = . if _n != _N | `touse' == 0
	markout `touse' `row1' `row3'
	sort `touse' `C'
	gen `temp' = sum(`row1') if `touse'
	gen `row4' = `temp'[_n-1] if `touse'
	replace `row4' = 0 if `touse' & `row4' == .
	replace `temp' = sum(`row3') if `touse'
	gen `row2' = `na' - `temp' if `touse'
	gen `row5' = `row1'*(`row2' + 0.5*`row3') if `touse'
	summ `row5' if `touse', meanonly
	gen `row6' = `row3'*(`row4'*(`row4'+`row1')+(1/3)*`row1'^2) if `touse'
	summ `row6' if `touse', meanonly
	scalar `Q2' = r(sum)/(`na'*`nn'^2)
	gen `row7' = `row1'*(`row2'*(`row2'+`row3')+(1/3)*`row3'^2) if `touse'
	summ `row7' if `touse', meanonly
	scalar `Q1' = r(sum)/(`nn'*`na'^2)
	scalar `SE_W' = sqrt(( `W'*(1-`W') + (`na'-1)*(`Q1'-`W'^2) /*
	*/ + (`nn'-1)*(`Q2'-`W'^2))/(`na'*`nn'))
	}
	sret local se=`SE_W'
end

prog def BAMberSE, sclass
	args C D W touse na nn wv biasadj
	tempvar x y ux uy vx vy
	preserve
	qui keep if `touse'
	qui gen double `ux'=.
	qui gen double `vx'=.
	qui gen double `uy'=.
	qui gen double `vy'=.
	local i=1
	while `i'<=_N {
		tempvar uxt vxt uyt vyt
		tempname val
		scalar `val'=`C'[`i']
		qui gen double /*
		*/ `uxt'=`wv' if `C'<`val' & `D'[`i']==1 & `D'==0 & `touse'
		qui gen double/*
		*/  `vxt'=`wv' if `C'>`val' & `D'[`i']==1 & `D'==0 & `touse'
		qui gen double/*
		*/  `uyt'=`wv' if `C'<`val' & `D'[`i']==0 & `D'==1 & `touse'
		qui gen double /*
		*/ `vyt'=`wv' if `C'>`val' & `D'[`i']==0 & `D'==1 & `touse'
		qui replace `uxt'=sum(`uxt')
		qui replace `vxt'=sum(`vxt')
		qui replace `uyt'=sum(`uyt')
		qui replace `vyt'=sum(`vyt')
		qui replace `ux'=`uxt'[_N] if _n==`i'
		qui replace `vx'=`vxt'[_N] if _n==`i'
		qui replace `uy'=`uyt'[_N] if _n==`i'
		qui replace `vy'=`vyt'[_N] if _n==`i'
		local i=`i'+1
	}
	sort `D'
	tempvar sumwt bxny byyx1 bxxy1
	tempname pxny byyx bxxy var bse
	qui gen double `bxny'=`ux'+`vx'
	qui replace `bxny'=sum(`bxny'*`wv')
	scalar `pxny'=(`bxny'[_N])/(`na'*`nn')
	drop `bxny'
	qui gen double `bxxy1' /*
	*/  = (`uy'*(`uy'-1)+`vy'*(`vy'-1)-2*`uy'*`vy') if `uy'~=.
	qui replace `bxxy1'=sum(`bxxy1'*`wv')
	scalar `bxxy'=(`bxxy1'[_N])/(`na'*(`na'-1)*`nn')
	drop `bxxy1'
	qui gen double `byyx1'/*
	*/ = `ux'*(`ux'-1)+`vx'*(`vx'-1)-2*`ux'*`vx' if `ux'~=.
	qui replace `byyx1'=sum(`byyx1'*`wv')
	scalar `byyx'=(`byyx1'[_N])/(`nn'*(`nn'-1)*`na')
	drop `byyx1'
	if "`biasadj'"~="" {     /* bias not adjusted */
		scalar `var'=1/(4*`na'*`nn')*(`pxny'+(`na'-1)* `bxxy' /*
		*/ +(`nn'-1) * `byyx' -4*(`na'+`nn'-1)*((`W'-.5)^2))
	}
	else {  /* bias adjusted - default */
		scalar `var'=(1/(4*(`na'-1)*(`nn'-1)))*(`pxny'+(`na'-1)* /*
		*/ `bxxy' +(`nn'-1) * `byyx' -4*(`na'+`nn'-1)*((`W'-.5)^2))
	}
	sret local se = sqrt(`var')
end
prog def DeLongSE, 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')
	tempname S10 S01 S
	tempvar pd01 pd10 sd01 sd10
	qui gen double `pd01'=`v01'*`v01'
	qui gen double `pd10'=`v10'*`v10'
	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 S10=`sd10'
	local S01=`sd01'
	scalar `S'=(1/`na')*`S10' + (1/`nn')*`S01'
	sret local se = sqrt(`S')
end