*! 1.1.2 NJC 31 October 2024
* 1.1.1 NJC 26 October 2024
* 1.1.0 NJC 25 October 2024 
* 1.0.0 NJC 21 October 2024 
program cisets
	version 14.1 
	
	gettoken subcmd 0 : 0 
	
	if substr("`subcmd'", 1, 4) == "mean" { 
		_mean `0'
	}
	else if substr("`subcmd'", 1, 4) == "prop" {
		_prop `0'
	}
	else if substr("`subcmd'", 1, 3) == "var" {
		_var `0'
	}
	else if "`subcmd'" == "gmean" { 
		_gmean `0'
	}
	else if "`subcmd'" == "hmean" { 
		_hmean `0'
	}
	else if "`subcmd'" == "centile" {
		_centile `0'
	}
	else { 
		display as err "did not understand subcommand `subcmd'"
		exit 198 
	}

end 

* I guess shorter code would be entirely possible with more programs, 
* but it might be harder to follow the flow. 
* In essence, once each statistic -whatever- is chosen the 
* default program _whatever loops over or more variables using 
* -postfile- to assemble a confidence interval set.
* But if -over()- is specified, we branch off to program _whatever_g 
* which handles groups of observations using -statsby-. 

* Here we keep a record of which weights are allowed. 
* mean            aweight (if normal), fweight 
* proportion      fweight 
* variance / SD   fweight
* geometric mean  aweight, fweight 
* harmonic mean   aweight, fweight 
* centile         none 

program _mean 
	capture syntax varname(numeric) [if] [in] [aweight fweight]      ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total ///
	POISson EXPosure(passthru) * ]   
			
	if _rc == 0  {
 		if "`weight'" == "aweight" & "`poisson'`exposure'" != "" {
			display as err "aweights not allowed for Poisson means"
			exit 101 
		}

		_mean_g `0'
		exit 0  
	}
	
	syntax varlist(numeric) [if] [in] [aweight fweight] ///
	[, SAVING(str asis) Level(integer $S_level)        ///
	POISson EXPosure(passthru) ALLobs inclusive cw * ]   
	
	if "`weight'" == "aweight" & "`poisson'`exposure'" != "" {
		display as err "aweights not allowed for Poisson means"
		exit 101 
	}

	if "`allobs'`inclusive'`cw'" != "" marksample touse, novarlist 
	else marksample touse 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse'

	if `"`saving'"' == "" {
		tempfile saving 
		local wantsave 0  
	}
	else local wantsave 1 
	
	tempname handle 
	postfile `handle' str32 varname str80 varlabel n point se lb ub using `saving'
	
	quietly foreach v of local varlist {
	    local varlabel : var label `v'
		if `"`varlabel'"' == "" local varlabel "`v'"
		ci means `v', `poisson' `exposure'
		post `handle' ("`v'") ("`varlabel'") (r(N)) (r(mean)) (r(se)) (r(lb)) (r(ub)) 
	}
	
	postclose `handle'
	
	gettoken filename rest : saving, parse(,) 
	use "`filename'", clear 
	gen level = `level'
	gen statname = "mean"

	if "`poisson'`exposure'" != "" {
		gen options = trim("`poisson' `exposure'")
	}
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	order varname varlabel n statname point se lb ub level 
	list, noobs `options'
	
	if `wantsave' {
		display  
		quietly compress
		save "`filename'", replace
	} 
end 

