From 95cffafc6ee6f76f3a4c10b49d9989f2272820d4 Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Sat, 18 Apr 2015 13:44:54 -0400 Subject: [PATCH 1/3] Experimental support for 2+ absorb with hdfe.ado Complete changelist: - Allow `hdfe` option - Absorb can be abbreviated as a(), like in areg - Multiple absvars allowed (anything that goes in hdfe goes in here) - Replaced local names in reportreg with more meaningful names Pending issues: - hdfe.ado has no -addmean- option; I need to add it so it works with addmean here. For now, you NEED to set noaddmean if you set hdfe Example Usage: binscatter price weight length, absorb(foreign) controls(gear head) hdfe noaddmean reportreg line(qfit) --- binscatter.ado | 51 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/binscatter.ado b/binscatter.ado index 85d2947..c8b8ad4 100644 --- a/binscatter.ado +++ b/binscatter.ado @@ -16,11 +16,12 @@ program define binscatter, eclass sortpreserve syntax varlist(min=2 numeric) [if] [in] [aweight fweight], [by(varname) /// Nquantiles(integer 20) GENxq(name) discrete xq(varname numeric) MEDians /// - CONTROLs(varlist numeric ts fv) absorb(varname) noAddmean /// + CONTROLs(varlist numeric ts fv) Absorb(varname) noAddmean /// LINEtype(string) rd(numlist ascending) reportreg /// COLors(string) MColors(string) LColors(string) Msymbols(string) /// savegraph(string) savedata(string) replace /// nofastxtile randvar(varname numeric) randcut(real 1) randn(integer -1) /// + hdfe /// /* LEGACY OPTIONS */ nbins(integer 20) create_xq x_q(varname numeric) symbols(string) method(string) unique(string) /// *] @@ -170,8 +171,24 @@ program define binscatter, eclass sortpreserve ****** Create residuals ****** - - if (`"`controls'`absorb'"'!="") quietly { + if (`"`controls'`absorb'"'!="" & "`hdfe'"!="") { + assert "`addmean'"=="noaddmean" + cap which hdfe + if (_rc==11) ssc install hdfe + hdfe `x_var' `y_vars' `wt' if `touse', partial(`controls') absorb(`absorb') gen(__resid__) // `addmean' + * possible simplification: have three options: stub() replace generate() + * possible improvement: there may be some limitations on binscatter's by(); maybe hdfe can lift them (or they are intended?) + tempvar x_r + rename __resid__`x_var' `x_r' + label variable `x_r' "`x_var'" + foreach var of varlist `y_vars' { + tempvar residvar + rename __resid__`var' `residvar' + label variable `residvar' "`var'" + local y_vars_r `y_vars_r' `residvar' + } + } + else if (`"`controls'`absorb'"'!="") quietly { * Parse absorb to define the type of regression to be used if `"`absorb'"'!="" { @@ -208,7 +225,6 @@ program define binscatter, eclass sortpreserve local y_vars_r `y_vars' } - ****** Regressions for fit lines ****** if ("`reportreg'"=="") local reg_verbosity "quietly" @@ -273,24 +289,37 @@ program define binscatter, eclass sortpreserve if (`ynum'>1) { if ("`controls'`absorb'"!="") local depvar_name : var label `depvar' else local depvar_name `depvar' - di as text "{bf:y_var = `depvar_name'}" } * perform regression - if ("`reg_verbosity'"=="quietly") capture reg `depvar' `x_r2' `x_r' `wt' if `conds' - else capture noisily reg `depvar' `x_r2' `x_r' `wt' if `conds' + ereturn clear + capture regress `depvar' `x_r2' `x_r' `wt' if `conds', noheader notable + local rc = _rc + + * replay regression with correct names + if ("`reg_verbosity'"!="quietly") { + ereturn local depvar = "`depvar_name'" + local indepvar_names `x_var' _cons + if ("`linetype'"=="qfit") local indepvar_names `x_var'^2 `indepvar_names' + tempname b + matrix `b' = e(b) + *local backup_colnames : colnames `b' + matrix colnames `b' = `indepvar_names' + ereturn repost b=`b', rename + regress // Replay + } * store results - if (_rc==0) matrix e_b_temp=e(b) - else if (_rc==2000) { + if (`rc'==0) matrix e_b_temp=e(b) + else if (`rc'==2000) { if ("`reg_verbosity'"=="quietly") di as error "no observations for one of the fit lines. add 'reportreg' for more info." if ("`linetype'"=="lfit") matrix e_b_temp=.,. else /*("`linetype'"=="qfit")*/ matrix e_b_temp=.,.,. } else { - error _rc - exit _rc + error `rc' + exit `rc' } * relabel matrix row From 3dbfdd4ec9e55227b01234ef457476c1cc9f74d0 Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Sat, 18 Apr 2015 16:22:55 -0400 Subject: [PATCH 2/3] (bugfixes) 1) HDFE Now works with addmean (the default option) 2) Changed Absorb to ABSorb to avoid conflict with noAddmean 3) hdfe not installed by default --- binscatter.ado | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/binscatter.ado b/binscatter.ado index c8b8ad4..26d76b1 100644 --- a/binscatter.ado +++ b/binscatter.ado @@ -16,7 +16,7 @@ program define binscatter, eclass sortpreserve syntax varlist(min=2 numeric) [if] [in] [aweight fweight], [by(varname) /// Nquantiles(integer 20) GENxq(name) discrete xq(varname numeric) MEDians /// - CONTROLs(varlist numeric ts fv) Absorb(varname) noAddmean /// + CONTROLs(varlist numeric ts fv) ABSorb(varlist) noAddmean /// LINEtype(string) rd(numlist ascending) reportreg /// COLors(string) MColors(string) LColors(string) Msymbols(string) /// savegraph(string) savedata(string) replace /// @@ -172,10 +172,13 @@ program define binscatter, eclass sortpreserve ****** Create residuals ****** if (`"`controls'`absorb'"'!="" & "`hdfe'"!="") { - assert "`addmean'"=="noaddmean" - cap which hdfe - if (_rc==11) ssc install hdfe - hdfe `x_var' `y_vars' `wt' if `touse', partial(`controls') absorb(`absorb') gen(__resid__) // `addmean' + hdfe `x_var' `y_vars' `wt' if `touse', partial(`controls') absorb(`absorb') gen(__resid__) + if ("`addmean'"!="noaddmean") { + foreach var of varlist `x_var' `y_vars' { + summarize `var' `wt' if `touse', meanonly + qui replace __resid__`var' = __resid__`var' + r(mean) + } + } * possible simplification: have three options: stub() replace generate() * possible improvement: there may be some limitations on binscatter's by(); maybe hdfe can lift them (or they are intended?) tempvar x_r From b95f43de3e507880921d98b0d9072e976c042607 Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Sat, 18 Apr 2015 16:41:45 -0400 Subject: [PATCH 3/3] autoselect hdfe when needed uses hdfe.ado when there is more than one absvar --- binscatter.ado | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/binscatter.ado b/binscatter.ado index 26d76b1..5f3a81d 100644 --- a/binscatter.ado +++ b/binscatter.ado @@ -21,7 +21,6 @@ program define binscatter, eclass sortpreserve COLors(string) MColors(string) LColors(string) Msymbols(string) /// savegraph(string) savedata(string) replace /// nofastxtile randvar(varname numeric) randcut(real 1) randn(integer -1) /// - hdfe /// /* LEGACY OPTIONS */ nbins(integer 20) create_xq x_q(varname numeric) symbols(string) method(string) unique(string) /// *] @@ -171,7 +170,12 @@ program define binscatter, eclass sortpreserve ****** Create residuals ****** - if (`"`controls'`absorb'"'!="" & "`hdfe'"!="") { + if (`"`controls'`absorb'"'!="" & `: word count `absorb''>1) { + cap which hdfe.ado + if _rc { + di as error "hdfe.ado required when using multiple absorb variables: {stata ssc install hdfe}" + exit 111 + } hdfe `x_var' `y_vars' `wt' if `touse', partial(`controls') absorb(`absorb') gen(__resid__) if ("`addmean'"!="noaddmean") { foreach var of varlist `x_var' `y_vars' {