/******************************************************************************* NOTES: - the first covariate is the treatment of interest - example syntax: mhtexpreg (y1 d1 if sub==1) (y1 d1 if sub==2) (y3 d1 if sub==1) (y3 d1 if sub==2), bootstrap(5000) - added error message if moremata package not installed - changed specification of cltype option - changed the check for missing values *******************************************************************************/ program mhtreg, rclass sortpreserve version 14 syntax anything, [bootstrap(integer 3000) robust cluster(varname) cltype(integer 0) seed(real -1) replace] // cltype specifications // 1 clustered bootstrap // 2 clustered errors in model // 3 clustered in both instances tempvar clus touse_any local i=1 while strlen("`anything'")>0 { gettoken eqn`i' anything : anything, parse(" ,[") match(paren) if ("`eqn`i''"=="") continue gettoken y`i' x`i': eqn`i' local x`i' = subinstr("`x`i''"," if ",",",.) gettoken x`i' co`i': x`i', parse(",") local co`i' = subinstr("`co`i''",",","",.) tempvar touse`i' gen byte `touse`i''=1 markout `touse`i'' `y`i'' `x`i'' // missings in variables if ("`co`i''"!="") quietly replace `touse`i'' = 0 if !(`co`i'') // if condition local y_list = "`y_list' `y`i''" local t_list = "`t_list' `touse`i''" local n_eq=`i' local i = `i'+1 } egen `touse_any' = rowmax(`t_list') quietly count if `touse_any'==1 local n = r(N) // Check whether moremata is installed cap which moremata.hlp if _rc { di as error "mhtreg requires the moremata package. Install by typing ssc install moremata." exit } if (`seed'!=-1) mata: rseed(`seed') // In principle, these elements are not necessary anymore with the new syntax. Eliminate them in future version mata: excludemat = (.,.,.) mata: onlymat = (.,.,.) mata: xmat = rbuildPointer(`n_eq') mata: ymat = rbuildPointer(`n_eq') mata: tomat = rbuildPointer(`n_eq') mata: TOA = rbuildTO("`touse_any'", "`touse_any'") // Indicator for all observations that should be considered in the bootstrap // If no cluster variable is specified, generate artificial cluster where each obs is its own cluster // Note: it's important that the sort command is executed before rbuilding the data matrices if ("`cluster'" != "" & `cltype'==0) local cltype = 3 if ("`cluster'" != "" & `cltype'!=0) { gen `clus' = `cluster' } else { gen `clus' = _n } sort `clus' mata: CLUSTER = rbuildCLUSTER("`clus'","`touse_any'") forvalues c=1/`n_eq' { mata: Y`c' = rbuildY("`y`c''", "`touse_any'") mata: X`c' = rbuildX("`x`c''", "`touse_any'") mata: TO`c' = rbuildTO("`touse`c''", "`touse_any'") mata: xmat[`c']=&X`c' mata: ymat[`c']=&Y`c' mata: tomat[`c']=&TO`c' } mata: sizes = rbuildsizes(`n_eq') mata: combo = rbuildcombo(sizes[3]) mata: numpc = rbuildnumpc(combo) mata: select = rbuildselect(onlymat, excludemat, sizes[1], sizes[2], numpc) mata: results = seidelxusteinmayr(ymat, xmat, tomat, TOA, `n_eq', combo, select, `bootstrap', "`robust'", CLUSTER, `cltype') mata: rbuildoutput("results", results) matlist results if "`replace'"=="replace" { clear svmat results, names(col) } return matrix results = results end mata: function rbuildPointer(real scalar n_eq) { // returns an matrix of pointers pointer(real matrix) rowvector pmat pmat = J(1, n_eq, NULL) return(pmat) } function rbuildY(string scalar outcome, string scalar touse) { // returns an X matrix that contains the treatment of interest and a constant Y = st_data(., tokens(outcome), touse) return(Y) } function rbuildTO(string scalar num, string scalar touse) { // returns an X matrix that contains the treatment of interest and a constant TO = st_data(., tokens(num), touse) return(TO) } function rbuildCLUSTER(string scalar cluster, string scalar touse) { // returns a matrix that contains the cluster variable CLUSTER = st_data(., tokens(cluster), touse) return(CLUSTER) } function rbuildX(string scalar covars, string scalar touse) { // returns an X matrix that contains the treatment of interest and a constant TO = st_data(., tokens(touse), touse) if (covars!="") { X = st_data(., tokens(covars), touse), J(rows(TO), 1,1) } else { X = J(rows(TO), 1,1) } return(X) } function rbuildsizes(real scalar n_eq) { numg = 1 // nojoint adds all treatments together and runs the test of any treatment versus the control group (0...do joint, 1...no joint) numoc = n_eq numsub = 1 return((numoc, numsub, numg)) } function rbuildcombo(real scalar numg){ combo = (J(numg,1,0), (1::numg)) return(combo) } function rbuildnumpc(real matrix combo){ return(rows(combo)) } function rbuildselect(real matrix only, real matrix exclude, real scalar numoc, real scalar numsub, real scalar numpc){ if (rownonmissing(only) != 0){ select =rmdarray((numoc, numsub, numpc),0) for (r = 1; r <= rows(only); r++){ i = only[r, 1] j = only[r, 2] k = only[r, 3] rput(1, select, (i,j,k)) } }else{ select =rmdarray((numoc, numsub, numpc), 1) } if (rownonmissing(exclude) !=0){ for (r=1; r <= rows(exclude); r++){ i = exclude[r, 1] j = exclude[r, 2] k = exclude[r, 3] rput(0, select, (i,j,k)) } } return(select) } end