program _mean_g 
	syntax varname(numeric) [if] [in] [aweight fweight]              ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total ///
	POISson EXPosure(passthru) * ]   

	marksample touse  
	markout `touse' `over', strok 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 
		
	local varlabel : variable label `varlist'
	local gvarlabel : variable label `over' 
	
	quietly statsby , by(`over') clear `total' : ///
	ci means `varlist' [`weight' `exp'], `poisson' `exposure' level(`level')
	
	quietly egen group = group(`over'), label 
	_crcslbl group `over'

	quietly if "`total'" != "" { 
		su group, meanonly 
		local gmax = r(max) + 1 
		replace group = `gmax' if group == . 
		label def group `gmax' "Total", modify 
	}
	
	rename (`over' N mean) (origgvar n point) 
	
	gen varname = "`varlist'"
	gen varlabel = cond(missing("`varlabel'"), varname, "`varlabel'")
	gen groupvar = "`over'"
	gen gvarlabel = cond(missing("`gvarlabel'"), groupvar, "`gvarlabel'")
	gen statname = "mean"
	
	if "`poisson'`exposure'" != "" {
		gen options = trim("`poisson' `exposure'")
	}
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	foreach v in n point se ub lb level {
		label var `v' 
	}

	order varname varlabel origgvar groupvar gvarlabel group n statname point se lb ub level 
	list, noobs `options'

	if `"`saving'"' != "" { 
		label data 
		display 
		quietly compress 
		save `saving'
	}
end 

program _prop 
    capture syntax varname(numeric) [if] [in] [fweight]              ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total ///
	exact wald wilson AGRESti JEFFreys * ]   
	
	if _rc == 0 { 
		_prop_g `0'
		exit 0
	}
	
	syntax varlist(numeric) [if] [in] [fweight]  ///
	[, SAVING(str asis) Level(integer $S_level) ///
	exact wald wilson AGRESti JEFFreys ALLobs inclusive cw * ]  
	
	if "`allobs'`inclusive'`cw'" != "" marksample touse, novarlist 
	else marksample touse 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 

	if `"`saving'"' == "" {
		tempfile saving 
		local wantsave 0  
	}
	else local wantsave 1 

	tempname handle 
	postfile `handle' str32 varname str80 varlabel n point se lb ub using `saving'
	
	local bad = 0 
	local nv : word count `varlist'
	
	quietly foreach v of local varlist {
		count if !(inlist(`v', 0, 1) | missing(`v'))
		if r(N) { 
			local flag `flag' `v'
			local ++bad 
			continue 
		}
		local varlabel : var label `v'
		if `"`varlabel'"' == "" local varlabel "`v'"
		ci prop `v', `exact' `wald' `wilson' `agresti' `jeffreys'
		post `handle' ("`v'") ("`varlabel'") (r(N)) (r(mean)) (r(se)) (r(lb)) (r(ub)) 
	}
		
	postclose `handle'
	
	noisily if "`flag'" != "" {
		display _n "{p}" plural(`bad', "variable") " ignored: `flag'{p_end}"
		display "{p}(0, 1) binary variables are needed for confidence intervals for proportions{p_end}"
		if `bad' == `nv' exit 450
	}
	
	gettoken filename rest : saving, parse(,) 
	use "`filename'", clear 
	gen level = `level'
	gen statname = "proportion"
	
	if "`exact'`wald'`wilson'`agresti'`jeffreys'" != "" {
		gen options = trim("`exact' `wald' `wilson' `agresti' `jeffreys'") 
	}
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	order varname varlabel n statname point se lb ub level 
	list, noobs `options'

	if `wantsave' {
		display
		quietly compress 
		save "`filename'", replace
	}
end 

