*! version 6.0.0 PR 26nov2008 program define xriml, eclass version 8 if "`*'"=="" | substr("`1'",1,1)=="," { ml display exit } local hidopts "EXpx(str) ORIgin(str) Zero noTIdy TRace ZCI PARam(str)" syntax varlist(min=1 max=2) [if] [in] [aweight fweight], DIst(str) [FP(str) /* */ CEns(varname numeric) COVArs(str) CV noGRaph noLEAve noOUTofsample /* */ CEntile(numlist >0 <100) restrict(string) SE noSCALing LTolerance(real .001) INit(str) /* */ SCATter(str asis) plot(str asis) OFFset(varname) `hidopts' *] local small 1e-6 if "`cens'"=="" global S_cens else global S_cens `cens' if "`scaling'"!="noscaling" local showtsf "noi" else local showtsf "qui" if "`centile'"=="" local centile "3 97" tokenize `centile' local i 0 while "`1'"!="" { if "`1'"!="," { local ++i local c`i' `1' } mac shift } local nc `i' local dist = lower(substr("`dist'",1,2)) if "`dist'"=="n"|"`dist'"=="no" { local dnum 0 local dist n } else { local d= 1*("`dist'"=="sl")+2*("`dist'"=="pn")+3*("`dist'"=="en") /* */ +4*("`dist'"=="eg")+7*("`dist'"=="mp")+8*("`dist'"=="me") if `d'==0 { di as err "invalid distribution `dist'" exit 198 } local dnum `d' } if "`weight'"!="" & `dnum'!=0 &`dnum'!=1 & `dnum'!=2 & `dnum'!=3 & `dnum'!=4 & `dnum'!=7 & `dnum'!=8 { di as err "weights not yet implemented for dist(`dist')" exit 198 } local pars3=(`dnum'>=3) local pars4=(`dnum'>=5) if `dnum'>0 { local gamma "g" } if `pars4' { local delta "d" } local dupper=upper("`dist'") local dt0 "Normal" local dt1 "Shifted Log-Normal" local dt2 "Power-Normal" local dt3 "Exponential-Normal" local dt4 "Exponential-Gamma" local dt7 "Modulus power-Normal" local dt8 "Modulus exp-Normal" if "`expx'"!="" local expx "expx(`expx')" if "`origin'"!="" local origin "origin(`origin')" if "`detail'"!="" local detail "noisily" if "`cv'"!="" local cv "cv" if "`param'"!="" { tokenize `param' while "`1'"!="" { local fl=lower(substr("`1'",1,2)) if "`fl'"=="cv" local cv "cv" else if "`fl'"=="ln" local lns "lns" else if "`fl'"=="ta" local tau "tau" else if "`fl'"=="tr" local trunc "trunc" else { di as err "invalid param() option `1'" exit 198 } mac shift } } /* Extract base variables for each parameter */ _jprxrpa "`covars'" ms`gamma'`delta' "covariates" local ncl $S_1 forvalues i=1/`ncl' { local curve ${S_p`i'} local `curve'base "${S_c`i'}" /* basevars */ } /* Parameter initialisation: gamma (& delta) only at present */ _jprxrpa "`init'" `gamma'`delta' initializations local ncl $S_1 /* ncl is at most 2, but following code is general */ forvalues i=1/`ncl' { local curve ${S_p`i'} local init "${S_c`i'}" /* !! ? Can be initialised with a var or a num */ cap confirm var `init' if _rc confirm num `init' local `curve'init `init' } /* Default initial shape params depend on distribution */ if "`ginit'"=="" { local ginit 0 if `dnum'==0 { /* normal */ local ginit 1 local gfix "gfix" } else if `dnum'==2 local ginit 0.5 /* PG */ else if `dnum'==3 local ginit 0.01 /* EN */ else if `dnum'==4 local ginit 0.25 /* EG */ else if `dnum'==7 local ginit 1 /* MPN */ else if `dnum'==8 local ginit -0.2 /* MEN */ } if "`dinit'"=="" & `pars4' { if `dnum'==7 | `dnum'==8 { /* MPN, MEN */ local dinit 1 } else local dinit 0 } tokenize `varlist' tempvar y M Z local lhs `1' local rhs `2' marksample touse markout `touse' `lhs' `rhs' `cens' `mbase' `sbase' `gbase' `dbase' /* Out-of-sample prediction is done automatically for all observed values of x and y, unless -nooutofsample- is specified. */ tempvar touse_user if "`outofsample'" == "nooutofsample" { qui gen byte `touse_user' = `touse' } else qui gen byte `touse_user' = 1 local if_touse_user "if `touse_user'" quietly if "`weight'"!="" { cap drop __wt gen __wt `exp' if `touse' if "`weight'"=="aweight" { sum __wt, meanonly replace __wt=__wt/r(mean) } global S_wt __wt local wtd "Weighted " } else global S_wt /* Extract FP model specifications. */ _jprxrpa "`fp'" ms`gamma'`delta' "FP model items" local ncl $S_1 /* could be 0 */ forvalues i=1/`ncl' { local curve ${S_p`i'} local spec "${S_c`i'}" tokenize `spec' local first = lower("`1'") if "`first'"=="fix" { if "`curve'"=="m" | "`curve'"=="s" { di as err "invalid `spec'" exit 198 } local `curve'fix "`curve'fix" mac shift if "`*'"!="" { cap confirm var `*' if _rc confirm num `*' local `curve'init `*' } } else { if "`rhs'"=="" { di as err "no xvar, cannot specify FP model" exit 198 } if "`first'"=="powers" mac shift `showtsf' fracgen `rhs' `*' `if_touse_user', `scaling' /// name(X`curve') replace `expx' `origin' `zero' adjust(mean) local `curve'vars `r(names)' local `curve'fixpow `*' } } /* Next 6 stmts set globals for use by _`dist'll.ado. Possibly could be made into _dta chars. */ global S_trunc = "`trunc'"!="" global S_cv = "`cv'"!="" global S_tau = "`tau'"!="" global S_lns = "`lns'"!="" global S_gamma `ginit' global S_delta `dinit' global S_dist `dist' /* for default use by centcalc and centcal2 */ global S_gfix = "`gfix'"!="" global S_dfix = "`dfix'"!="" global S_off `offset' /* offset for M-curve only */ quietly { /* Calculate and set up initial parameter values for ML fitting !! needs thought about how/if to incorporate initialisation for M and S */ tempname s g d mu b f V cap eq drop D cap eq drop G cap eq drop S cap eq drop M eq M : `lhs' `mvars' `mbase' eq S : `svars' `sbase' regress `lhs' `mvars' `mbase' if `touse', nohead matrix `mu' = get(_b) matrix colnames `mu' = M: if "`absres'"!="" { local scale = e(rmse) /* initialisation of sigma (_cons) */ if "`cv'"!="" { /* CV parametrization */ sum `lhs' if `touse' local scale = `scale'/r(mean) } if "`lns'"!="" local scale = ln(`scale') matrix `s' = (`scale') matrix colnames `s' = S:_cons } else { /* Initialize S via absolute residuals */ predict `M' `if_touse_user' if "`lns'"!="" { /* -1.96... is digamma(0.5), Abramowitz & Stegun p258 */ scalar `f' = -0.5*(-1.963510026+ln(2)) if "`cv'"!="" { gen `Z' = ln(abs(`lhs'/`M'-1))+`f' } else { gen `Z' = ln(abs(`lhs'-`M'))+`f' } } else { scalar `f' = sqrt(_pi/2) if "`cv'"!="" { gen `Z' = `f'*abs(`lhs'/`M'-1) } else { gen `Z' = `f'*abs(`lhs'-`M') } } regress `Z' `svars' `sbase' if `touse', nohead matrix `s' = get(_b) matrix colnames `s' = S: drop `M' `Z' } matrix `mu' = `mu',`s' local mods if "`gfix'"=="" { /* gamma to be estimated */ eq G : `gvars' `gbase' local gdim: word count `gvars' `gbase' if `gdim'>0 { forvalues i=1/`gdim' { local ginit `ginit',0 } } matrix `g' = (`ginit') matrix colnames `g' = G: matrix `mu' = `mu',`g' local mods "(G:`gvars' `gbase')" } if `pars4' & ("`dfix'"=="") { /* delta to be estimated */ eq D : `dvars' `dbase' local ddim: word count `dvars' `dbase' if `ddim'>0 { forvalues i=1/`ddim' { local dinit `dinit',1 } } matrix `d' = (`dinit') matrix colnames `d' = D: matrix `mu' = `mu',`d' local mods "`mods' (D:`dvars' `dbase')" } * version 6 of ml version 6: ml model lf xri_`dist'll (M:`lhs'=`mvars' `mbase') /* */ (S:`svars' `sbase') `mods' if `touse', /* */ title(`wtd'`dt`dnum'' Regression) ml init `mu', copy ml query noi ml maximize local dev = -2*e(ll) tempname v matrix `v' = e(V) tempvar S G z predict `M' `if_touse_user', equation(M) predict `S' `if_touse_user', equation(S) if "`gfix'"!="" { gen `G' = `ginit' `if_touse_user' } else { predict `G' `if_touse_user', equation(G) } if `pars4' { tempvar D if "`dfix'"!="" { gen `D' = `dinit' `if_touse_user' } else { predict `D' `if_touse_user', equation(D) } } if "`se'"!="" { tempvar se1 se2 se3 predict `se1' `if_touse_user', equation(M) stdp predict `se2' `if_touse_user', equation(S) stdp if "`gfix'"=="" { predict `se3' `if_touse_user', equation(G) stdp } if `pars4' & ("`dfix'"=="") { tempvar se4 predict `se4' `if_touse_user', equation(D) stdp } } /* Centiles (and standard errors) */ if `pars4' { local dd "delta(`D')" } centcalc `M' `S', centile(`centile') prefix(C) /* */ dist(`dist') gamma(`G') `dd' `cv' `lns' `tau' `trunc' /* Extract names of centile variables */ local C forvalues i=1/`nc' { local C`i' `s(cvar`i')' local C `C' `C`i'' } /* SEs of centile values. */ local no_x=("`rhs'`covars'"=="") if "`se'"!="" { forvalues i=1/`nc' { tempvar c`i'se gen `c`i'se'=. noi di as txt _n "Calculating SE of `c`i''th centile ..." if `pars4' { _se4 `dnum' /// "`mvars'" "`svars'" "`gvars'" "`dvars'" /// "`mbase'" "`sbase'" "`gbase'" "`dbase'" /// `M' `S' `G' `D' `v' "`cv'" "`tau'" "`lns'" /// "`gfix'" "`dfix'" `c`i'' `c`i'se' `no_x' `touse_user' } else { _se3 `dnum' "`mvars'" "`svars'" "`gvars'" /// "`mbase'" "`sbase'" "`gbase'" /// `M' `S' `G' `v' "`cv'" "`tau'" "`lns'" "`gfix'" /// `c`i'' `c`i'se' `no_x' `touse_user' } } } /* Standardized residuals (Z-scores), calculated (if appropriate, out of sample) by xri_*ll.ado. */ global ML_y1 `lhs' gen `Z' = . xri_`dist'll `Z' `M' `S' `G' `D' // `Z' is a placeholder here (ll) replace `Z' = __U if "`zci'"!="" { tempvar yse zl zu gen `yse' = . if `pars4' { _se4 `dnum' /// "`mvars'" "`svars'" "`gvars'" "`dvars'" /// "`mbase'" "`sbase'" "`gbase'" "`dbase'" /// `M' `S' `G' `D' `v' "`cv'" "`tau'" "`lns'" /// "`gfix'" "`dfix'" `Z' `yse' `no_x' `touse_user' } else { _se3 `dnum' "`mvars'" "`svars'" "`gvars'" /// "`mbase'" "`sbase'" "`gbase'" /// `M' `S' `G' `v' "`cv'" "`tau'" "`lns'" "`gfix'" /// `Z' `yse' `no_x' `touse_user' } local z = -invnorm((100-c(level))/200) gen `zl' = `lhs'-`z'*`yse' gen `zu' = `lhs'+`z'*`yse' global ML_y1 `zl' xri_`dist'll `yse' `M' `S' `G' `D' /* `yse' is a dummy here */ replace `zl' = __U global ML_y1 `zu' xri_`dist'll `yse' `M' `S' `G' `D' replace `zu' = __U } drop __U } /* Graph */ if "`graph'"!="nograph" & "`rhs'"!="" { qui count if `touse' local nobs = r(N) if "`saving'"!="" local saving "saving(`saving')" local ms "ms(oh)" local title `"title("`dt`dnum'' model for `lhs'")"' local subtitle `"subtitle("`centile' centiles")"' local ytitle `"ytitle("`lhs'")"' local xtitle `"xtitle("`rhs'")"' scatter `lhs' `rhs' if `touse', `ms' `scatter' || /// line `M' `C' `rhs' if `touse', sort `ytitle' `xtitle' `title' `subtitle' legend(off) `options' || /// `plot' /* gr7 `lhs' `M' `C' `rhs' if `touse', t1title("`t1title'") xlab ylab /* */ t2title("`t2title'") l1("`lhs'") b2("`rhs'") sort `saving' `cs' */ } /* Save variables if required, and name/label them. */ if "`leave'"=="" { local prog "_ml" local vn Z`prog' cap drop `vn' rename `Z' `vn' lab var `vn' "`dupper' Z-scores" if "`cv'"!="" local cvl " [cv]" if "`lns'"!="" local lnsl "ln " local a1 m local a2 s local b1 "location" local b2 "`lnsl'scale`cvl'" if `pars3' { local b3 "shape" local a3 g } if `pars4' { local b3 "shape [gamma]" local a4 d local b4 "shape [delta]" } local p=2+`pars3'+`pars4' forvalues i=1/`p' { local a `a`i'' local A = upper("`a'") local b `b`i'' local vn `A'`prog' cap drop `vn' rename ``A'' `vn' if "``a'fix'"!="" local add "fixed at ``a'init'" else if "``a'fixpow'"!="" local add "powers ``a'fixpow'" else local add "constant" lab var `vn' "`dupper' `b': `add'" if "`se'"!="" & (`i'<=2 | (`i'==3 & "`gfix'"=="") /* */ | ((`i'==4) & `pars4' & "`dfix'"=="")) { local vn se`vn' cap drop `vn' rename `se`i'' `vn' lab var `vn' "`dupper' se[`b']" } } forvalues i=1/`nc' { local cent `c`i'' local vn = substr("`C`i''`prog'",1,8) cap drop `vn' rename `C`i'' `vn' lab var `vn' "`dupper' `cent' centile" if "`se'"!="" { local vn=substr("se`vn'",1,8) cap drop `vn' rename `c`i'se' `vn' lab var `vn' "`dupper' se[`cent' centile]" } } if "`zci'"!="" { local vn "Zl`prog'" cap drop `vn' rename `zl' `vn' lab var `vn' "`dupper' Z lower c(level)% conf. limit" local vn "Zu`prog'" cap drop `vn' rename `zu' `vn' lab var `vn' "`dupper' Z upper c(level)% conf. limit" } } di as txt _n "Final deviance = " %9.3f as res `dev' /* */ as txt " (" as res e(N) as txt " observations.)" if "`tidy'"!="notidy" { if "`mvars'"!="" drop `mvars' if "`svars'"!="" drop `svars' if "`gvars'"!="" drop `gvars' if "`dvars'"!="" drop `dvars' } global S_1 `dev' ereturn scalar dev=`dev' ereturn local dist `dist' ereturn local cmd xriml end program define _se3 /* SE for estimated centiles, 2 and 3 parameter models */ version 8 args dnum /// distribution number vars1 /// covariates for M-curve vars2 /// covariates for S-curve vars3 /// covariates for G-curve base1 /// base vars for M-curve base2 /// base vars for S-curve base3 /// base vars for G-curve M /// S /// G /// V /// cv /// tau /// lns /// gfix /// centile /// cse /// no_x /// touse_user foreach thing in cv tau lns gfix { local `thing' = ("``thing''"!="") } * Treat normal as boxcox if `dnum'==0 local dnum 2 * Put names of covariates into xn* local small 1e-6 local npar 0 // npar counts the covariates, including _cons's forvalues p=1/3 { // parameter no.: 1=m, 2=s, 3=g local no_gpar = `gfix' & (`p'==3) if `no_gpar' local n3 0 else local n`p' 1 /* Put names of the FP and base covariates into xn* */ if "`vars`p''`base`p''"!="" { tokenize `vars`p'' `base`p'' while "`1'"!="" { local ++n`p' local ++npar local xn`npar' "`1'" mac shift } } if !`no_gpar' local ++npar // add one for _cons } /* Calc derivatives wrt params. */ tempvar h1 h2 h3 A B cap confirm var `centile' if _rc { tempname uq scalar `uq'=invnorm(`centile'/100) } else local uq `centile' /* uq contains Z-scores (zci option) */ if `lns' { /* log S parameterization */ tempvar s gen `s' = exp(`S') } else local s `S' if `dnum'==1 { /* SLN */ gen `A' = exp(`G'*`uq') gen `h1' = 1 if `cv' { gen `h2' = cond(abs(`G')<`small', `M'*`uq', /* */ `M'*(`A'-1)/`G' ) } else gen `h2' = cond(abs(`G')<`small', `uq', (`A'-1)/`G' ) if !`gfix' { if `cv' { gen `h3' = cond(abs(`G')<`small', /* */ 0.5*`s'*`M'*`uq'^2, /* */ (`A'*(`uq'-1/`G')+1/`G')*`s'*`M'/`G' ) } else { gen `h3' = cond(abs(`G')<`small', /* */ 0.5*`s'*`uq'^2, /* */ (`A'*(`uq'-1/`G')+1/`G')*`s'/`G' ) } } } else if `dnum'==2 { /* PN */ if `tau' { /* tau parameterization */ tempvar t /* lambda */ if `cv' { gen `t' = 1-`G'/`s' } else gen `t' = 1-`G'*`M'/`s' } else local t `G' if `cv' { gen `B' = `uq'*`s' } else gen `B' = `uq'*`s'/`M' gen `A' = (1+`t'*`B')^(1/`t') gen `h1' = cond(abs(`t')<`small', (1-`B')*exp(`B'), /* */ `A'*(1-`B'/`A'^`t')) if `cv' { gen `h2' = cond(abs(`t')<`small', `M'*`uq'*exp(`B'), /* */ `M'*`uq'*`A'^(1-`t')) } else { gen `h2' = cond(abs(`t')<`small', `uq'*exp(`B'), /* */ `uq'*`A'^(1-`t')) } if !`gfix' { gen `h3' = cond(abs(`t')<`small', -0.5*`M'*`B'^2*exp(`B'), /* */ `M'*`A'*(`B'/`A'^`t'-log(`A'))/`t') } } else if `dnum'==3 { /* EN */ gen `A' = 1+`G'*`uq' gen `h1' = 1 if `cv' { gen `h2' = cond(abs(`G')<`small', `M'*`uq', /* */ `M'*log(`A')/`G' ) } else gen `h2' = cond(abs(`G')<`small', `uq', log(`A')/`G' ) if !`gfix' { if `cv' { gen `h3' = cond(abs(`G')<`small', /* */ -0.5*`s'*`M'*`uq'^2, /* */ (1-1/`A'-log(`A'))*`s'*`M'/`G'^2 ) } else { gen `h3' = cond(abs(`G')<`small', /* */ -0.5*`s'*`uq'^2, /* */ (1-1/`A'-log(`A'))*`s'/`G'^2 ) } } } * Calc SE of centile, element-by-element tempname xx h hbeta hVh se matrix `hbeta' = J(1,`npar',0) local pp = 3-`gfix' local n = _N forvalues i = 1 / `n' { if `touse_user'[`i'] == 1 { * multiply centile derivs by data for each parameter local k 0 forvalues param=1/`pp' { scalar `h' = `h`param''[`i'] local np `n`param'' forvalues j=1/`np' { local ++k if `j'<`np' { scalar `xx'=`xn`k''[`i'] } else scalar `xx'=1 matrix `hbeta'[1,`k'] =`h'*`xx' } } matrix `hVh' = `hbeta'*`V' matrix `hVh' = `hVh'*`hbeta'' scalar `se'=sqrt(`hVh'[1,1]) if `no_x' continue, break qui replace `cse'=`se' in `i' } } if `no_x' qui replace `cse' = `se' if `touse_user' end program define _se4 /* SE for estimated centiles, MPN and MEN models */ version 8 args dnum /// distribution number vars1 /// covariates for M-curve vars2 /// covariates for S-curve vars3 /// covariates for G-curve vars4 /// covariates for D-curve base1 /// base vars for M-curve base2 /// base vars for S-curve base3 /// base vars for G-curve base4 /// base vars for D-curve M /// S /// G /// D /// V /// VCE matrix of parameters cv /// tau /// lns /// gfix /// dfix /// centile /// cse /// to hold SE, assumed to exist no_x /// touse_user foreach thing in cv tau lns gfix dfix { local `thing' = ("``thing''"!="") } local small 1e-6 local npar 0 // npar counts the covariates, including _cons's forvalues p=1/4 { // parameter no.: 1=m, 2=s, 3=g, 4=d local no_gpar = `gfix' & (`p'==3) local no_dpar = `dfix' & (`p'==4) if `no_gpar' | `no_dpar' local n`p' 0 else local n`p' 1 if "`vars`p''`base`p''"!="" { /* Put names of the FP and base covariates into xn* */ tokenize `vars`p'' `base`p'' while "`1'"!="" { local n`p'=`n`p''+1 local npar=`npar'+1 local xn`npar' "`1'" mac shift } } /* Add one param for _cons */ if !`no_gpar' & !`no_dpar' local ++npar } /* Calc first derivatives w.r.t. params. */ tempvar h1 h2 h3 h4 A B DD zq s cap confirm var `centile' if _rc { tempname uq scalar `uq' = invnorm(`centile'/100) } else local uq `centile' // uq contains Z-scores (zci option) gen `DD' = 1+`D'*abs(`uq') gen `zq' = sign(`uq')*(`DD'^(1/`D')-1) if `lns' { // log S parameterization gen `s' = exp(`S') } else gen `s' = `S' if `cv' replace `s' = `s'*`M' // `s' is sigma, not cv if `dnum'==7 { // MPN if `tau' { // tau parameterization tempvar t // lambda gen `t' = 1-`G'*`M'/`s' } else local t `G' gen `B' = `zq'*`s'/`M' gen `A' = cond(abs(`t')<`small', exp(`B'), (1+`t'*`B')^(1/`t')) gen `h1' = cond(abs(`t')<`small', `A'*(1-`B'), `A'*(1-`B'/`A'^`t')) if `cv' gen `h2' = `M'*`zq'*`A'^(1-`t') else gen `h2' = `zq'*`A'^(1-`t') if !`gfix' { gen `h3' = cond(abs(`t')<`small', -0.5*`M'*`A'*`B'^2, /* */ (`M'*`A'/`t')*(`B'/`A'^`t'-log(`A')) ) } if !`dfix' { gen `h4' = (`zq'+sign(`uq'))*(`s'/`D')*`A'^(1-`t')* /* */ (abs(`uq')/`DD'-log(`DD')/`D') } } else if `dnum'==8 { // MEN gen `A' = 1+`G'*`zq' gen `h1' = 1 if `cv' { gen `h2' = cond(abs(`G')<`small', `M'*`zq', `M'*log(`A')/`G' ) } else gen `h2' = cond(abs(`G')<`small', `zq', log(`A')/`G' ) if !`gfix' { gen `h3' = cond(abs(`G')<`small', /* */ -0.5*`s'*`zq'^2, (1-1/`A'-log(`A'))*`s'/`G'^2 ) } if !`dfix' { gen `h4' = (`zq'+sign(`uq'))*(`s'/(`D'*`A'))* /* */ (abs(`uq')/`DD'-log(`DD')/`D') } } * Calc SE of centile, element-by-element tempname xx h hbeta hVh se matrix `hbeta' = J(1,`npar',0) local pp = 4-`gfix'-`dfix' local n = _N forvalues i = 1 / `n' { if `touse_user'[`i'] == 1 { * multiply centile derivs by data for each parameter local k 0 forvalues param=1/`pp' { scalar `h'=`h`param''[`i'] local np `n`param'' forvalues j=1/`np' { local ++k if `j'<`np' { scalar `xx' = `xn`k''[`i'] } else scalar `xx' = 1 matrix `hbeta'[1,`k'] = `h'*`xx' } } matrix `hVh' = `hbeta'*`V' matrix `hVh' = `hVh'*`hbeta'' scalar `se' = sqrt(`hVh'[1,1]) if `no_x' continue, break qui replace `cse' = `se' in `i' } } if `no_x' qui replace `cse' = `se' `if_touse_user' end *! v 1.0.1 PR 01Jun95. program define _jprxrpa // parses "clusters" version 8 args stuff /// string to be parsed prefixs /// string of permitted one-character prefixes items /// items in error message if #clusters > #prefixes local nprefix = length("`prefixs'") forvalues i=1/`nprefix' { local p`i'=substr("`prefixs'",`i',1) global S_p`i' global S_c`i' } tokenize "`stuff'", parse(",") global S_1 0 /* # of comma-delimited clusters */ while "`1'"!="" { if "`1'"=="," mac shift global S_1 = $S_1+1 local clust$S_1 "`1'" mac shift } if "`clust${S_1}'"=="" global S_1 = $S_1-1 if $S_1>`nprefix' { noi di as err "too many `items' specified" exit 198 } /* Disentangle each prefix:string cluster */ forvalues i=1/$S_1 { parse "`clust`i''", parse("=:") local prefix = lower(substr("`1'",1,1)) local j 1 local found 0 while (`j'<=`nprefix') & !`found' { if "`prefix'"=="`p`j''" { global S_p`i' `prefix' global S_c`i' "`3'" local found 1 } local ++j } if !`found' { noi di as err "invalid `clust`i''" exit 198 } } end