*! version 1.0 31/31/2024 * This is dltable with 3 digits precision cap program drop dltable program define dltable version 18.0 set more off syntax [varlist] [using] [if], TREATment(varlist) CONTrol(varlist fv) [PARTialout(varlist fv) CLUSTer(varlist) keep quiet sd sheet(string asis) QValue(name) SELECTion(name)] pause on quiet{ if mi("`keep'")==1 { preserve foreach cvar in VAR LAB N_ind N_clust A C COEF* { capture confirm variable `cvar' if !_rc { dis as error "Dataset should not include the following variables: VAR LAB N_ind N_clust A C COEF* " exit 100 } } quiet for any VAR LAB N_ind N_clust A C COEF* : cap drop X } if mi("`qvalue'") ==0 { cap which qqvalue if _rc ssc install qqvalue if "`qvalue'" =="bky" | "`qvalue'" =="bonferroni" | "`qvalue'" =="sidak" | "`qvalue'" =="holm" | "`qvalue'" =="holland" | "`qvalue'" =="hochberg" | "`qvalue'" =="simes" | "`qvalue'" =="yekutieli"{ dis "Qvalues are based on `qvalue'" } else { dis as error `"Unrecognised method `qvalue' "' } } local c=1 foreach i in `treatment' { quiet: gen COEF`c' ="" local c=`c'+1 } local c=`c'-1 forval h=1/`c' { local COEFS "`COEFS' COEF`h'" if `h'==1 { local COEFS_tex "T`h'" } else{ local COEFS_tex "`COEFS_tex' & T`h' " } } foreach i in VAR LAB A C N_ind N_clust { quiet: gen `i'="" } *** Add additional lines if number of test > number of observations cap set obs `=wordcount("`varlist'")*3+5' } local pvalues="" local j=1 local k=1 foreach i in `varlist' { if mi("`quiet'")==0 { xi: quietly dsregress `i' `treatment' `if' , cluster(`cluster') controls((`partialout') `control') selection(`selection') } if mi("`quiet'")==1 { xi: quietly dsregress `i' `treatment' `if' , cluster(`cluster') controls((`partialout') `control') selection(`selection') } local t: variable label `i' quiet: replace VAR="`i'" if _n==`j' quiet: replace LAB="`t'" if _n==`j' tokenize `treatment' local temoin "`1'==0" forval v=2/`c' { if "``v''"!= "" { local cond "`cond' & ``v''==0" local temoin "`temoin' & ``v''==0" } } * Creation of a Control Tempvar taking value 1 when control and 0 otherwise. tempvar T0 gen `T0' = cond(`temoin', 1, 0) if `1'!=. if mi("`if'")==1 { quiet { sum `i' [`weight'`exp'] if `T0'==1 `cond' , d if abs(r(mean))>=10 & abs(r(mean))<100 { quiet: replace C="`: display %7.2fc r(mean)'" if _n==`j' } if abs(r(mean))>=100 & abs(r(mean))<1000 { quiet: replace C="`: display %7.1fc r(mean)'" if _n==`j' } if abs(r(mean))>=1000 { quiet: replace C="`: display %7.0fc r(mean)'" if _n==`j' } if abs(r(mean)) <10 { quiet: replace C="`: display %7.3fc r(mean)'" if _n==`j' } quiet: replace C= subinstr(C," ","",.) if _n==`j' quiet: replace C= "0.000" if _n==`j' & C=="-0.000" if mi("`sd'")==0 { if abs(r(sd))>=10 & abs(r(sd))<100 { quiet: replace C="`: display %7.2fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=100 & abs(r(sd))<1000 { quiet: replace C="`: display %7.1fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=1000 { quiet: replace C="`: display %7.0fc r(sd)'" if _n==`j'+1 } if abs(r(sd)) <10 { quiet: replace C="`: display %7.3fc r(sd)'" if _n==`j'+1 } replace C=subinstr(C," ","",.) if _n==`j'+1 quiet: replace C= "0.000" if _n==`j'+1 & C=="-0.000" replace C="["+C+"]" if _n==`j'+1 } } quiet { sum `i' [`weight'`exp'] , d if abs(r(mean))>=10 & abs(r(mean))<100 { quiet: replace A="`: display %7.2fc r(mean)'" if _n==`j' } if abs(r(mean))>=100 & abs(r(mean))<1000 { quiet: replace A="`: display %7.1fc r(mean)'" if _n==`j' } if abs(r(mean))>=1000 { quiet: replace A="`: display %7.0fc r(mean)'" if _n==`j' } if abs(r(mean)) <10 { quiet: replace A="`: display %7.3fc r(mean)'" if _n==`j' } quiet replace A=subinstr(A," ","",.) if _n==`j' quiet: replace A= "0.000" if _n==`j' & A=="-0.000" } if mi("`sd'")==0 { quiet { if abs(r(sd))>=10 & abs(r(sd))<100 { replace A="`: display %7.2fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=100 & abs(r(sd))<1000 { replace A="`: display %7.1fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=1000 { replace A="`: display %7.0fc r(sd)'" if _n==`j'+1 } if abs(r(sd)) <10 { replace A="`: display %7.3fc r(sd)'" if _n==`j'+1 } replace A=subinstr(A," ","",.) if _n==`j'+1 replace A= "0.000" if _n==`j'+1 & A=="-0.000" replace A="["+A+"]" if _n==`j'+1 } } } else { quiet { sum `i' [`weight'`exp'] `if' & `T0'==1 `cond' , d if abs(r(mean))>=10 & abs(r(mean))<100 { quiet: replace C="`: display %7.2fc r(mean)'" if _n==`j' } if abs(r(mean))>=100 & abs(r(mean))<1000 { quiet: replace C="`: display %7.1fc r(mean)'" if _n==`j' } if abs(r(mean))>=1000 { quiet: replace C="`: display %7.0fc r(mean)'" if _n==`j' } if abs(r(mean)) <10 { quiet: replace C="`: display %7.3fc r(mean)'" if _n==`j' } replace C=subinstr(C," ","",.) if _n==`j' quiet: replace C= "0.000" if _n==`j' & C=="-0.000" } if mi("`sd'")==0 { quiet{ if abs(r(sd))>=10 & abs(r(sd))<100 { quiet: replace C="`: display %7.2fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=100 & abs(r(sd))<1000 { quiet: replace C="`: display %7.1fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=1000 { quiet: replace C="`: display %7.0fc r(sd)'" if _n==`j'+1 } if abs(r(sd)) <10 { quiet: replace C="`: display %7.3fc r(sd)'" if _n==`j'+1 } replace C=subinstr(C," ","",.) if _n==`j'+1 quiet: replace C= "0.000" if _n==`j'+1 & C=="-0.000" replace C="["+C+"]" if _n==`j'+1 } } quiet { sum `i' [`weight'`exp'] `if' , d } if mi("`sd'")==0 { quiet { if abs(r(sd))>=10 & abs(r(sd))<100 { quiet: replace A="`: display %7.2fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=100 & abs(r(sd))<1000 { quiet: replace A="`: display %7.1fc r(sd)'" if _n==`j'+1 } if abs(r(sd))>=1000 { quiet: replace A="`: display %7.0fc r(sd)'" if _n==`j'+1 } if abs(r(sd)) <10 { quiet: replace A="`: display %7.3fc r(sd)'" if _n==`j'+1 } replace A=subinstr(A," ","",.) if _n==`j'+1 replace A= "0.000" if _n==`j'+1 & A=="-0.000" replace A="["+A+"]" if _n==`j'+1 } } quiet { if abs(r(mean))>=10 & abs(r(mean))<100 { quiet: replace A="`: display %7.2fc r(mean)'" if _n==`j' } if abs(r(mean))>=100 & abs(r(mean))<1000 { quiet: replace A="`: display %7.1fc r(mean)'" if _n==`j' } if abs(r(mean))>=1000 { quiet: replace A="`: display %7.0fc r(mean)'" if _n==`j' } if abs(r(mean)) <10 { quiet: replace A="`: display %7.3fc r(mean)'" if _n==`j' } replace A=subinstr(A," ","",.) if _n==`j' replace A= "0.000" if _n==`j' & A=="-0.000" } } quiet { replace N_ind="`: display %7.0fc e(N)'" if _n==`j' replace N_ind=subinstr(N_ind," ","",.) if _n==`j' distinct `cluster' if e(sample) replace N_clust="`: display %7.0fc r(ndistinct)'" if _n==`j' replace N_clust=subinstr(N_clust," ","",.) if _n==`j' } forval h=1/`c' { quiet{ * cleaning and stars * first row if abs(_b[``h''])>=10 & abs(_b[``h''])<100 { quiet: replace COEF`h'="`: display %4.2fc _b[``h'']'" if _n==`j' } if abs(_b[``h''])>=100 & abs(_b[``h''])<1000 { quiet: replace COEF`h'="`: display %4.1fc _b[``h'']'" if _n==`j' } if abs(_b[``h''])>=1000 { quiet: replace COEF`h'="`: display %4.0fc _b[``h'']'" if _n==`j' } if abs(_b[``h'']) <10 { quiet: replace COEF`h'="`: display %4.3fc _b[``h'']'" if _n==`j' } replace COEF`h'=subinstr(COEF`h'," ","",.) if _n==`j' replace COEF`h'="0.000" if _n==`j' & COEF`h'=="-0.000" replace COEF`h'=COEF`h'+"*" if _n==`j' & 2*normal(-abs(_b[``h'']/_se[``h''])) <=0.1 replace COEF`h'=COEF`h'+"*" if _n==`j' & 2*normal(-abs(_b[``h'']/_se[``h'']))<=0.05 replace COEF`h'=COEF`h'+"*" if _n==`j' & 2*normal(-abs(_b[``h'']/_se[``h'']))<=0.01 * second row (SE) if abs(_se[``h''])>=10 & abs(_se[``h''])<100 { quiet: replace COEF`h'="`: display %4.2fc _se[``h'']'" if _n==`j'+1 } if abs(_se[``h''])>=100 & abs(_se[``h''])<1000 { quiet: replace COEF`h'="`: display %4.1fc _se[``h'']'" if _n==`j'+1 } if abs(_se[``h''])>=1000 { quiet: replace COEF`h'="`: display %4.0fc _se[``h'']'" if _n==`j'+1 } if abs(_se[``h'']) <10 { quiet: replace COEF`h'="`: display %4.3fc _se[``h'']'" if _n==`j'+1 } replace COEF`h'=subinstr(COEF`h'," ","",.) if _n==`j'+1 replace COEF`h'="0.000" if _n==`j'+1 & COEF`h'=="-0.000" replace COEF`h'="("+COEF`h'+")" if _n==`j'+1 * store pvalues for qvalue calculation if mi("`qvalue'") ==0 { local p``h''=2*normal(-abs(_b[``h'']/_se[``h''])) local pvalues="`pvalues' `p``h''' " } } } if mi("`qvalue'")==0 { local j= `j'+3 } if mi("`qvalue'") ==1 { local j= `j'+2 } local k= `k'+1 } * qvalues if mi("`qvalue'")==0 & "`qvalue'" !="bky" { quietly { tempvar P gen `P'=. tempvar Q local count=1 foreach p in `pvalues' { replace `P'=`p' if _n==`count' local count= `count'+1 } qqvalue `P', method(`qvalue') qvalue(`Q') local j=0 local qcount=0 foreach varq in `varlist' { local j= `j'+3 forval h=1/`c' { local qcount= `qcount'+1 replace COEF`h'="`: display %7.3fc `Q'[`qcount']'" if _n==`j' replace COEF`h'=subinstr(COEF`h'," ","",.) if _n==`j' replace COEF`h'="["+COEF`h'+"]" if _n==`j' } } } drop `Q' `P' } if "`qvalue'" =="bky" { quietly { tempvar Q tempvar q gen `Q'=. local count=1 foreach k in `pvalues' { replace `Q'=`k' if _n==`count' local count= `count'+1 } sum `Q' local totalpvals = r(N) * Sort the p-values in ascending order and generate a variable that codes each p-value's rank tempvar original_sorting_order gen int `original_sorting_order' = _n sort `Q' tempvar rank gen int `rank' = _n if `Q'!=. * Set the initial counter to 1 local qval = 1 * Generate the variable that will contain the BKY (2006) sharpened q-values gen `q' = 1 if `Q'!=. * Set up a loop that begins by checking which hypotheses are rejected at q = 1.000, then checks which hypotheses are rejected at q = 0.999, then checks which hypotheses are rejected at q = 0.998, etc. The loop ends by checking which hypotheses are rejected at q = 0.001. while `qval' > 0 { * First Stage * Generate the adjusted first stage q level we are testing: q' = q/1+q local qval_adj = `qval'/(1+`qval') * Generate value q'*r/M tempvar fdr_temp1 gen `fdr_temp1' = `qval_adj'*`rank'/`totalpvals' * Generate binary variable checking condition p(r) <= q'*r/M tempvar reject_temp1 gen `reject_temp1' = (`fdr_temp1'>=`Q`h'') if `Q`h''!=. * Generate variable containing p-value ranks for all p-values that meet above condition tempvar reject_rank1 gen `reject_rank1' = `reject_temp1'*`rank' * Record the rank of the largest p-value that meets above condition tempvar total_rejected1 egen `total_rejected1' = max(`reject_rank1') * Second Stage * Generate the second stage q level that accounts for hypotheses rejected in first stage: q_2st = q'*(M/m0) local qval_2st = `qval_adj'*(`totalpvals'/(`totalpvals'-`total_rejected1'[1])) * Generate value q_2st*r/M tempvar fdr_temp2 gen `fdr_temp2' = `qval_2st'*`rank'/`totalpvals' * Generate binary variable checking condition p(r) <= q_2st*r/M tempvar reject_temp2 gen `reject_temp2' = (`fdr_temp2'>=`Q`h'') if `Q`h''!=. * Generate variable containing p-value ranks for all p-values that meet above condition tempvar reject_rank2 gen `reject_rank2' = `reject_temp2'*`rank' * Record the rank of the largest p-value that meets above condition tempvar total_rejected2 egen `total_rejected2' = max(`reject_rank2') * A p-value has been rejected at level q if its rank is less than or equal to the rank of the max p-value that meets the above condition replace `q' = `qval' if `rank' <= `total_rejected2' & `rank'!=. * Reduce q by 0.001 and repeat loop drop `fdr_temp1' `reject_temp1' `reject_rank1' `total_rejected1' `fdr_temp2' `reject_temp2' `reject_rank2' `total_rejected2' local qval = `qval' - .001 } quietly sort `original_sorting_order' local j=0 local qcount=0 foreach varq in `varlist' { local j= `j'+3 forval h=1/`c' { local qcount= `qcount'+1 replace COEF`h'="`: display %7.3fc `q'[`qcount']'" if _n==`j' replace COEF`h'=subinstr(COEF`h'," ","",.) if _n==`j' replace COEF`h'="["+COEF`h'+"]" if _n==`j' } } drop `q`h'' `Q`h'' `original_sorting_order' } } * Summary variable at the bottom of the table quietly { if mi("`if'")==1 { replace VAR="Observations" if _n==`j'+1 count if `1'!=. replace N_ind="`: display %7.0fc r(N)'" if _n==`j'+1 replace N_ind= subinstr(N_ind," ","",.) if _n==`j'+1 count if `T0'==1 replace C="`: display %7.0fc r(N)'" if _n==`j'+1 replace C= subinstr(C," ","",.) if _n==`j'+1 local l=1 foreach i in `treatment' { count if `i'==1 replace COEF`l'="`: display %7.0fc r(N)'" if _n==`j'+1 replace COEF`l'= subinstr(COEF`l'," ","",.) if _n==`j'+1 local l= `l'+1 } if mi("`cluster'")==0 { replace VAR="Clusters" if _n==`j'+2 duplicates report `cluster' replace N_ind="`: display %7.0fc r(unique_value)'" if _n==`j'+2 replace N_ind= subinstr(N_ind," ","",.) if _n==`j'+2 duplicates report `cluster' if `T0'==1 replace C="`: display %7.0fc r(unique_value)'" if _n==`j'+2 replace C= subinstr(C," ","",.) if _n==`j'+2 local l=1 foreach i in `treatment' { duplicates report `cluster' if `i'==1 replace COEF`l'="`: display %7.0fc r(unique_value)'" if _n==`j'+2 replace COEF`l'= subinstr(COEF`l'," ","",.) if _n==`j'+2 local l= `l'+1 } } } if mi("`if'")==0 { replace VAR="Observations" if _n==`j'+1 count `if' & `1'!=. replace N_ind="`: display %7.0fc r(N)'" if _n==`j'+1 replace N_ind= subinstr(N_ind," ","",.) if _n==`j'+1 count `if' & `T0'==1 replace C="`: display %7.0fc r(N)'" if _n==`j'+1 replace C= subinstr(C," ","",.) if _n==`j'+1 local l=1 foreach i in `treatment' { count `if' & `i'==1 replace COEF`l'="`: display %7.0fc r(N)'" if _n==`j'+1 replace COEF`l'= subinstr(COEF`l'," ","",.) if _n==`j'+1 local l= `l'+1 } if mi("`cluster'")==0 { replace VAR="Clusters" if _n==`j'+2 duplicates report `cluster' `if' replace N_ind="`: display %7.0fc r(unique_value)'" if _n==`j'+2 replace N_ind= subinstr(N_ind," ","",.) if _n==`j'+2 local l=1 foreach i in `treatment' { duplicates report `cluster' `if' & `i'==1 replace COEF`l'="`: display %7.0fc r(unique_value)'" if _n==`j'+2 replace COEF`l'= subinstr(COEF`l'," ","",.) if _n==`j'+2 local l= `l'+1 } duplicates report `cluster' `if' & `T0'==1 replace C="`: display %7.0fc r(unique_value)'" if _n==`j'+2 replace C= subinstr(C," ","",.) if _n==`j'+2 } } } * Saving in excel if mi("`using'")==0 & mi("`latex'") ==1 { if mi("`sheet'")==0 { gettoken worksheet option: sheet, parse(,) export excel VAR LAB N_ind N_clust A C COEF* `using', sheet(`worksheet' `option') first(var) } if mi("`sheet'")==1 { export excel VAR LAB N_ind N_clust A C COEF* `using', firstrow(var) replace } } end