program _prop_g 
    syntax varname(numeric) [if] [in] [fweight]                       ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total  ///
	exact wald wilson AGRESti JEFFreys * ]   
	
	marksample touse  
	markout `touse' `over', strok 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 
	
	quietly count if !inlist(`varlist', 0, 1) 
	
	if r(N) { 
		noisily display _n "{p}(0, 1) binary variables are needed for confidence intervals for proportions{p_end}"
		exit 450
	}
	
	local varlabel : variable label `varlist'
	local gvarlabel : variable label `over' 
	
	quietly statsby , by(`over') clear `total' : ///
	ci prop `varlist' [`weight' `exp'],  level(`level') `exact' `wald' `wilson' `agresti' `jeffreys'
	
	quietly egen group = group(`over'), label 
	_crcslbl group `over'
	
	quietly if "`total'" != "" { 
		su group, meanonly 
		local gmax = r(max) + 1 
		replace group = `gmax' if group == . 
		label def group `gmax' "Total", modify 
	}

	rename (`over' N mean) (origgvar n point)
	drop proportion 
	
	gen varname = "`varlist'"
	gen varlabel = cond(missing("`varlabel'"), varname, "`varlabel'")
	gen groupvar = "`over'"
	gen gvarlabel = cond(missing("`gvarlabel'"), groupvar, "`gvarlabel'")
	gen statname = "proportion"
	
	if "`exact'`wald'`wilson'`agresti'`jeffreys'" != "" {
		gen options = trim("`exact' `wald' `wilson' `agresti' `jeffreys'") 
	}
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	foreach v in n point se ub lb level {
		label var `v' 
	}

	order varname varlabel origgvar groupvar gvarlabel group n statname point se lb ub level 
	list, noobs `options'
	
	if `"`saving'"' != "" { 
		label data 
		display 
		quietly compress
		save `saving'
	} 
end 

program _var
    capture syntax varname(numeric) [if] [in] [fweight]    ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total SD BONett * ]   
	
	if _rc == 0 {
		_var_g `0'
		exit 0
	}
	
	syntax varlist(numeric) [if] [in] [fweight]    ///
	[, SAVING(str asis) Level(integer $S_level) SD BONett ALLobs inclusive cw * ]  
	
	if "`allobs'`inclusive'`cw'" != "" marksample touse, novarlist 
	else marksample touse 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 

	if `"`saving'"' == "" {
		tempfile saving 
		local wantsave 0  
	}
	else local wantsave 1 
	
	tempname handle 
	postfile `handle' str32 varname str80 varlabel n point lb ub using `saving'
	
	local which = cond("`sd'" != "", "sd", "Var")
	
	quietly foreach v of local varlist {
		local varlabel : var label `v'
		if `"`varlabel'"' == "" local varlabel "`v'"
		ci var `v' [`weight' `exp'],  level(`level') `sd'`bonett'
		post `handle' ("`v'") ("`varlabel'") (r(N)) (r(`which')) (r(lb)) (r(ub)) 
	}
	
	postclose `handle'
	
	gettoken filename rest : saving, parse(,) 
	use "`filename'", clear 
	gen level = `level'
	gen statname = cond("`sd'" != "", "SD", "variance")
		
	if "`sd'`bonett'" != "" {
		gen options = trim("`sd' `bonett'") 
	}
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	order varname varlabel n statname point lb ub level 
	list, noobs `options'
	
	if `wantsave' {
		display 
		quietly compress 
		save "`filename'", replace
	}
end 

program _var_g 
    syntax varname(numeric) [if] [in] [fweight]                       ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total  ///
	SD BONett * ]   
	
	marksample touse  
	markout `touse' `over', strok 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 
	
	local varlabel : variable label `varlist'
	local gvarlabel : variable label `over' 
	
	quietly statsby , by(`over') clear `total' : ///
	ci var `varlist' [`weight' `exp'],  level(`level') `sd' `bonett'

	quietly egen group = group(`over'), label 
	_crcslbl group `over'

	quietly if "`total'" != "" { 
		su group, meanonly 
		local gmax = r(max) + 1 
		replace group = `gmax' if group == . 
		label def group `gmax' "Total", modify 
	}
		
	local which = cond("`sd'" != "", "sd", "Var")
	if "`sd'" != "" drop Var
	drop Var_se 
	rename (`over' N `which') (origgvar n point)
	
	gen varname = "`varlist'"
	gen varlabel = cond(missing("`varlabel'"), varname, "`varlabel'")
	gen groupvar = "`over'"
	gen gvarlabel = cond(missing("`gvarlabel'"), groupvar, "`gvarlabel'")
	gen statname =  cond("`sd'" == "sd", "SD", "variance")
	
	if "`sd'`bonett'" != "" {
		gen options = trim("`sd' `bonett'") 
	}
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	foreach v in n point ub lb level {
		label var `v' 
	}

	order varname varlabel origgvar groupvar gvarlabel group n statname point lb ub level
	list, noobs `options'

	if `"`saving'"' != "" { 
		label data
		display 
		quietly compress 
		save `saving'
	}
end 
	
program _gmean 
	capture syntax varname(numeric) [if] [in] [aweight fweight]      ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total ///
	overasis * ]   
	
	if _rc == 0 { 
		_gmean_g `0'
		exit 0 
	} 
	
	syntax varlist(numeric) [if] [in] [aweight fweight]    ///
	[, SAVING(str asis) Level(integer $S_level) ALLobs inclusive cw * ]   
	
  	if "`allobs'`inclusive'`cw'" != "" marksample touse, novarlist 
	else marksample touse 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse'
 
	if `"`saving'"' == "" {
		tempfile saving 
		local wantsave 0  
	}
	else local wantsave 1 

	tempname handle 
	postfile `handle' str32 varname str80 varlabel n point lb ub using `saving'
	
	quietly foreach v of local varlist {
		local varlabel : var label `v'
		if `"`varlabel'"' == "" local varlabel "`v'"
		ameans `v' [`weight' `exp'],  level(`level') 
		post `handle' ("`v'") ("`varlabel'") (r(N_pos)) (r(mean_g)) (r(lb_g)) (r(ub_g)) 
		if r(N) > r(N_pos) local flag `flag' `v'
	}
	
	postclose `handle'
	
	if "`flag'" != "" { 
		noisily display _n "{p}note: zero or negative values on `flag' ignored{p_end}"
	}
	
	gettoken filename rest : saving, parse(,) 
	use "`filename'", clear 
	gen level = `level'
	gen statname = "geometric mean"
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
		
	order varname varlabel n statname point lb ub level 
	list, noobs `options'
	
	if `wantsave' {
		display 
		quietly compress 
		save "`filename'", replace
	}
end 

program _gmean_g 
	syntax varname(numeric) [if] [in] [aweight fweight]              ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total * ]   

	marksample touse  
	markout `touse' `over', strok 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 
	
	qui count if `varlist' <= 0 
	if r(N) {
		noisily display "`r(N)' values of `varlist' zero or negative; will be ignored"
	}
	
	local varlabel : variable label `varlist'
	local gvarlabel : variable label `over' 
	
	quietly statsby , by(`over') clear `total' : ///
	ameans `varlist' [`weight' `exp'], level(`level')
	
	drop N mean lb ub *_h Var* 

	quietly egen group = group(`over'), label 
	_crcslbl group `over'
	
	quietly if "`total'" != "" { 
		su group, meanonly 
		local gmax = r(max) + 1 
		replace group = `gmax' if group == . 
		label def group `gmax' "Total", modify 
	}
	
	rename (`over' N_pos mean_g lb_g ub_g) (origgvar n point lb ub)
	
	gen varname = "`varlist'"
	gen varlabel = cond(missing("`varlabel'"), varname, "`varlabel'")
	gen groupvar = "`over'"
	gen gvarlabel = cond(missing("`gvarlabel'"), groupvar, "`gvarlabel'")
	gen statname = "geometric mean"
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	foreach v in n point ub lb level {
		label var `v' 
	}
	
	order varname varlabel origgvar groupvar gvarlabel group n statname point lb ub level 
	list, noobs `options'
	
	if `"`saving'"' != "" { 
		label data 
		display 
		quietly compress 
		save `saving'
	}
end 

program _hmean 
	capture syntax varname(numeric) [if] [in] [aweight fweight]      ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total * ]   
	
	if _rc == 0 { 
		_hmean_g `0'
		exit 0 
	}
	
	syntax varlist(numeric) [if] [in] [aweight fweight] ///
	[, SAVING(str asis) Level(integer $S_level) ALLobs inclusive cw * ]   
	
	if "`allobs'`inclusive'`cw'" != "" marksample touse, novarlist 
	else marksample touse 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 

	if `"`saving'"' == "" {
		tempfile saving 
		local wantsave 0  
	}
	else local wantsave 1 

	tempname handle 
	postfile `handle' str32 varname str80 varlabel n point lb ub using `saving'
	
	quietly foreach v of local varlist {
		local varlabel : var label `v'
		if `"`varlabel'"' == "" local varlabel "`v'"
		ameans `v' [`weight' `exp'],  level(`level') 
		post `handle' ("`v'") ("`varlabel'") (r(N_pos)) (r(mean_h)) (r(lb_h)) (r(ub_h)) 
		if r(N) > r(N_pos) local flag `flag' `v'
	}
	
	postclose `handle'
	
	if "`flag'" != "" { 
		noisily display _n "{p}note: zero or negative values on `flag' ignored{p_end}"
	}
	
	gettoken filename rest : saving, parse(,) 
	use "`filename'", clear 
	gen level = `level'
	gen statname = "harmonic mean"
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
		
	order varname varlabel n statname point lb ub level 
	list, noobs `options'
	
	if `wantsave' {
		display  
		quietly compress 
		save "`filename'", replace
	}
end 

program _hmean_g 
	syntax varname(numeric) [if] [in] [aweight fweight]                  ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total * ]   

	marksample touse  
	markout `touse' `over', strok 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 
	
	qui count if `varlist' <= 0 
	if r(N) {
		noisily display "`r(N)' values of `varlist' zero or negative; will be ignored"
	}
	
	local varlabel : variable label `varlist'
	local gvarlabel : variable label `over' 
	
	quietly statsby , by(`over') clear `total' : ///
	ameans `varlist' [`weight' `exp'], level(`level')
	
	drop N mean lb ub *_g Var* 

	quietly egen group = group(`over'), label 
	_crcslbl group `over'

	quietly if "`total'" != "" { 
		su group, meanonly 
		local gmax = r(max) + 1 
		replace group = `gmax' if group == . 
		label def group' `gmax' "Total", modify 
	}
	
	rename (`over' N_pos mean_h lb_h ub_h) (origgvar n point lb ub)
	
	gen varname = "`varlist'"
	gen varlabel = cond(missing("`varlabel'"), varname, "`varlabel'")
	gen groupvar = "`over'"
	gen gvarlabel = cond(missing("`gvarlabel'"), groupvar, "`gvarlabel'")
	gen statname = "harmonic mean"
	
	if "`weight'" != "" gen weight = "`weight' `exp'"
	
	foreach v in n point ub lb level {
		label var `v' 
	}
	
	order varname varlabel origgvar groupvar gvarlabel group n statname point lb ub level 
	list, noobs `options'

	if `"`saving'"' != "" { 
		label data 
		display 
		quietly compress 
		save `saving'
	}
end 

program _centile
	capture syntax varname(numeric) [if] [in]                        ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total ///
	Centile(numlist max=1 >0 <100)  CCi Normal Meansd * ]   
	
	if _rc == 0 { 
		_centile_g `0'
		exit 0
	} 
	
	syntax varlist(numeric) [if] [in]            ///
	[ , SAVING(str asis) Level(integer $S_level) ///   
	Centile(numlist max=1 >0 <100)  CCi Normal Meansd ALLobs inclusive cw * ]   
	
	if "`allobs'`inclusive'`cw'" != "" marksample touse, novarlist 
	else marksample touse 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 

	if `"`saving'"' == "" {
		tempfile saving 
		local wantsave 0  
	}
	else local wantsave 1 

	tempname handle 
	postfile `handle' str32 varname str80 varlabel n point lb ub using `saving'
	
	if "`centile'" == "" local centile 50 
	
	quietly foreach v of local varlist {
		local varlabel : var label `v'
		if `"`varlabel'"' == "" local varlabel "`v'"
		centile `v', centile(`centile') level(`level') `cci' `normal' `meansd'
		post `handle' ("`v'") ("`varlabel'") (r(N)) (r(c_1)) (r(lb_1)) (r(ub_1))
	}
	
	postclose `handle'
	
	gettoken filename rest : saving, parse(,) 
	use "`filename'", clear 
	gen level = `level'
	gen statname = "`centile' pctile"
	
	if "`cci'`normal'`meansd'" != "" { 
		gen options = trim("`cci' `normal' `meansd'")
	}
		
	order varname varlabel n statname point lb ub level 
	list, noobs `options'
	
	if `wantsave' {
		display 
		quietly compress 
		save "`filename'", replace
	}
