***Randinf******************************************** ***by John Ternovski, S3 R&D Lab, Harvard University** ***Version 1.7**************************************** ********version history ******1.7 minor fixes based on CK's comments ******1.6 added onesided p-value option ******1.5 fixed bug excluding strata when covars are specified and normalizing rank ******1.4 added ability to specify custom residuals ******1.3 using tempnames for all locals ******1.2 added ability to specify custom covars program define randinf, eclass version 12 syntax [if] [in], TReat(varname) STRata(varname) [iter(real 1000)] OUTcome(varname) [GRANularity(real .05)] [MIss] [COVars(string)] [DIsplayprogress] [resid(string)] [ONEsided] [NOFigure] ***************check if required packages exist****** cap which shufflevar if _rc { ssc install shufflevar } *****************error checking****** qui tab `treat' if `r(r)'!=2 { disp as error "ERROR: Treatment variable must be binary." exit } ******************keep just the specified data preserve if "`in'"!="" { qui keep `in' } if "`if'"!="" { qui keep `if' } ****************setting up variables***** //generating variables that will be used in the "p-value"" vs. "treatment effects" output graph tempvar treatgroup pvalueforgraph tauforgraph counterforgraph qui egen `treatgroup'=group(`treat') qui replace `treatgroup'=`treatgroup'-1 qui gen `pvalueforgraph'=. qui gen `tauforgraph'=. qui gen `counterforgraph'=. //setting up strata you can use both string and numeric strata tempvar stratanum qui egen `stratanum'=group(`strata') //drop strata with missing values unless miss is specified if "`miss'"=="" { cap drop if `stratanum'==. } //makes sure youre limiting just to those assigned treatment conditions qui drop if `treatgroup'==. //setting up data to accommodate distribution of test statistics in null distribution cap set obs `iter' //need a variable to be as long as the number of iterations //setting up locals tempname innull donegativenow counter tau local `innull'=1 //while-loop breaker local `donegativenow'=0 //look at negative treatment effects local `counter'=1 //counter local `tau'=0 //tau = treatment effect, start with 0 then add iteratively ****************************************** *********generating residuals************* if "`resid'"=="" { //if using custom covars... if "`covars'"!="" { if "`displayprogress'"!="" { xi: areg `outcome' `covars', absorb(`stratanum') } else { qui xi: areg `outcome' `covars', absorb(`stratanum') } } else { if "`displayprogress'"!="" { xi: reg `outcome' i.`stratanum' } else { qui xi: reg `outcome' i.`stratanum' } } tempvar resid qui predict `resid', residuals } ****************************************** tempname finalpvalue ********running randomizaiton inference*** while "``innull''"=="1" { //setting up locals now for each randomization loop tempvar y0 rank synthstat tempname controlrankmean treatrankmean actualstat fakestatindiv meansynthstat pvalue //generating y0 (null distribution) from residuals qui gen `y0'=`resid' if `treatgroup'==0 qui replace `y0'=(`resid'-``tau'') if `treatgroup'==1 //generating rank qui egen `rank'=rank(`y0') qui count if `rank'!=. qui replace `rank'=`rank'-((`r(N)'+1)/2) //normalize ranks qui sum `rank' if `treatgroup'==0 local `controlrankmean'=`r(mean)' qui sum `rank' if `treatgroup'==1 local `treatrankmean'=`r(mean)' //using absolute difference in ranks as test statistic local `actualstat'=``treatrankmean''-``controlrankmean'' local `actualstat'=``actualstat'' qui drop `rank' //generating null distribution by randomly permuting treatment assignment within strata qui gen `synthstat'=. forval qp=1/`iter' { qui shufflevar `treatgroup', cluster(`stratanum') //custom shufflevar package qui egen `rank'=rank(`y0') qui count if `rank'!=. qui replace `rank'=`rank'-((`r(N)'+1)/2) //normalize ranks qui sum `rank' if `treatgroup'_shuffled==0 local `controlrankmean'=`r(mean)' qui sum `rank' if `treatgroup'_shuffled==1 local `treatrankmean'=`r(mean)' local `fakestatindiv'=``treatrankmean''-``controlrankmean'' local `fakestatindiv'=``fakestatindiv'' qui replace `synthstat'=``fakestatindiv'' in `qp' qui drop `rank' `treatgroup'_shuffled } qui sum `synthstat' local `meansynthstat'=`r(mean)' //now taking the mean of the statistic variable //now see where our y0 statistic rests in comparison to the synthetic distribution if "`onesided'"=="onesided" { if ``actualstat''<0 { qui count if `synthstat'>``actualstat'' & `synthstat'!=. } else { qui count if `synthstat'<``actualstat'' & `synthstat'!=. } } else { qui count if `synthstat'