*! synth2 2.1.0 Guanpeng Yan and Qiang Chen 05/10/2023 program synth2, eclass sortpreserve version 16 preserve qui xtset if "`r(panelvar)'" == "" | "`r(timevar)'" == "" { di as err "panel variable or time variable missing, please use -{bf:xtset} {it:panelvar} {it:timevar}" exit 198 } syntax anything, TRUnit(integer) TRPeriod(integer) /// [COUnit(numlist min = 1 int sort) /// CTRLUnit(numlist min = 1 int sort) /// PREPeriod(numlist min = 1 int sort) /// POSTPeriod(numlist min = 1 int sort) /// XPeriod(passthru) /// MSPEPeriod(passthru) /// CUStomV(passthru) /// nested /// allopt /// margin(passthru) /// maxiter(passthru) /// sigf(passthru) /// bound(passthru) /// placebo(string) /// loo /// frame(string) /// symbol(integer 1) /// SAVEGraph(string) /// noFIGure /// ] local panelVar "`r(panelvar)'" local timeVar "`r(timevar)'" cap synth if _rc== 199 { di as err `"{bf:synth} must be installed (use Stata command "{bf:ssc install synth, replace}")."' exit 198 } if "`ctrlunit'" != ""{ if "`counit'" == ""{ di as err `"The option {bf:ctrlunit()} is obsolete and replaced by the option {bf:counit()}, but continues to work just like the current option {bf:counit()}."' local counit "`ctrlunit'" } else{ di as err `"The options {bf:ctrlunit()} and {bf:counit()} can not be specified together, and the current option {bf:counit()} is recommended."' exit 198 } } /* Check frame */ if "`frame'" == "" tempname frame else { capture frame drop `frame' qui pwf if "`frame'" == "`r(currentframe)'" { di as err "invalid frame() -- current frame can not be specified" exit 198 } local framename "`frame'" } /* Check trunit */ qui levelsof `panelVar', local(unit_n) loc check: list trunit in unit_n if `check' == 0 { di as err "invalid trunit() -- treatment unit not found in {it:panelvar}" exit 198 } /* Check counit */ if "`counit'" != "" { loc check: list counit in unit_n if `check' == 0 { di as err "invalid counit() -- at least one control unit not found in {it:panelvar}" exit 198 } loc check: list trunit in counit if `check' == 1 { di as err "invalid counit() -- treatment unit appears among control units" exit 198 } foreach i in `unit_n'{ loc check: list i in counit if `check' == 0 & `i' != `trunit' qui drop if `panelVar' == `i' } } /* Check trperiod */ qui mata: synth2_levelsof("`timeVar'", "time_n") loc check: list trperiod in time_n if `check' == 0 { di as err "invalid trperiod() -- treatment period not found in {it:timelvar}" exit 198 } /* Check preperiod */ if "`preperiod'" != "" { qui mata: synth2_levelsofsel("`timeVar'", "time_pre", st_data(., "`timeVar'"):<`trperiod') loc check: list preperiod in time_pre if `check' == 0 { di as err "invalid preperiod() -- at least one of pretreatment periods that not found in {it:timevar} or not ahead of treatment period" exit 198 } foreach i in `time_pre'{ loc check: list i in preperiod if `check' == 0 qui drop if `timeVar' == `i' } } /* Check postperiod */ if "`postperiod'" != "" { qui mata: synth2_levelsofsel("`timeVar'", "time_post", st_data(., "`timeVar'") :>= `trperiod') loc check: list posof "`trperiod'" in postperiod if `check' != 1 { di as err "invalid postperiod() -- treatment period should be the first period of posttreatment periods" exit 198 } loc check: list postperiod in time_post if `check' == 0 { di as err "invalid postperiod() -- at least one of posttreatment periods not found in {it:timevar}" exit 198 } foreach i in `time_post'{ loc check: list i in postperiod if `check' == 0 qui drop if `timeVar' == `i' } } /* Check symbol */ if `symbol' == 1{ local sym "ยท" } else if `symbol' == 2{ local sym "_" } else { di as err "invalid symbol() -- symbol() should be specified {bf:1} or {bf:2}" exit 198 } gettoken depvar indepvars : anything local indepvars = strltrim("`indepvars'") qui ds mata: synth2_abstract("`anything'", "`r(varlist)'", "`depvar'") frame put `panelVar' `timeVar' `depvar' `covariates', into(`frame') local graphlist "" frame `frame'{ tempvar panelVarStr timeVarStr { capture decode `panelVar', gen(`panelVarStr') if _rc qui tostring `panelVar', gen(`panelVarStr') usedisplayformat force else qui replace `panelVarStr' = subinstr(`panelVarStr', " ", "", .) qui replace `panelVarStr' = strtoname(`panelVarStr', 0) } qui levelsof `panelVarStr', local(unit_all) clean qui levelsof `panelVarStr' if `panelVar' != `trunit', local(unit_ctrl) clean qui levelsof `panelVarStr' if `panelVar' == `trunit', local(unit_tr) clean qui tostring `timeVar', gen(`timeVarStr') usedisplayformat force mata: synth2_slevelsof("`timeVarStr'", "time_all") mata: synth2_slevelsofsel("`timeVarStr'", "time_pre", st_data(., "`timeVar'") :< `trperiod') mata: synth2_slevelsofsel("`timeVarStr'", "time_post", st_data(., "`timeVar'") :>= `trperiod') mata: synth2_slevelsofsel("`timeVarStr'", "time_tr", st_data(., "`timeVar'") :== `trperiod') } qui cap varabbrev synth `anything', trunit(`trunit') trperiod(`trperiod') `xperiod' `mspeperiod' `customV' `margin' `maxiter' `sigf' `bound' `nested' `allopt' if (_rc){ error _rc exit } matrix weight_vars = vecdiag(e(V_matrix))' matrix V_wt = e(V_matrix) matrix colname weight_vars = Weight frame `frame'{ capture gen pred`sym'`depvar' = . label variable pred`sym'`depvar' "prediction of `depvar' mata: synth2_insertMatrix("`panelVar'", "`timeVar'", `trunit', st_matrix("e(Y_synthetic)"), "pred`sym'`depvar'") capture gen tr`sym'`depvar' = `depvar' - pred`sym'`depvar' label variable tr`sym'`depvar' "treatment effect on `depvar'" di as txt "Fitting results in the pretreatment periods:" mata: synth2_sum("`panelVar'", "`timeVar'", `trunit', `trperiod', "`unit_tr'", "`time_tr'", cols(tokens("`unit_ctrl'")), /// cols(tokens("`indepvars'")), st_data(., "pred`sym'`depvar'"), st_data(., "tr`sym'`depvar'"), 0, .) matrix balance = e(X_balance), J(rowsof(e(X_balance)), 1 ,.) matrix colnames balance = Treated Synthetic Control } if "`preperiod'" == "" qui mata: synth2_levelsofsel("`timeVar'", "preperiod", st_data(., "`timeVar'") :< `trperiod') synth2_balance `indepvars', panelVar(`panelVar') timeVar(`timeVar') trunit(`trunit') `xperiod' preperiod(`preperiod') frame(`frame') matrix coljoinbyname balance = weight_vars balance mata: temp = st_matrixrowstripe("balance"); /// st_matrix("balance", (st_matrix("balance")[., 1..2], st_matrix("balance")[.,3], ((st_matrix("balance")[.,3] :/ st_matrix("balance")[.,2]) :- 1) :* 100, st_matrix("balance")[.,4], ((st_matrix("balance")[.,4] :/ st_matrix("balance")[.,2]) :- 1) :* 100)); /// st_matrixrowstripe("balance", temp); mata: st_matrixcolstripe("balance", (J(6, 1, ""), ("Vweight", "Treated", "ValueSyntheticControl", "BiasSyntheticControl", "ValueAverageControl", "BiasAverageControl")')) tempname balanceFrame cap frame create `balanceFrame' frame `balanceFrame'{ qui svmat balance, name(col) mata: st_sstore(., st_addvar("strL", "variable"), st_matrixrowstripe("balance")[., 2]) cap replace BiasSyntheticControl = BiasSyntheticControl cap replace BiasAverageControl = BiasAverageControl graph dot (asis) BiasAverageControl BiasSyntheticControl, over(variable) yline(0, lcolor(gs10)) marker(1, /// msymbol(O)) marker(2, msymbol(X)) ytitle("Standardized % Bias across Covariates") /// legend(lab(2 "Synthetic Control") lab(1 "Average Control")) name(bias, replace) title("Covariate Balance") nodraw //legend(pos(5) ring(0) lab(1 "Control") lab(2 "Synthetic")) name(bias, replace) nodraw local graphlist = "`graphlist' bias" } di _newline "{p 0 0 2}{txt}Covariate balance in the pretreatment periods:{p_end}" mata: synth2_print4(st_matrixrowstripe("balance")[., 2], ("Covariate", "V.weight", "Treated ", "Value ", "Bias", "Value ", "Bias "), /// (" Synthetic Control", " Average Control"), st_matrix("balance"), ., 0, (8, 10, 10, 7, 10, 7), 0, 0) di `"{p 0 6 2}{txt}Note: "V.weight" is the optimal covariate weight in the diagonal of V matrix.{p_end}"' di `"{p 6 6 2}{txt}"Synthetic Control" is the weighted average of donor units with optimal weights.{p_end}"' di `"{p 6 6 2}{txt}"Average Control" is the simple average of all control units with equal weights.{p_end}"' di tempname weightVarsFrame cap frame create `weightVarsFrame' frame `weightVarsFrame'{ qui svmat weight_vars, name(col) mata: st_sstore(., st_addvar("strL", "variable"), st_matrixrowstripe("weight_vars")[., 2]) qui sum Weight qui local ymax= r(max)*1.1 graph hbar (asis) Weight, over(variable, sort(Weight) descending) ytitle(weight) name(weight_vars, replace) blabel(total, format(%9.4f)) ysc(r(0 `ymax')) title(Optimal Covariate Weights) nodraw local graphlist = "`graphlist' weight_vars" } di "{p 0 6 2}{txt}Optimal Unit Weights:{p_end}" frame `frame'{ mata: synth2_weight("e(W_weights)") } tempname weightUnitFrame cap frame create `weightUnitFrame' frame `weightUnitFrame'{ qui svmat weight_unit, name(col) mata: st_sstore(., st_addvar("strL", "unit"), st_matrixrowstripe("weight_unit")[., 2]) qui sum Weight qui local ymax= r(max)*1.1 graph hbar (asis) Weight, over(unit, sort(Weight) descending) ytitle(weight) name(weight_unit, replace) title(Optimal Unit Weights) blabel(total, format(%9.4f)) ysc(r(0 `ymax')) nodraw local graphlist = "`graphlist' weight_unit" } di frame `frame'{ di _newline as txt "Prediction results in the posttreatment periods:" mata: synth2_print(st_sdata(., "`timeVarStr'"), ("Time", "Actual Outcome", " Synthetic Outcome", " Treatment Effect"), /// st_data(., "`depvar' pred`sym'`depvar' tr`sym'`depvar'"), /// selectindex((st_data(., "`panelVar'") :== `trunit') :& (st_data(., "`timeVar'") :>= `trperiod')), 1, (13, 17, 16), 0, 0, 1) if("`figure'" == ""){ qui mata: synth2_levelsof("`timeVar'", "temp") loc pos: list posof "`trperiod'" in temp loc pos = `pos' - 1 loc xline: word `pos' of `temp' twoway (line `depvar' `timeVar') (line pred`sym'`depvar' `timeVar', lpattern(dash)) if `panelVar' == `trunit', /// title("Actual and Synthetic Outcomes") xline(`xline', lp(dot) lc(black)) name(pred, replace) /// ytitle(`depvar') legend(order(1 "Actual" 2 "Synthetic")) nodraw line tr`sym'`depvar' `timeVar', xline(`xline', lp(dot) lc(black)) yline(0, lp(dot) lc(black)) /// title("Treatment Effects") name(eff, replace) /// ytitle("treatment effects on `depvar'") nodraw local graphlist = "`graphlist' pred eff" } } /* Implement the placebo test using fake unit and/or time */ if "`placebo'" != "" { ereturn local trperiod "`trperiod'" ereturn local trunit "`trunit'" if(strpos("`placebo'", "unit") != 0 & strpos("`placebo'", "unit(") == 0) local placebo = subinstr("`placebo'", "unit", "unit(.)", .) synth2_placebo `anything', trunit(`trunit') trperiod(`trperiod') /// panelVar(`panelVar') timeVar(`timeVar') panelVarStr(`panelVarStr') timeVarStr(`timeVarStr') /// unit_all(`unit_all') unit_tr(`unit_tr') unit_ctrl(`unit_ctrl') time_tr(`time_tr') time_all(`time_all') /// frame(`frame') sym("`sym'") `xperiod' `mspeperiod' `placebo' `figure' `nested' `allopt' `margin' `maxiter' `sigf' `bound' local graphlist = "`graphlist' `e(graphlist)'" capture mat pval = e(pval) } /* Implement Robustness Test */ if("`loo'" != ""){ di _newline as txt "Implementing leave-one-out robustness test that excludes one control unit with a nonzero weight " _continue local linePred "" local lineEff "" foreach loounit in `loounitlist'{ frame `frame': qui levelsof `panelVarStr' if `panelVar' == `loounit', local(unit_loo) clean di as res "`unit_loo'" as txt "..." _continue qui levelsof `panelVar' if (`panelVar' != `trunit') & (`panelVar' != `loounit'), local(remunitlist) qui cap varabbrev synth `anything', trunit(`trunit') trperiod(`trperiod') counit(`remunitlist') `xperiod' `mspeperiod' `customV' `margin' `maxiter' `sigf' `bound' `nested' `allopt' if(_rc){ error _rc exit } frame `frame'{ qui cap gen pred`sym'`depvar'`sym'rmv`unit_loo' = . qui label variable pred`sym'`depvar'`sym'rmv`unit_loo' "prediction of `depvar' (`unit_loo' excluded) generated by 'robustness test'" mata: synth2_insertMatrix("`panelVar'", "`timeVar'", `trunit', st_matrix("e(Y_synthetic)"), "pred`sym'`depvar'`sym'rmv`unit_loo'") qui cap gen tr`sym'`depvar'`sym'rmv`unit_loo' = `depvar' - pred`sym'`depvar'`sym'rmv`unit_loo' qui label variable tr`sym'`depvar'`sym'rmv`unit_loo' "treatment effect on `depvar' (`unit_loo' excluded) generated by 'robustness test'" local linePred " `linePred' (line pred`sym'`depvar'`sym'rmv`unit_loo' `timeVar', lc(gs8%20) lp(solid)) " local lineEff " `lineEff' (line tr`sym'`depvar'`sym'rmv`unit_loo' `timeVar', lc(gs8%20) lp(solid)) " } } di _newline _newline as txt "Leave-one-out robustness test results in the posttreatment period:" frame `frame'{ mata: st_store(., (st_addvar("float", "pred`sym'`depvar'`sym'loomin"), st_addvar("float", "pred`sym'`depvar'`sym'loomax")), /// rowminmax(st_data(., ("pred`sym'`depvar'`sym'rmv" :+ tokens("`unit_loolist'"))))) qui label variable pred`sym'`depvar'`sym'loomin "min prediction of `depvar' generated by 'robustness test'" qui label variable pred`sym'`depvar'`sym'loomax "max prediction of `depvar' generated by 'robustness test'" mata: st_store(., (st_addvar("float", "tr`sym'`depvar'`sym'loomin"), st_addvar("float", "tr`sym'`depvar'`sym'loomax")), /// rowminmax(st_data(., ("tr`sym'`depvar'`sym'rmv" :+ tokens("`unit_loolist'"))))) qui label variable tr`sym'`depvar'`sym'loomin "min treatment effect on `depvar' generated by 'robustness test'" qui label variable tr`sym'`depvar'`sym'loomax "max treatment effect on `depvar' generated by 'robustness test'" mata: synth2_print3(st_sdata(., "`timeVarStr'"), ("Time", "Actual ", "Synthetic ", "Min ", "Max "), ("Outcome", "Synthetic Outcome (LOO)"), st_data(., "`depvar' pred`sym'`depvar' pred`sym'`depvar'`sym'loomin pred`sym'`depvar'`sym'loomax"), selectindex((st_data(., "`panelVar'") :== `trunit') :& (st_data(., "`timeVar'") :>= `trperiod')), 0, (10, 10, 10, 10), 0, 0) di "{p 0 6 2}{txt}Note: The last two columns report the minimum and maximum synthetic outcomes when one control unit with a nonzero weight is excluded at a time.{p_end}" di mata: synth2_print2(st_sdata(., "`timeVarStr'"), ("Time", "Treatment Effect", "Min ", "Max "), "Treatment Effect (LOO)", st_data(., "tr`sym'`depvar' tr`sym'`depvar'`sym'loomin tr`sym'`depvar'`sym'loomax"), selectindex((st_data(., "`panelVar'") :== `trunit') :& (st_data(., "`timeVar'") :>= `trperiod')), 0, (18, 12, 12), 0, 0) di "{p 0 6 2}{txt}Note: The last two columns report the minimum and maximum treatment effects when one control unit with a nonzero weight is excluded at a time.{p_end}" } if "`figure'" == ""{ frame `frame'{ qui mata: synth2_levelsof("`timeVar'", "temp") loc pos: list posof "`trperiod'" in temp loc pos = `pos' - 1 loc xline: word `pos' of `temp' twoway (line `depvar' `timeVar', lp(solid)) (line pred`sym'`depvar' `timeVar', lp(dash)) `linePred' /// if `panelVar' == `trunit', xline(`xline', lp(dot) lc(black)) title("Leave-one-out Robustness Test") /// legend(order(1 "Actual" 2 "Synthetic" 3 "Synthetic (LOO)") rows(1)) /// name(pred_loo, replace) ytitle(`depvar') nodraw twoway (line tr`sym'`depvar' `timeVar', lp(solid)) `lineEff' if `panelVar' == `trunit', /// xline(`xline', lp(dot) lc(black)) yline(0, lp(dot) lc(black)) /// title("Leave-one-out Robustness Test") name(eff_loo, replace) /// ytitle("treatment effects on `depvar'") /// legend(order(1 "Treatment Effect" 2 "Treatment Effect (LOO)")) nodraw local graphlist = "`graphlist' pred_loo eff_loo" } } } /* Display graphs */ if "`figure'" == "" { if "`savegraph'" == "" foreach graph in `graphlist'{ capture graph display `graph' } else{ di ereturn local graphlist "`graphlist'" synth2_savegraph `savegraph' } } ereturn clear capture ereturn matrix pval = pval capture if rowsof(mspe) > 1 ereturn matrix mspe = mspe ereturn matrix bal = balance ereturn matrix U_wt= weight_unit ereturn matrix V_wt = V_wt capture ereturn local graph "`graphlist'" ereturn local frame "`framename'" ereturn local time_post "`time_post'" ereturn local time_pre "`time_pre'" ereturn local time_tr "`time_tr'" ereturn local time_all "`time_all'" ereturn local unit_ctrl "`unit_ctrl'" ereturn local unit_tr "`unit_tr'" ereturn local unit_all "`unit_all'" ereturn local indepvars "`indepvars'" ereturn local depvar "`depvar'" ereturn local varlist "`anything'" ereturn local timevar "`timeVar'" ereturn local panelvar "`panelVar'" ereturn scalar N = _N ereturn scalar T = wordcount("`time_all'") ereturn scalar T0 = wordcount("`time_pre'") ereturn scalar T1 = wordcount("`time_post'") ereturn scalar K = wordcount("`indepvars'") ereturn scalar J = wordcount("`unit_all'") ereturn scalar rmse = rmse ereturn scalar r2 = r2 ereturn scalar att = att di _newline as txt "Finished." end program synth2_savegraph version 16 preserve syntax [anything], [asis replace] foreach graph in `e(graphlist)'{ capture graph display `graph' graph save `anything'_`graph', `asis' `replace' } end program synth2_placebo, eclass sortpreserve version 16 preserve local trperiod = `e(trperiod)' local trunit = `e(trunit)' syntax anything, trunit(numlist) trperiod(numlist) [panelVar(string) timeVar(string) panelVarStr(string) timeVarStr(string) /// unit_all(string) unit_tr(string) unit_ctrl(string) /// time_all(string) time_tr(string) frame(string) /// xperiod(passthru) /// mspeperiod(passthru) /// customV(passthru) /// margin(passthru) /// maxiter(passthru) /// sigf(passthru) /// bound(passthru) /// sym(string) /// unit(numlist missingokay) period(numlist min = 1 int sort <`trperiod') Cutoff(numlist min = 1 max = 1 >=1) /// show(numlist min = 1 max = 1 >=1) noFIGure nested allopt] gettoken depvar indepvars : anything local graphlist "" if("`unit'" != "."){ local unit_pboList "" frame `frame'{ foreach i in `unit'{ qui levelsof `panelVarStr' if `panelVar' == `i', local(temp) clean local unit_pboList "`unit_pboList' `temp'" } } } else local unit_pboList "`unit_ctrl'" qui mata: synth2_levelsof("`timeVar'", "temp") loc pos: list posof "`trperiod'" in temp loc pos = `pos' - 1 loc xline: word `pos' of `temp' if("`unit'" != ""){ di _newline as txt "Implementing placebo test using fake treatment unit " _continue local tsline "" local unit_pboSel "" local unit_pboRmv "" foreach unit_pbo in `unit_pboList'{ di as res "`unit_pbo'" as txt "..." _continue qui frame `frame': levelsof `panelVar' if `panelVarStr' == "`unit_pbo'", local(pbounit) clean qui cap varabbrev synth `anything', trunit(`pbounit') trperiod(`trperiod') `xperiod' `mspeperiod' `customV' `margin' `maxiter' `sigf' `bound' `nested' `allopt' if _rc { error _rc exit } frame `frame'{ capture gen pred`sym'`depvar' = . mata: synth2_insertMatrix("`panelVar'", "`timeVar'", `pbounit', st_matrix("e(Y_synthetic)"), "pred`sym'`depvar'") qui replace tr`sym'`depvar' = `depvar'- pred`sym'`depvar' if `panelVar' == `pbounit' mata: synth2_sum("`panelVar'", "`timeVar'", `pbounit', `trperiod', "`unit_tr'", "`time_tr'", ., ., st_data(., "pred`sym'`depvar'"), /// st_data(., "tr`sym'`depvar'"), 1, ("`cutoff'" == "" ? . : strtoreal("`cutoff'"))) if(`isRmv' == 0){ local unit_pboSel "`unit_pboSel' `unit_pbo'" local line " `line' (tsline tr`sym'`depvar' if `panelVar' == `pbounit', lp(solid) lc(gs8%20)) " } else local unit_pboRmv "`unit_pboRmv' `unit_pbo'" } } matrix colnames mspe = PreMSPE PostMSPE RatioPostPre RatioTrCtrl matrix rownames mspe = `unit_tr' `unit_pboList' di _newline _newline as txt "In-space placebo test results using fake treatment units:" mata: synth2_print(tokens("`unit_tr' `unit_pboList'")', ("Unit", "Pre MSPE ", " Post MSPE ", "Post/Pre MSPE", " Pre MSPE of Fake Unit/Pre MSPE of Treated Unit"), st_matrix("mspe"), ., 0, (9, 9, 13, 24), 0, 0, 0) if "`unit_pboRmv'" != "" { mata: printf(stritrim(sprintf( /// "{p 0 6 2}{txt}Note: (1) Using all control units, the probability of obtaining a post/pretreatment MSPE ratio as large as {res}`unit_tr'{txt}'s is{res}%10.4f{txt}.{p_end}\n", mean((st_matrix("mspe")[1, 3] :<= st_matrix("mspe")[. , 3]))))) mata: printf(stritrim(sprintf( /// "{p 6 6 2}{txt}(2) Excluding control units with pretreatment MSPE {res}`cutoff'{txt} times larger than the treated unit, the probability of obtaining a post/pretreatment MSPE ratio as large as {res}`unit_tr'{txt}'s is {res}%10.4f{txt}.{p_end}\n", mean((st_matrix("mspe_cut")[1, 3] :<= st_matrix("mspe_cut")[. , 3]))))) di "{p 6 6 2}{txt}(3) The pointwise p-values below are computed by excluding control units with pretreatment MSPE {res}`cutoff'{txt} times larger than the treated unit.{p_end}" di "{p 6 6 2}{txt}(4) There are total{res}", wordcount("`unit_pboRmv'"), "{txt}units with pretreatment MSPE {res}`cutoff'{txt} times larger than the treated unit, including {res}`unit_pboRmv'{txt}.{p_end}" } else mata: printf(stritrim(sprintf( /// "{p 0 6 2}{txt}Note: The probability of obtaining a post/pretreatment MSPE ratio as large as {res}`unit_tr'{txt}'s is{res}%10.4f{txt}.{p_end}\n", mean((st_matrix("mspe")[1, 3] :<= st_matrix("mspe")[. , 3]))))) mata: printf("\n{txt}In-space placebo test results using fake treatment units (continued" + /// ("`cutoff'" == "" ? "" : (", cutoff = {res}`cutoff'")) + "{txt}):\n") frame `frame'{ mata: synth2_placebo(st_data(., "`timeVar'"), st_sdata(., "`panelVarStr'"), st_sdata(., "`timeVarStr'"), "`unit_tr'", "`unit_pboSel'", `trperiod', st_data(., "tr`sym'`depvar'")) di "{p 0 6 2}{txt}Note: (1) The two-sided p-value of the treatment effect for a particular period is defined as the frequency that the absolute values of the placebo effects are greater than or equal to the absolute value of treatment effect.{p_end}" di "{p 6 6 2}{txt}(2) The right-sided (left-sided) p-value of the treatment effect for a particular period is defined as the frequency that the placebo effects are greater (smaller) than or equal to the treatment effect.{p_end}" di "{p 6 6 2}{txt}(3) If the estimated treatment effect is positive, then the right-sided p-value is recommended; whereas the left-sided p-value is recommended if the estimated treatment effect is negative.{p_end}" label variable pvalTwo "two-sided p-value of treatment effect generated by 'placebo unit'" label variable pvalRight "right-sided p-value of treatment effect generated by 'placebo unit'" label variable pvalLeft "left-sided p-value of treatment effect generated by 'placebo unit'" } if "`figure'" == ""{ frame `frame'{ qui local num = wordcount("`unit_pboSel'") + 1 twoway `line' (tsline tr`sym'`depvar' if `panelVar' == `trunit', lp(solid)) , /// xline(`xline', lp(dot) lc(black)) yline(0, lp(dot) lc(black)) /// title("In-space Placebo Test") name(eff_pboUnit, replace) /// ytitle("treatment/placebo effects on `depvar'") /// legend(order(`num' "Treatment Effect" 2 "Placebo Effect")) nodraw local graphlist = "`graphlist' eff_pboUnit" } tempname placeboUnitframe frame create `placeboUnitframe' frame `placeboUnitframe'{ qui svmat mspe, name(col) mata: st_sstore(., st_addvar("strL", "unit"), tokens("`unit_tr' `unit_pboList'")') if ("`show'" != "") { qui gsort -RatioPostPre qui drop if _n >`show' } graph hbar (asis) RatioPostPre, over(unit, sort(RatioPostPre) descending label(labsize(vsmall))) /// ytitle("Ratios of posttreatment MSPE to pretreatment MSPE") /// title("In-space Placebo Test") name("ratio_pboUnit", replace) nodraw } local graphlist = "`graphlist' ratio_pboUnit" frame `frame'{ twoway connected pvalTwo `timeVar' if `panelVar' == `trunit' & `timeVar' >= `trperiod', /// ytitle("two-sided p-values of treatment effects on `depvar'") /// yline(0.05 0.1, lp(dot) lc(black)) ylabel(0(0.1)1) /// title("In-space Placebo Test") name(pvalTwo_pboUnit, replace) nodraw twoway connected pvalRight `timeVar' if `panelVar' == `trunit' & `timeVar' >= `trperiod', /// ytitle("right-sided p-values of treatment effects on `depvar'") /// yline(0.05 0.1, lp(dot) lc(black)) ylabel(0(0.1)1) /// title("In-space Placebo Test") name(pvalRight_pboUnit, replace) nodraw twoway connected pvalLeft `timeVar' if `panelVar' == `trunit' & `timeVar' >= `trperiod', /// ytitle("left-sided p-values of treatment effects on `depvar'") /// yline(0.05 0.1, lp(dot) lc(black)) ylabel(0(0.1)1) /// title("In-space Placebo Test") name(pvalLeft_pboUnit, replace) nodraw local graphlist = "`graphlist' pvalTwo_pboUnit pvalRight_pboUnit pvalLeft_pboUnit" } } } if("`period'" != ""){ di _newline as txt "Implementing placebo test using fake treatment time " _continue foreach pboperiod in `period'{ qui mata: synth2_levelsof("`timeVar'", "time_n") loc check: list pboperiod in time_n if `check' == 0 { di _newline as err "placebo() invalid -- invalid fake period `pboperiod'" exit 198 } frame `frame': qui levelsof `timeVarStr' if `timeVar' == `pboperiod', local(time_pbo) clean loc pos: list posof "`pboperiod'" in temp loc pos = `pos' - 1 loc xlinePbo: word `pos' of `temp' di as res "`time_pbo'" as txt "..." _continue qui cap varabbrev synth `anything', trunit(`trunit') trperiod(`pboperiod') `xperiod' `mspeperiod' `customV' `margin' `maxiter' `sigf' `bound' `nested' `allopt' if _rc { error _rc exit } frame `frame'{ loc pboTimeVar = strtoname("`depvar'`sym'`time_pbo'") capture gen pred`sym'`pboTimeVar' = . mata: synth2_insertMatrix("`panelVar'", "`timeVar'", `trunit', st_matrix("e(Y_synthetic)"), "pred`sym'`pboTimeVar'") capture gen tr`sym'`pboTimeVar' = `depvar' - pred`sym'`pboTimeVar' label variable pred`sym'`pboTimeVar' "prediction of `depvar' generated by 'placebo period `time_pbo''" label variable tr`sym'`pboTimeVar' "treatment effect on `depvar' generated by 'placebo period `time_pbo''" if "`figure'" == "" { twoway (line `depvar' `timeVar' if `panelVar' == `trunit') /// (line pred`sym'`pboTimeVar' `timeVar' if `panelVar' == `trunit', lpattern(dash)), /// title("In-time Placebo Test (fake treatment time = `time_pbo')") xline(`xline' `xlinePbo', lp(dot) lc(black)) /// name(pred_pboTime`pboperiod', replace) ytitle(`depvar') /// legend(order(1 "Actual" 2 "Synthetic")) nodraw local graphlist = "`graphlist' pred_pboTime`pboperiod'" line tr`sym'`pboTimeVar' `timeVar' if `panelVar' == `trunit', /// xline(`xline' `xlinePbo', lp(dot) lc(black)) yline(0, lp(dot) lc(black)) /// title("In-time Placebo Test (fake treatment time = `time_pbo')") name(eff_pboTime`pboperiod', replace) /// ytitle("placebo effects on `depvar'") nodraw local graphlist = "`graphlist' eff_pboTime`pboperiod'" } } } di foreach pboperiod in `period'{ frame `frame': qui levelsof `timeVarStr' if `timeVar' == `pboperiod', local(time_pbo) clean loc pboTimeVar = strtoname("`depvar'`sym'`pboperiod'") di _newline as txt "In-time placebo test results using fake treatment time " as res "`time_pbo'" as txt":" frame `frame': mata: synth2_print(st_sdata(., "`timeVarStr'"), ("Time", "Actual Outcome", " Synthetic Outcome", " Treatment Effect"), /// st_data(., "`depvar' pred`sym'`pboTimeVar' tr`sym'`pboTimeVar'"), /// selectindex((st_data(., "`panelVar'") :== `trunit') :& (st_data(., "`timeVar'") :>= `pboperiod')), 1, (13, 17, 16), 0, 0, 0) } } capture ereturn matrix pval = pval ereturn local graphlist "`graphlist'" end **# Balance program synth2_balance version 16 preserve syntax anything, panelVar(string) timeVar(string) trunit(integer) preperiod(numlist) [xperiod(numlist)] frame(string) if "`xperiod'" == "" mata: st_local("ifperiod", "(" + invtokens("`timeVar' == " :+ tokens("`preperiod'"), " | ") + ")") else mata: st_local("ifperiod", "(" + invtokens("`timeVar' == " :+ tokens("`xperiod'"), " | ") + ")") foreach var of local anything{ local period "" local rownumb = rownumb(balance,"`var'") if(strpos("`var'","(") > 0){ local period = substr("`var'", strpos("`var'", "(") + 1, strlen("`var'") - strpos("`var'","(") - 1) local period = subinstr("`period'", "&", " ", .) qui numlist "`period'" local period "`r(numlist)'" local var = substr("`var'", 1, strpos("`var'","(") - 1) } if("`period'" == "") local period "`ifperiod'" else mata: st_local("period", "(" + invtokens("`timeVar' == " :+ tokens("`period'"), " | ") + ")") cap qui sum `var' if `period' & `panelVar' != `trunit' matrix balance[`rownumb', 3] = r(mean) } end version 16 mata: real matrix synth2_uniqrows(real matrix m){ tmp = J(0, 1, .) for(i = 1;i<=rows(m); i++){ if(i == 1) tmp = tmp\m[i,.] else{ if(sum(tmp:==m[i,.])==0) tmp = tmp\m[i,.] } } return(tmp) } string matrix synth2_suniqrows(string matrix m){ tmp = J(0, 1, "") for(i = 1;i<=rows(m); i++){ if(i == 1) tmp = tmp\m[i,.] else{ if(sum(tmp:==m[i,.])==0) tmp = tmp\m[i,.] } } return(tmp) } void synth2_levelsof(string scalar varname, string scalar localname){ st_local(localname, "") tmp = synth2_uniqrows(st_data(., varname)); for(i=1; i<=rows(tmp);i++) st_local(localname, st_local(localname) + (i==1?"":" ")+ strofreal(tmp[i])) } void synth2_levelsofsel(string scalar varname, string scalar localname, real matrix selvar){ st_local(localname, "") tmp = synth2_uniqrows(st_data(selectindex(selvar), varname)); for(i=1; i<=rows(tmp);i++) st_local(localname, st_local(localname) + (i==1?"":" ")+ strofreal(tmp[i])) } void synth2_slevelsof(string scalar varname, string scalar localname){ st_local(localname, "") tmp = synth2_suniqrows(st_sdata(., varname)); for(i=1; i<=rows(tmp); i++) st_local(localname, st_local(localname) + (i==1?"":" ") + tmp[i]) } void synth2_slevelsofsel(string scalar varname, string scalar localname, real matrix selvar){ st_local(localname, "") tmp = synth2_suniqrows(st_sdata(selectindex(selvar), varname)); for(i=1; i<=rows(tmp);i++) st_local(localname, st_local(localname) + (i==1?"":" ")+ tmp[i]) } void synth2_abstract(string scalar anything, string scalar varlist, string scalar depvar){ anything = tokens(usubinstr(usubinstr(anything, "(", " ", .), ")", " ", .)) covariates = "" for(i = 1; i <= cols(anything); i++){ if((sum(anything[i] :== tokens(varlist)) > 0) & (anything[i] != depvar)) covariates = covariates + " " + anything[i] } st_local("covariates", invtokens(uniqrows(tokens(covariates)')')) } void synth2_insertMatrix(string scalar panelVar, string scalar timeVar, real scalar unit_tr, real matrix M, string scalar insertVar){ real matrix data st_view(data, ., invtokens((panelVar, timeVar, invtokens(insertVar)))) data[selectindex(data[., 1] :== unit_tr), 3..cols(data)] = M } void synth2_sum(string scalar panelVar, string scalar timeVar, real scalar trunit, real scalar trperiod, string scalar unit_tr, string scalar time_tr, real scalar J, real scalar K, real matrix respo, real matrix effect, real scalar isplacebo, real scalar cut){ indexPre = selectindex((st_data(., timeVar) :< trperiod) :& (st_data(., panelVar) :== trunit)) indexPost = selectindex((st_data(., timeVar) :>= trperiod) :& (st_data(., panelVar) :== trunit)) // MSPE_pre = mean(effect[indexPre, .] :^ 2) MSPE_pre = st_matrix("e(RMSPE)")^2 MSPE_post = mean(effect[indexPost, .] :^ 2) // MSE = MSPE_pre MSE = st_matrix("e(RMSPE)")^2 // RMSE = sqrt(MSE) RMSE = st_matrix("e(RMSPE)") MAE = mean(abs(effect[indexPre, .])) R2 = 1 - sum(effect[indexPre, .] :^ 2)/sum((respo[indexPre, .] :- mean(respo[indexPre, .])):^ 2) if(isplacebo == 0){ wide = 3 printf("{hline " + strofreal(wide + 77) + "}\n") printf(" {txt}%-24uds : {res}%10uds {space "+ strofreal(wide) + "} {txt}%-24uds : {res}%10uds\n", "Treated Unit", abbrev(unit_tr, 10), "Treatment Time", abbrev(time_tr, 10)) printf("{hline " + strofreal(wide + 77) + "}\n") printf(" {txt}%-24uds = {res}%9.0f {space "+ strofreal(wide) + "} {txt}%-24uds = {res}%9.5f\n", "Number of Control Units", J, "Root Mean Squared Error", RMSE) printf(" {txt}%-24uds = {res}%9.0f {space "+ strofreal(wide) + "} {txt}%-24uds = {res}%9.5f\n", "Number of Covariates", K, "R-squared", R2) printf("{hline " + strofreal(wide + 77) + "}\n") st_numscalar("mse", MSE) st_numscalar("mae", MAE) st_numscalar("rmse", RMSE) st_numscalar("r2", R2) st_matrix("mspe", (MSPE_pre, MSPE_post, MSPE_post/MSPE_pre, 1)) st_matrix("mspe_cut", (MSPE_pre, MSPE_post, MSPE_post/MSPE_pre, 1)) } else{ ratio = MSPE_pre/st_matrix("mspe")[1, 1] st_matrix("mspe", st_matrix("mspe")\(MSPE_pre, MSPE_post, MSPE_post/MSPE_pre, ratio)) if((cut == .) | (ratio <= cut)) { st_local("isRmv", "0") st_matrix("mspe_cut", st_matrix("mspe_cut")\(MSPE_pre, MSPE_post, MSPE_post/MSPE_pre, ratio)) } else st_local("isRmv", "1") } } void synth2_weight(string scalar name){ rownames = st_matrixrowstripe(name)[., 2] M = st_matrix(name)[., .] delRownames = rownames[selectindex(M[., 2] :== 0), .]' rownames = rownames[selectindex(M[., 2] :> 0), .] M = M[selectindex(M[., 2] :> 0), .] M = sort(((1..rows(M))', M), -3) rownames = rownames[M[., 1], .] st_local("loounitlist", invtokens(strofreal(M[., 2]'))) st_local("unit_loolist", invtokens(rownames')) M = M[., 3] st_matrix("weight_unit", M) st_matrixcolstripe("weight_unit", ("", "Weight")) st_matrixrowstripe("weight_unit", (J(rows(M), 1, ""), rownames)) synth2_print(rownames, ("Unit", "U.weight"), M, ., 0, 10, 0, 0, 0) if(cols(delRownames) > 0) printf("{p 0 6 2}{txt}Note: The unit {res}" + invtokens(delRownames) /// + "{txt} in the donor pool " + (cols(delRownames) > 1? "get" : "gets") + " a weight of {res}0{txt}.\n") } void synth2_print(string matrix rownames, string matrix colnames, real matrix M, real matrix indexRow, real scalar isMean, real matrix wideM, real scalar extend, real scalar isInt, real scalar att){ if (rows(indexRow) != 1){ rownames = rownames[indexRow, .] M = M[indexRow, .] } wide = max(udstrlen((rownames[1..rows(rownames),1]\colnames[1]))) printf(sprintf("{hline %g}{c TT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) printf(sprintf(" {txt}%%~%guds {c |}", wide), colnames[1]) for(j = 2; j <= cols(colnames); j++){ if(j == cols(colnames) & (udstrlen(colnames[j]) > wideM[j - 1] + 2)){ printf(sprintf("%%%guds\n", wideM[j - 1] + 2), substr(colnames[j], 1, wideM[j - 1])) printf(" {space %g} {c |}", wide) for(k = 2; k <= cols(colnames); k++){ if(k != cols(colnames)){ printf("{space %g}", wideM[k - 1] + 2) } else printf(sprintf("%%%guds", wideM[k - 1] + 2), substr(colnames[k], wideM[k - 1] +1)) } } else printf(sprintf("%%%guds", wideM[j - 1] + 2), colnames[j]) } printf(sprintf("\n{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) for(i = 1; i <= rows(M); i++){ printf(sprintf(" {txt}%%%guds {c |}{res}", wide), rownames[i]) for(j = 1; j <= cols(M); j++){ if(isInt == 0) printf(sprintf(" %%%g.4f ", wideM[j]), M[i,j]) else printf(sprintf(" %%%g.0g ", wideM[j]), M[i,j]) } printf("\n") } if(isMean == 1){ printf(sprintf("{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) meanM = mean(M[1..rows(M), .]) printf(sprintf(" {txt}%%~%guds {c |}{res}", wide), "Mean") for(j = 1; j <= cols(M); j++){ printf(sprintf(" %%%g.4f ", wideM[j]), meanM[., j]) } printf("\n") }else if(isMean == 2){ printf(sprintf("{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) sumM = sum(M[1..rows(M), .]) printf(sprintf(" {txt}%%~%guds {c |}{res}", wide), "Sum") for(j = 1; j <= cols(M); j++){ printf(sprintf(" %%%g.4f ", wideM[j]), sumM[., j]) } printf("\n") } printf(sprintf("{hline %g}{c BT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) if(isMean == 1){ printf(stritrim(sprintf("{p 0 6 2}{txt}Note: The average treatment effect over the posttreatment period is{res} %10.4f{txt}.\n", meanM[., 3]))) if(att == 1) st_numscalar("att", meanM[., 3]) } } void synth2_print2(string matrix rownames, string matrix colnames, string scalar colname, real matrix M, real matrix indexRow, real scalar isMean, real matrix wideM, real scalar extend, real scalar isInt){ if (rows(indexRow) != 1){ rownames = rownames[indexRow, .] M = M[indexRow, .] } wide = max(udstrlen((rownames[1..rows(rownames),1]\colnames[1]))) printf(sprintf("{hline %g}{c TT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) printf(sprintf(" {txt}%%~%guds {c |}", wide), colnames[1]) printf(sprintf("{txt}%%%guds", wideM[1] + 2), colnames[2]) printf(sprintf("{txt}%%~%guds\n", sum(wideM[2..cols(wideM)]) + 2*(cols(wideM)-1)), colname) printf(sprintf("{space %g}{c |}", wide + 2)) for(j = 2; j <= cols(colnames); j++){ if(j == cols(colnames) & (udstrlen(colnames[j]) > wideM[j - 1] + 2)){ printf(sprintf("%%%guds\n", wideM[j - 1] + 2), substr(colnames[j], 1, wideM[j - 1])) printf(" {space %g} {c |}", wide) for(k = 2; k <= cols(colnames); k++){ if(k != cols(colnames)){ printf("{space %g}", wideM[k - 1] + 2) } else printf(sprintf("%%%guds", wideM[k - 1] + 2), substr(colnames[k], wideM[k - 1] +1)) } } else{ if(j == 2) printf("{space %g}", wideM[j - 1] + 2) else printf(sprintf("%%%guds", wideM[j - 1] + 2), colnames[j]) } } printf(sprintf("\n{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) for(i = 1; i <= rows(M); i++){ printf(sprintf(" {txt}%%%guds {c |}{res}", wide), rownames[i]) for(j = 1; j <= cols(M); j++){ if(isInt == 0) printf(sprintf(" %%%g.4f ", wideM[j]), M[i,j]) else printf(sprintf(" %%%g.0g ", wideM[j]), M[i,j]) } printf("\n") } if(isMean == 1){ printf(sprintf("{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames)-1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) meanM = mean(M[1..rows(M), .]) printf(sprintf(" {txt}%%~%guds {c |}{res}", wide), "Mean") for(j = 1; j <= cols(M); j++){ printf(sprintf(" %%%g.4f ", wideM[j]), meanM[., j]) } printf("\n") } printf(sprintf("{hline %g}{c BT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) if(isMean == 1) printf(stritrim(sprintf("{txt}Note: The average treatment effect over the posttreatment period is{res} %10.4f{txt}.\n", meanM[., 3]))) } void synth2_print3(string matrix rownames, string matrix colnames, string matrix colname, real matrix M, real matrix indexRow, real scalar isMean, real matrix wideM, real scalar extend, real scalar isInt){ if (rows(indexRow) != 1){ rownames = rownames[indexRow, .] M = M[indexRow, .] } wide = max(udstrlen((rownames[1..rows(rownames),1]\colnames[1]))) printf(sprintf("{hline %g}{c TT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) printf(sprintf(" {txt}%%~%guds {c |}", wide), colnames[1]) printf(sprintf("{txt}%%~%guds", sum(wideM[1..2]) + 4), colname[1]) printf(sprintf("{txt}%%~%guds\n", sum(wideM[3..4]) + 4), colname[2]) printf(sprintf("{space %g}{c |}", wide + 2)) for(j = 2; j <= cols(colnames); j++){ if(j == cols(colnames) & (udstrlen(colnames[j]) > wideM[j - 1] + 2)){ printf(sprintf("%%%guds\n", wideM[j - 1] + 2), substr(colnames[j], 1, wideM[j - 1])) printf(" {space %g} {c |}", wide) for(k = 2; k <= cols(colnames); k++){ if(k != cols(colnames)){ printf("{space %g}", wideM[k - 1] + 2) } else printf(sprintf("%%%guds", wideM[k - 1] + 2), substr(colnames[k], wideM[k - 1] +1)) } } else printf(sprintf("%%%guds", wideM[j - 1] + 2), colnames[j]) } printf(sprintf("\n{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) for(i = 1; i <= rows(M); i++){ printf(sprintf(" {txt}%%%guds {c |}{res}", wide), rownames[i]) for(j = 1; j <= cols(M); j++){ if(isInt == 0) printf(sprintf(" %%%g.4f ", wideM[j]), M[i,j]) else printf(sprintf(" %%%g.0g ", wideM[j]), M[i,j]) } printf("\n") } if(isMean == 1){ printf(sprintf("{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames)-1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) meanM = mean(M[1..rows(M), .]) printf(sprintf(" {txt}%%~%guds {c |}{res}", wide), "Mean") for(j = 1; j <= cols(M); j++){ printf(sprintf(" %%%g.4f ", wideM[j]), meanM[., j]) } printf("\n") } printf(sprintf("{hline %g}{c BT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) if(isMean == 1) printf(stritrim(sprintf("{txt}Note: The average treatment effect over the posttreatment period is{res} %10.4f{txt}.\n", meanM[., 3]))) } void synth2_print4(string matrix rownames, string matrix colnames, string matrix colname, real matrix M, real matrix indexRow, real scalar isMean, real matrix wideM, real scalar extend, real scalar isInt){ if (rows(indexRow) != 1){ rownames = rownames[indexRow, .] M = M[indexRow, .] } wide = max(udstrlen((rownames[1..rows(rownames),1]\colnames[1]))) printf(sprintf("{hline %g}{c TT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) printf(sprintf(" {txt}%%~%guds {c |}", wide), colnames[1]) printf(sprintf("{txt}%%%guds", wideM[1] + 2), colnames[2]) printf(sprintf("{txt}%%%guds", wideM[2] + 2), colnames[3]) printf(sprintf("{txt}%%~%guds", sum(wideM[3..4]) + 4), colname[1]) printf(sprintf("{txt}%%~%guds\n", sum(wideM[5..6]) + 4), colname[2]) printf(sprintf("{space %g}{c |}", wide + 2)) for(j = 2; j <= cols(colnames); j++){ if(j == cols(colnames) & (udstrlen(colnames[j]) > wideM[j - 1] + 2)){ printf(sprintf("%%%guds\n", wideM[j - 1] + 2), substr(colnames[j], 1, wideM[j - 1])) printf(" {space %g} {c |}", wide) for(k = 2; k <= cols(colnames); k++){ if(k != cols(colnames)){ printf("{space %g}", wideM[k - 1] + 2) } else printf(sprintf("%%%guds", wideM[k - 1] + 2), substr(colnames[k], wideM[k - 1] +1)) } } else{ if(j == 2 | j == 3) printf("{space %g}", wideM[j - 1] + 2) else printf(sprintf("%%%guds", wideM[j - 1] + 2), colnames[j]) } } printf(sprintf("\n{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) for(i = 1; i <= rows(M); i++){ printf(sprintf(" {txt}%%%guds {c |}{res}", wide), rownames[i]) for(j = 1; j <= cols(M); j++){ if(j != 4 & j != 6) printf(sprintf(" %%%g.4f ", wideM[j]), M[i,j]) else printf(sprintf(" %%%g.2f%%%%", wideM[j]), M[i,j]) } printf("\n") } if(isMean == 1){ printf(sprintf("{hline %g}{c +}", wide + 2)) for(j = 1; j <= cols(colnames)-1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) meanM = mean(M[1..rows(M), .]) printf(sprintf(" {txt}%%~%guds {c |}{res}", wide), "Mean") for(j = 1; j <= cols(M); j++){ printf(sprintf(" %%%g.4f ", wideM[j]), meanM[., j]) } printf("\n") } printf(sprintf("{hline %g}{c BT}", wide + 2)) for(j = 1; j <= cols(colnames) - 1; j++) printf(sprintf("{hline %g}", wideM[j] + 2)) printf(sprintf("{hline %g}\n", extend)) if(isMean == 1) printf(stritrim(sprintf("{txt}Note: The average treatment effect over the posttreatment period is{res} %10.4f{txt}.\n", meanM[., 3]))) } void synth2_placebo(real matrix timeVar, string matrix panelVarStr, string matrix timeVarStr, string scalar unit_tr, string scalar unit_pboSel, real scalar trperiod, real matrix respo){ real matrix pvalM indexRow = selectindex((panelVarStr :== unit_tr) :& (timeVar :>= trperiod)) tr_eff = respo[indexRow,] unit_list = tokens(unit_pboSel) eff = tr_eff for(i = 1; i<= cols(unit_list); i++){ tempIndexRow = selectindex((panelVarStr :== unit_list[i]) :& (timeVar :>= trperiod)) eff = (eff, respo[tempIndexRow, .]) } pval = J(rows(eff), 3, .) for(i = 1; i <= rows(pval); i++) { pval[i, 1] = mean((abs(tr_eff[i, 1]) :<= abs(eff[i, .]))') pval[i, 2] = mean((tr_eff[i, 1] :<= eff[i, .])') pval[i, 3] = mean((tr_eff[i, 1] :>= eff[i, .])') } synth2_print2(timeVarStr[indexRow, .], ("Time", "Treatment Effect", "Two-sided ", "Right-sided", "Left-sided"), "p-value of Treatment Effect", (tr_eff, pval), ., 0, (16, 11, 11, 11), 0, 0) st_matrix("pval", (tr_eff, pval)) st_matrixcolstripe("pval", (("", "p-value", "p-value", "p-value")',("Tr.Eff.", "two-sided", "right-sided", "left-sided")')) st_matrixrowstripe("pval",(J(rows(timeVarStr[indexRow, .]), 1, ""), timeVarStr[indexRow, .])) temp = _st_addvar("float", "pvalTwo") temp = _st_addvar("float", "pvalRight") temp = _st_addvar("float", "pvalLeft") st_view(pvalM, ., ("pvalTwo", "pvalRight", "pvalLeft")) pvalM[indexRow, .] = pval } end * 2.1.0 Add the option sign() * 2.0.1 Fix some bugs * 2.0.0 Enhance the functionality of saving graphs * 1.0.0 Address the compatibility issue of varabbreviation * 0.0.2 Adjust the input of numlist of covariates * 0.0.1 Fix the issue of parameter transfer in the placebo test * 0.0.0 Submit the initial version of synth2