end 

program _centile_g 
	syntax varname(numeric) [if] [in]                                ///
	, OVER(varname) [ SAVING(str asis) Level(integer $S_level) Total ///
	Centile(numlist max=1 >0 <100)  CCi Normal Meansd * ]   

	marksample touse  
	markout `touse' `over', strok 
	
	quietly count if `touse'
	if r(N) == 0 error 2000
	if r(N) == 1 error 2001 
	
	preserve 
	quietly keep if `touse' 
		
	local varlabel : variable label `varlist'
	local gvarlabel : variable label `over' 
	
	if "`centile'" == "" local centile 50 
	
	quietly statsby , by(`over') clear `total' :       ///
	centile `varlist', centile(`centile') level(`level') ///
	`cci' `normal' `meansd'
		
	quietly egen group = group(`over'), label 
	_crcslbl group `over'

	quietly if "`total'" != "" { 
		su group, meanonly 
		local gmax = r(max) + 1 
		replace group = `gmax' if group == . 
		label def group `gmax' "Total", modify 
	}
	
	drop n_cent 
	rename (`over' N c_1 lb_1 ub_1) (origgvar n point lb ub)
	
	gen varname = "`varlist'"
	gen varlabel = cond(missing("`varlabel'"), varname, "`varlabel'")
	gen groupvar = "`over'"
	gen gvarlabel = cond(missing("`gvarlabel'"), groupvar, "`gvarlabel'")
	gen statname = "`centile' pctile"
	gen level = `level'
	
	if "`cci'`normal'`meansd'" != "" { 
		gen options = trim("`cci' `normal' `meansd'")
	}
	
	foreach v in n point ub lb level {
		label var `v' 
	}
	
	order varname varlabel origgvar groupvar gvarlabel group n statname point lb ub level 
	list, noobs `options'
	
	if `"`saving'"' != "" { 
		label data 
		display  
		quietly compress 
		save `saving'
	} 
end