************************************************************************* * PROGRAM "TED" * Date: 04/11/2016 * Author: Giovanni Cerulli * Used for the paper: * "Testing Stability of Regression Discontinuity Models" * by G. Cerulli, Y. Dong, A. Lewbel, and A. Poulsen (2016) ************************************************************************* ************************************************************************* * PROGRAM FOR VARIOUS KERNELS GENERATION: "_Kernel_" ************************************************************************* cap program drop _Kernel_ program define _Kernel_ args kernel weight dif bwidth if ("`kernel'"=="epan") { qui g double `weight' = 1 - (`dif'/`bwidth')^2 if abs(`dif')<=`bwidth' } else if ("`kernel'"=="normal") { qui g double `weight' = normalden(`dif'/`bwidth') } else if ("`kernel'"=="biweight") { qui g double `weight' = (1 - (`dif'/`bwidth')^2)^2 if abs(`dif')<=`bwidth' } else if ("`kernel'"=="uniform") { qui g double `weight' = 1 if abs(`dif')<=`bwidth' } else if ("`kernel'"=="triangular") { qui g double `weight' = (1-abs(`dif'/`bwidth')) if abs(`dif')<=`bwidth' } else if ("`kernel'"=="tricube") { qui g double `weight' = (1-abs(`dif'/`bwidth')^3)^3 if abs(`dif')<=`bwidth' } // normalize sum of weights to 1 sum `weight', mean replace `weight' = `weight'/r(sum) end ************************************************************************* * PROGRAM "ted" ************************************************************************* *! ted v2.0.0 GCerulli 29apr2016 capture program drop ted program ted, eclass version 13 #delimit; syntax varlist [if] [in] [fweight iweight pweight] [, model(string) h(numlist max=1) c(numlist max=1) m(numlist max=1 integer) l(numlist max=1) k(string) vce(string) graph save_graph_o(string) save_graph_p(string) ]; #delimit cr ************************************************************ if "`model'"=="sharp"{ marksample touse tokenize `varlist' local y `1' // outcome local s `2' // running variable local w `3' macro shift macro shift macro shift local xvars `*' ************************************************************* cap drop _x gen _x=`s'-`c' // demeaned forcing variable la var _x "Running variable (centered at zero)" ************************************************************* la var `w' "Binary treatment variable" la var `s' "Uncentered running variable" la var `y' "Outcome variable" ************************************************************* * GENERATE _T=1(s>s_star) ************************************************************* cap drop _T gen _T=(`s'>=`c') la var _T "1[S > S*] = above-threshold variable" ************************************************************************* * Generate the polynomial factors ************************************************************* forvalues j=1/`m'{ cap drop _x_`j' } forvalues j=1/`m'{ gen _x_`j'=(_x)^(`j') la var _x_`j' "Polynomial term for running variable of degree `j'" } forvalues j=1/`m'{ cap drop _T_x_`j' } forvalues j=1/`m'{ gen _T_x_`j'=_T*(_x)^(`j') la var _T_x_`j' "Interaction between running and above-threshold. Polynomial degree `j'" } local xvars forvalues j=1/`m'{ local xvars `xvars' _x_`j' } local Txvars forvalues j=1/`m'{ local Txvars `Txvars' _T_x_`j' } ************************************************************************* * COMPUTATION OF DISCONTINUITY IN THE OUTCOME ************************************************************************* * GENERATE KERNEL WEIGHTS ("weight") ************************************************************************* tempvar _weight _Kernel_ `k' `_weight' _x `h' ************************************************************************* * LOCAL KERNEL POLYNOMIAL REGRESSION OF DEGREE "m" * (AROUND THE CUT-OFF s*, WITH BANDWIDTH "b") ************************************************************************* di as text "" di as text "{hline}" di as text "{bf:******************************************************************************}" di as text "{bf:************************ DISCONTINUITY IN THE OUTCOME ************************}" di as text "{bf:******************************************************************************}" reg `y' `xvars' _T `Txvars' [pw=`_weight'] if _x>=-`h' & _x<=`h' & `touse', `vce' scalar size_o=r(N) ************************************************************************* * RETURNED SCALARS ************************************************************************* scalar alfaO0=_b[_cons] // left regression intercept at cut-off scalar alfaO1=_b[_T]+alfaO0 // right regression intercept at cut-off scalar gammaO0=_b[_T] // discontinuity in the outcome at cut-off scalar gammaO1=_b[_T_x_1] // discontinuity in derivative at cut-off scalar betaO0=_b[_x_1] // left slope at cut-off scalar betaO1=betaO0+gammaO1 // right slope at cut-off global gammaO1=_b[_T_x_1] ************************************************************************* * Calculate (again) the discontinuity in the outcome ("disc_y") ************************************************************************* scalar disc_y = _b[_T] ************************************************************************* * Prediction of the polynomial fit ("y_hat") ************************************************************************* tempvar y_hat1 predict `y_hat1' if _T==1, xb tempvar y_hat0 predict `y_hat0' if _T==0 , xb replace `y_hat0'=alfaO0 if _x==0 & _T==0 ************************************************************************* * GENERATE THE LEFT ("0") AND THE RIGHT ("1") TANGENTS AT CUT-OFF ************************************************************************* tempvar y_tang1 gen `y_tang1' = alfaO1 + betaO1*_x tempvar y_tang0 gen `y_tang0' = alfaO0 + betaO0*_x ************************************************************************* * GRAPH OUTCOME DISCONTINUITY WITH TANGENTS ************************************************************************* if "`graph'"=="graph"{ * RIGHT tempvar grid_r points_r lpoly `y' _x if _x>=0 & _x<=`h' & `touse', kernel(rect) at(_x) gen(`grid_r' `points_r') degree(0) bwidth(1) noscatter nograph * LEFT tempvar grid_l points_l lpoly `y' _x if _x<=0 & _x>=-`h' & `touse', kernel(rect) at(_x) gen(`grid_l' `points_l') degree(0) bwidth(1) noscatter nograph graph twoway /// (scatter `points_r' `grid_r' if _x >0 & _x<`l' & `touse', msymbol(o)) /// (scatter `points_l' `grid_l' if _x >-`l' & _x<=0 & `touse', msymbol(oh)) /// (line `y_tang1' _x if _x>=0 & _x<=`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs10) lpattern(solid) ) /// (mspline `y_hat1' _x if _T==1 & _x>=0 & _x<=`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs0) lpattern(solid)) /// (line `y_tang0' _x if _x<=0 & _x>=-`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs10) lpattern(solid)) /// (mspline `y_hat0' _x if _T==0 & _x<=0 & _x>=-`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs0) lpattern(solid)) , /// legend(on order(1 2 3 4) label(1 "Right local means") label(2 "Left local means" ) label(3 "Tangent" ) label(4 "Prediction" )) /// xline(0, lpattern(dash)) /// ylabel(,labsize(small)) /// xlabel(-`l' +`l') /// xtitle("Running variable", size(small)) /// ytitle("Outcome") /// scheme(s2mono) graphregion(fcolor(white)) /// title("Fuzzy RD, KLPR, Outcome discontinuity" , size(medium)) /// legend(size(small)) /// xlabel(,labsize(small)) /// ylabel(,labsize(small)) /// note("KLPR = Kernel Local Polynomial Regression" "Kernel = `k'" "Bandwidth value = `h'" /// "Polynomial degree = `m'") if "`save_graph_o'"!=""{ graph save `save_graph_o' , replace } } ************************************************************************* * TEST OF SIGNIFICANCE FOR "LATE" ************************************************************************* qui reg `y' `xvars' _T `Txvars' [pw=`_weight'] if _x>=-`h' & _x<=`h' & `touse' , `vce' di as text "{hline}" di as text "{bf:************************ Test of significance for LATE ***********************}" nlcom (LATE: _b[_T]) ************************************************************************* * TEST OF SIGNIFICANCE FOR "TED" ************************************************************************* di as text "{hline}" di as text "{bf:************************ Test of significance for TED ************************}" nlcom (TED: _b[_T_x_1]) ************************************************************************* ************************************************************************* * CALCULATE "LATE" ************************************************************************* ereturn scalar LATE=disc_y ************************************************************************* * CALCULATE "TED" ************************************************************************* ereturn scalar TED=_b[_T_x_1] *** Number of (used) treated and untreated units ************************ qui sum `w' if e(sample) ereturn scalar N_tot=r(sum_w) qui sum `w' if e(sample) & `w'==1 ereturn scalar N_treated=r(sum_w) qui sum `w' if e(sample) & `w'==0 ereturn scalar N_untreated=r(sum_w) } ************************************************************************* * FUZZY ************************************************************************* else if "`model'"=="fuzzy"{ marksample touse tokenize `varlist' local y `1' // outcome local s `2' // running variable local w `3' macro shift macro shift macro shift local xvars `*' ************************************************************* cap drop _x gen _x=`s'-`c' // demeaned forcing variable la var _x "Running variable (centered at zero)" ************************************************************* la var `w' "Binary treatment variable" la var `s' "Uncentered running variable" la var `y' "Outcome variable" ************************************************************* * GENERATE _T=1(s>s_star) ************************************************************* cap drop _T gen _T=(`s'>=`c') la var _T "1[S > S*] = above-threshold indicator" ************************************************************************* * Generate the polynomial factors ************************************************************* forvalues j=1/`m'{ cap drop _x_`j' } forvalues j=1/`m'{ gen _x_`j'=(_x)^(`j') la var _x_`j' "Polynomial term for running variable of degree `j'" } forvalues j=1/`m'{ cap drop _T_x_`j' } forvalues j=1/`m'{ gen _T_x_`j'=_T*(_x)^(`j') la var _T_x_`j' "Interaction between running and above-threshold. Polynomial degree `j'" } local xvars forvalues j=1/`m'{ local xvars `xvars' _x_`j' } local Txvars forvalues j=1/`m'{ local Txvars `Txvars' _T_x_`j' } ************************************************************************* * COMPUTATION OF DISCONTINUITY IN THE OUTCOME ************************************************************************* * GENERATE KERNEL WEIGHTS ("weight") ************************************************************************* tempvar _weightO _Kernel_ `k' `_weightO' _x `h' ************************************************************************* * LOCAL KERNEL POLYNOMIAL REGRESSION OF DEGREE "m" * (AROUND THE CUT-OFF s*, WITH BANDWIDTH "b") ************************************************************************* di as text "" di as text "{hline}" di as text "{bf:******************************************************************************}" di as text "{bf:************************ DISCONTINUITY IN THE OUTCOME ************************}" di as text "{bf:******************************************************************************}" reg `y' `xvars' _T `Txvars' [pw=`_weightO'] if _x>=-`h' & _x<=`h' & `touse', `vce' *estimates store my scalar size_o=r(N) ************************************************************************* * RETURNED SCALARS ************************************************************************* scalar alfaO0=_b[_cons] // left regression intercept at cut-off scalar alfaO1=_b[_T]+alfaO0 // right regression intercept at cut-off scalar gammaO0=_b[_T] // discontinuity in the outcome at cut-off scalar gammaO1=_b[_T_x_1] // discontinuity in derivative at cut-off scalar betaO0=_b[_x_1] // left slope at cut-off scalar betaO1=betaO0+gammaO1 // right slope at cut-off ************************************************************************* * Calculate (again) the discontinuity in the outcome ("disc_y") ************************************************************************* scalar disc_y = _b[_T] ************************************************************************* * Prediction of the polynomial fit ("y_hat") ************************************************************************* tempvar y_hat1 predict `y_hat1' if _T==1, xb tempvar y_hat0 predict `y_hat0' if _T==0 , xb replace `y_hat0'=alfaO0 if _x==0 & _T==0 ************************************************************************* * GENERATE THE LEFT ("0") AND THE RIGHT ("1") TANGENTS AT CUT-OFF ************************************************************************* tempvar y_tang1 gen `y_tang1' = alfaO1 + betaO1*_x tempvar y_tang0 gen `y_tang0' = alfaO0 + betaO0*_x ************************************************************************* * GRAPH OUTCOME DISCONTINUITY WITH TANGENTS ************************************************************************* if "`graph'"=="graph"{ * RIGHT tempvar grid_r points_r lpoly `y' _x if _x>=0 & _x<=`h' & `touse', kernel(rect) at(_x) gen(`grid_r' `points_r') degree(0) bwidth(1) noscatter nograph * LEFT tempvar grid_l points_l lpoly `y' _x if _x<=0 & _x>=-`h' & `touse', kernel(rect) at(_x) gen(`grid_l' `points_l') degree(0) bwidth(1) noscatter nograph graph twoway /// (scatter `points_r' `grid_r' if _x >0 & _x<`l' & `touse', msymbol(o)) /// (scatter `points_l' `grid_l' if _x >-`l' & _x<=0 & `touse', msymbol(oh)) /// (line `y_tang1' _x if _x>=0 & _x<=`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs10) lpattern(solid) ) /// (mspline `y_hat1' _x if _T==1 & _x>=0 & _x<=`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs0) lpattern(solid)) /// (line `y_tang0' _x if _x<=0 & _x>=-`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs10) lpattern(solid)) /// (mspline `y_hat0' _x if _T==0 & _x<=0 & _x>=-`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs0) lpattern(solid)) , /// legend(on order(1 2 3 4) label(1 "Right local means") label(2 "Left local means" ) label(3 "Tangent" ) label(4 "Prediction" )) /// xline(0, lpattern(dash)) /// ylabel(,labsize(small)) /// xlabel(-`l' +`l') /// xtitle("Running variable", size(small)) /// ytitle("Outcome") /// scheme(s2mono) graphregion(fcolor(white)) /// title("Fuzzy RD, KLPR, Outcome discontinuity" , size(medium)) /// legend(size(small)) /// xlabel(,labsize(small)) /// ylabel(,labsize(small)) /// note("KLPR = Kernel Local Polynomial Regression" "Kernel = `k'" "Bandwidth value = `h'" /// "Polynomial degree = `m'" ) if "`save_graph_o'"!=""{ graph save `save_graph_o' , replace } } ************************************************************************* * DISCONTINUITY IN THE PROBABILITY ************************************************************************* * GENERATE KERNEL WEIGHTS ("weight") ************************************************************************* tempvar _weightP _Kernel_ `k' `_weightP' _x `h' ************************************************************************* * LOCAL KERNEL POLYNOMIAL REGRESSION OF DEGREE "m" * (AROUND THE CUT-OFF s*, WITH BANDWIDTH "b") ************************************************************************* di as text "" di as text "{hline}" di as text "{bf:******************************************************************************}" di as text "{bf:********************** DISCONTINUITY IN THE PROBABILITY **********************}" di as text "{bf:******************************************************************************}" reg `w' `xvars' _T `Txvars' [pw=`_weightP'] if _x>=-`h' & _x<=`h' & `touse', `vce' // same bandwidth of outcome *estimates store mw scalar size_p=r(N) ************************************************************************* * RETURNED SCALARS ************************************************************************* scalar alfaP0=_b[_cons] // left regression intercept at cut-off scalar alfaP1=_b[_T]+alfaP0 // right regression intercept at cut-off scalar gammaP0=_b[_T] // discontinuity in the probability at cut-off scalar gammaP1=_b[_T_x_1] // CPD or discontinuity in derivative at cut-off scalar betaP0=_b[_x_1] // left slope at cut-off scalar betaP1=betaP0+gammaP1 // right slope at cut-off ************************************************************************* * Calculate (again) the discontinuity in the probability ("disc_w") ************************************************************************* scalar disc_w = _b[_T] ************************************************************************* * Prediction of the polynomial fit ("w_hat") ************************************************************************* tempvar w_hat1 predict `w_hat1' if _T==1, xb tempvar w_hat0 predict `w_hat0' if _T==0 , xb replace `w_hat0'=alfaP0 if _x==0 & _T==0 ************************************************************************* * GENERATE THE LEFT ("0") AND THE RIGHT ("1") TANGENTS AT CUT-OFF ************************************************************************* tempvar w_tang1 gen `w_tang1' = alfaP1 + betaP1*_x tempvar w_tang0 gen `w_tang0' = alfaP0 + betaP0*_x ************************************************************************* * GRAPH PROBABILITY DISCONTINUITY WITH TANGENTS ************************************************************************* if "`graph'"=="graph"{ * RIGHT tempvar grid_r points_r lpoly `w' _x if _x>=0 & _x<=`h' & `touse', kernel(rect) at(_x) gen(`grid_r' `points_r') degree(0) bwidth(1) noscatter nograph * LEFT tempvar grid_l points_l lpoly `w' _x if _x<=0 & _x>=-`h' & `touse', kernel(rect) at(_x) gen(`grid_l' `points_l') degree(0) bwidth(1) noscatter nograph graph twoway /// (scatter `points_r' `grid_r' if _x >0 & _x<`l' & `touse', msymbol(o)) /// (scatter `points_l' `grid_l' if _x >-`l' & _x<=0 & `touse', msymbol(oh)) /// (line `w_tang1' _x if _x>=0 & _x<=`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs10) lpattern(solid) ) /// (mspline `w_hat1' _x if _T==1 & _x>=0 & _x<=`h' & _x>-`l' & _x<`l' & `touse', lcolor(gs0) lpattern(solid)) /// (line `w_tang0' _x if _x<=0 & _x>=-`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs10) lpattern(solid)) /// (mspline `w_hat0' _x if _T==0 & _x<=0 & _x>=-`h' & _x >-`l' & _x<`l' & `touse', lcolor(gs0) lpattern(solid)) , /// legend(on order(1 2 3 4) label(1 "Right local means") label(2 "Left local means" ) label(3 "Tangent" ) label(4 "Prediction" )) /// xline(0, lpattern(dash)) /// xtitle("Running variable") /// xlabel(-`l' +`l') /// scheme(s2mono) graphregion(fcolor(white)) /// title("Fuzzy RD, KLPR, Probability discontinuity" , size(medium)) /// ylabel(,labsize(small)) /// ytitle("Probability") /// xtitle("Running variable", size(small)) /// legend(size(small)) /// note("KLPR = Kernel Local Polynomial Regression" "Kernel = `k'" "Bandwidth value = `h'" /// "Polynomial degree = `m'") if "`save_graph_p'"!=""{ graph save `save_graph_p' , replace } } ************************************************************************* * SENSITIVITY TEST (PROBABILITY) ************************************************************************* di as text "" di as text "{hline}" di as text "{bf:************************ Test of significance for CPD ************************}" nlcom (CPD: _b[_T_x_1]) ************************************************************************* * CALCULATE "LATE" AS THE RATIO OF THE TWO DISCONTINUITY ************************************************************************* scalar LATE=disc_y/disc_w ************************************************************************* * CALCULATE "TED" ************************************************************************* ereturn scalar TED=(gammaO1-(gammaP1*gammaO0/gammaP0))/gammaP0 ereturn scalar CPD=gammaP1 ************************************************************************* * SIGNIFICANT TEST FOR "LATE" AND "TED" USING THE DELTA METHOD ************************************************************************* qui sureg /// (`y' `xvars' _T `Txvars') (`w' `xvars' _T `Txvars') /// if _x>=-`h' & _x<=`h' & `touse' [aw =`_weightP'] *Estimate LATE as the ratio of the coefficient of "_T" in equation "y" and "w" di as text "" di as text "{hline}" di as text "{bf:************************ Test of significance for LATE ***********************}" nlcom (LATE: [`y']_b[_T]/[`w']_b[_T]) *Estimate TED scalar TED=(gammaO1-(gammaP1*gammaO0/gammaP0))/gammaP0 di as text "" di as text "{hline}" di as text "{bf:************************ Test of significance for TED ************************}" nlcom (TED: ([`y']_b[_T_x_1]-([`w']_b[_T_x_1]*[`y']_b[_T]/[`w']_b[_T]))/[`w']_b[_T]) di as text "" ereturn scalar LATE=disc_y/disc_w ereturn scalar TED=(gammaO1-(gammaP1*gammaO0/gammaP0))/gammaP0 ereturn scalar CPD=gammaP1 *** Number of (used) treated and untreated units ************************ *qui reg `y' `xvars' _T `Txvars' [pw=`_weightO'] if _x>=-`h' & _x<=`h' & `touse', `vce' qui sum `w' if e(sample) ereturn scalar N_tot=r(sum_w) qui sum `w' if e(sample) & `w'==1 ereturn scalar N_treated=r(sum_w) qui sum `w' if e(sample) & `w'==0 ereturn scalar N_untreated=r(sum_w) } ************************************************************************* end