*! underid version 1.0.02 29sept2020 *! authors mes & fw * 1.0.01 (2july2020) * Final version of v1 release. * 1.0.02 (29sept2020) * nopartial option introduced * xtabond2+jgmm2s triggers nopartial unless h(1) * collinearity checks added program define underid, rclass byable(recall) sortpreserve version 13.1 local lversion 01.0.02 syntax [, /// underid /// default overid /// kp /// JGMM2s /// Jcue /// j2lr /// j2l /// wald /// lr /// small /// small-sample adjustment sw /// triggers looping through jgmm2s by regressor vceopt(string) /// overrides default VCE rkopt(string) /// additional ranktest options NOCENTER /// MUST APPEAR BEFORE CENTER IN OPTION LIST center /// repstata /// specific to EC2SLS and Hausman-Taylor only usemeans /// specific to EC2SLS and Hausman-Taylor only NOREPORT /// specific to xtabond2 VERsion /// debug /// EQxtabond2(string) /// specific to xtabond2: diff, lev or sys keepall /// specific to xtabond2: don't drop omitted etc. MAINeqn(string) /// for debugging - re-run IV eqn using retrieved data NOPARTIAL /// for debugging - suppresses partialling out for non-cue NOIsily /// NOCOLLIN /// don't check for collinearities ] if "`version'" != "" { // Report program version number, then exit. di in gr "`lversion'" return local version `lversion' exit } // check if command is supported local legalcmd "ivregress ivreg2 ivreg2h xtivreg xthtaylor xtivreg2 xtabond2 xtdpdgmm" local cmd "`e(cmd)'" local legal : list cmd in legalcmd if ~`legal' { di as err "underid not supported for command `e(cmd)'" error 301 } // check if essential component ranktest is installed and version is 2.0.03 or higher cap ranktest, version if _rc > 0 { di as err "Error: must have ranktest version 02.0.03 or greater installed" di as err "To install, from within Stata type " _c di in smcl "{stata ssc install ranktest :ssc install ranktest}" exit 601 } local vernum "`r(version)'" if ("`vernum'" < "02.0.03") | ("`vernum'" > "09.9.99") { di as err "Error: must have ranktest version 02.0.03 or greater installed" di as err "Currently installed version is " as text "`vernum'" di as err "To update, from within Stata type " _c di in smcl "{stata ssc install ranktest, replace :ssc install ranktest, replace}" exit 601 } // set various flags etc. if "`noisily'"=="" { local qui qui } if "`noreport'"~="" { local noreport qui } if "`underid'`overid'"=="" { // default local underidflag 1 local overidflag 0 } else { local underidflag ="`underid'"~="" local overidflag ="`overid'"~="" } local nopartialflag ="`nopartial'"~="" local swflag ="`sw'"~="" local swnopartialflag =`nopartialflag' // default, can be overridden below local repstataflag ="`repstata'"~="" local usemeansflag ="`usemeans'"~="" local collincheckflag ="`nocollin'"=="" if `repstataflag' & `usemeansflag' { di as err "incompatible options: repstata and usemeans" exit 198 } // special treatment below local jgmm2sflag ="`jgmm2s'"~="" // debugging/undocumented options local debugflag =("`debug'"~="") if "`kp'`jgmm2s'`jcue'`j2lr'`j2l'`lr'"=="" { // set default local rkstat jcue } else { // check syntax - can choose only one local check : word count `kp' `jgmm2s' `jcue' `j2lr' `j2l' `lr' if `check'==1 { local rkstat `kp' `jgmm2s' `jcue' `j2lr' `j2l' `lr' } else { di as err "synax error: incompatible options "`kp' `jgmm2s' `jcue' `j2lr' `j2l' `lr'" exit 198 } } // check syntax - can choose only one local check : word count `center' `nocenter' if `check' > 1 { di as err "synax error: incompatible options center nocenter" exit 198 } *************************************************************************************************** ************************* ASSEMBLE MODEL AND OPTION SPECS ***************************************** // Save command line local cmdline "underid `0'" // esample = touse, except for xtabond2 where esample = original e(sample) in estimation // use touse unless need to refer explicitly to original sample (e.g. when expanding factor vars) tempvar esample qui gen byte `esample'=e(sample) // If data already preserved, OK; if preserve fails for other reasons, exit with error capture preserve if _rc > 0 & _rc~=621 { di as err "Internal underid error - preserve failed" exit 498 } // Create temp variables that will be changed by subroutines tempvar touse wvar qui gen byte `touse'=. qui gen double `wvar'=1 // Get underid options from command line // Pass additional args to get_option_specs; bind needed in case of constructs like "l(1,2).abmi" gettoken first opts : 0 , parse(",") bind if "`first'"~="," { // args in macro `first' so run again gettoken first opts : opts , parse(",") bind // to get rid of comma } // Get model specs from active model `noreport' get_model_specs, /// Gets model specs from prev model. Catches some illegals. `opts' /// touse(`touse') /// Applies to possibly-expanded current estimation sample esample(`esample') /// Applies to original data estimation sample wvar(`wvar') /// eqxtabond2(`eqxtabond2') /// specific to xtabond2 - use only diff or lev data/eqn `keepall' /// specific to xtabond2 - don't drop omitteds etc. debugflag(`debugflag') if `debugflag' { return list } local cmd `r(cmd)' local model `r(model)' local xtmodel `r(xtmodel)' // empty if not estimated using panel data estimator local depvar `r(depvar)' local inexog `r(inexog)' local endo `r(endo)' local exexog `r(exexog)' local TVexog `r(TVexog)' // specific to xthtaylor local TVendo `r(TVendo)' // specific to xthtaylor local TIexog `r(TIexog)' // specific to xthtaylor local TIendo `r(TIendo)' // specific to xthtaylor local noconstant `r(noconstant)' // "noconstant" if no constant in original model specification local cons `r(cons)' // 0 if no constant in original model local nendog `r(nendog)' local nexexog `r(nexexog)' local ninexog `r(ninexog)' local nexog `r(nexog)' local robust `r(robust)' local cluster `r(cluster)' // = cluster( ) or cluster( ) local clustvar `r(clustvar)' // ="clustvar1" if 1-way, ="clustvar1 clustvar2" if 2-way local clustvar1 `r(clustvar1)' local clustvar2 `r(clustvar2)' local bw `r(bw)' local kernel `r(kernel)' local wtexp `r(wtexp)' local wtype `r(wtype)' local exp `r(exp)' local wf `r(wf)' local N `r(N)' local N_clust `r(N_clust)' // With 2-way clustering, is min(N_clust1,N_clust2) local N_clust1 `r(N_clust1)' local N_clust2 `r(N_clust2)' local N_g `r(N_g)' // #panel groups local g_min `r(g_min)' local g_max `r(g_max)' local g_avg `r(g_avg)' local Tbar `r(Tbar)' local sig_e2 `r(sig_e2)' local sig_u2 `r(sig_u2)' local singleton `r(singleton)' // #panel singletons local dofminus `r(dofminus)' // 0 unless set by ivreg2 local psd `r(psd)' local gmm2s `r(gmm2s)' local ivar `r(ivar)' local tvar `r(tvar)' local esmall `r(small)' // small option used for estimator local ecenter `r(center)' // center option used for estimator if "`center'`nocenter'"=="" { // if nocenter is specified, then center macro will be empty local center `r(center)' // if not specified by user, override } // xtabond2 is a special case if "`cmd'" == "xtabond2" { if "`vceopt'"~="" { di as err "Error: vceopt(.) option not supported with xtabond2" exit 198 } // xtabond2+jgmm2s triggers nopartial unless h=1 // note SW are always jgmm2s if "`rkstat'"=="jgmm2s" & r(h)~=1 { local nopartialflag =1 local nopartial nopartial } if `swflag' & r(h)~=1 { local swnopartialflag =1 } tempname A1 A2 S1 S2 H mat `A1' = r(A1) mat `A2' = r(A2) // matrices may be missing - caught later cap mat `S1' = invsym(`A1')*1/`N' cap mat `S2' = invsym(`A2')*1/`N' mat `H' = r(H) // H matrix local h = r(h) // h = 1, 2 or 3 local panelvar `r(panelvar)' local timevar `r(timevar)' local eqvar `r(eqvar)' local hvar `r(hvar)' local haslevel = `r(haslevel)' local uselevel = `r(uselevel)' local hasdiff = `r(hasdiff)' local usediff = `r(usediff)' local transform `r(transform)' // "first differences" or "orthogonal deviations" // following maybe unneeded local gmminsts1 `r(gmminsts1)' local gmminsts2 `r(gmminsts2)' local ivinsts1 `r(ivinsts1)' local ivinsts2 `r(ivinsts2)' local pca `r(pca)' } // create or process vceopt: if "`vceopt'"=="" { // take VCE options from previous estimation if "`clustvar1'" ~= "" { local clusterarg `clustvar1' `clustvar2' local clusterarg : list clean clusterarg local vceopt cluster(`clusterarg') } if "`kernel'" ~= "" { local vceopt bw(`bw') kernel(`kernel') } local vceopt `robust' `vceopt' local iidflag ="`robust'`clusterarg'`bw'`kernel'"=="" } else if "`vceopt'"=="iid" { // VCE is unrobust iid version local vceopt // overwrite iidflag local iidflag = 1 } else { local iidflag = 0 } // create clustflag local vceopt : subinstr local vceopt "cluster" "cluster", count(local clustflag) // within transformation for FE models if "`xtmodel'" == "fe" { foreach vlist in depvar endo inexog exexog { fvrevar ``vlist'' if `touse' local `vlist' `r(varlist)' } tempvar T_i sort `ivar' `touse' // Only iw and fw use weighted observation counts if "`wtype'" == "iweight" | "`wtype'" == "fweight" { qui by `ivar' `touse': gen long `T_i' = sum(`wvar') if `touse' } else { qui by `ivar' `touse': gen long `T_i' = _N if `touse' } qui by `ivar' `touse': replace `T_i' = . if _n~=_N qui count if `T_i' < . local allvars "`depvar' `endo' `inexog' `exexog'" foreach var of local allvars { tempvar `var'_m // To get weighted means qui by `ivar' `touse' : gen double ``var'_m'=sum(`var'*`wvar')/sum(`wvar') if `touse' qui by `ivar' `touse' : replace ``var'_m'=``var'_m'[_N] if `touse' & _n<_N // This guarantees that the demeaned variables are doubles qui by `ivar' `touse' : replace ``var'_m'=`var'-``var'_m'[_N] if `touse' drop `var' rename ``var'_m' `var' } } // end within transform // GLS transformation for RE models if "`xtmodel'" == "g2sls" | "`xtmodel'" == "ec2sls" { foreach vlist in depvar endo inexog exexog { fvrevar ``vlist'' if `touse' local `vlist' `r(varlist)' } tempvar i_obs theta sort `ivar' `touse' qui by `ivar': egen `i_obs'=count(`touse') if `touse' qui sum `i_obs' if `touse' local balanced = (r(min)==r(max)) qui gen double `theta' = 1 - sqrt( `sig_e2'/(`sig_u2'*`i_obs' +`sig_e2' ) ) if `touse' if `cons' { tempvar __cons qui gen double `__cons' = 1 -`theta' if `touse' } tempvar mean qui by `ivar' `touse': gen double `mean'=sum(`depvar') if `touse' qui by `ivar' `touse': replace `mean' =`mean'[_N]/_N if `touse' recast double `depvar' qui replace `depvar' =`depvar'-`theta'*`mean' foreach var of varlist `endo' { tempvar mean qui by `ivar' `touse': gen double `mean'=sum(`var') if `touse' qui by `ivar' `touse': replace `mean' =`mean'[_N]/_N if `touse' recast double `var' qui replace `var' =`var'-`theta'*`mean' } if "`inexog'" ~= "" { foreach var of varlist `inexog' { tempvar mean omean dm gls qui sum `var' if `touse', meanonly scalar `omean'=r(mean) qui by `ivar' `touse': gen double `mean'=sum(`var') if `touse' qui by `ivar' `touse': replace `mean' =`mean'[_N]/_N if `touse' // Don't add group-invariant vars to m OR dm lists - causes collinearity problems qui sum `mean' if `touse' if r(sd) ~= 0 { local inexog_m "`inexog_m' `mean'" tempvar dm qui gen double `dm' = `var' - `mean' + `omean' if `touse' // Don't add time-invariant vars to dm list if balanced - causes collinearity problems // nb: can also cause collinearity in SOME unbalanced panels, e.g., 2 time-invariant vars, but OK qui sum `dm' if `touse' if ~`balanced' | r(sd) ~= 0 { local inexog_dm "`inexog_dm' `dm'" } } recast double `var' qui replace `var' =`var'-`theta'*`mean' } } foreach var of varlist `exexog' { tempvar mean omean dm gls qui sum `var' if `touse', meanonly scalar `omean'=r(mean) qui by `ivar' `touse': gen double `mean'=sum(`var') if `touse' qui by `ivar' `touse': replace `mean' =`mean'[_N]/_N if `touse' // Don't add group-invariant vars to m list - causes collinearity problems qui sum `mean' if `touse' if r(sd) ~= 0 { local exexog_m "`exexog_m' `mean'" } qui gen double `dm' = `var' - `mean' + `omean' if `touse' // Don't add time-invariant vars to dm list if balanced panel - causes collinearity problems qui sum `dm' if `touse' if ~`balanced' | (r(sd) ~= 0) { local exexog_dm "`exexog_dm' `dm'" } recast double `var' qui replace `var' =`var'-`theta'*`mean' } local cons 0 local noconstant noconstant if "`xtmodel'"=="g2sls" { local inexog `inexog' `__cons' } if "`xtmodel'"=="ec2sls" { if `repstataflag' & ~`balanced' { // strange but true - if unbalanced, to replicate // official xtivreg treat inexog as endogenous local endo `inexog' `endo' local inexog `__cons' local exexog `exexog_dm' `exexog_m' `inexog_dm' `inexog_m' } else if `balanced' | ~`usemeansflag' { // default behavior // for balanced panels, can use inexog_dm or inexog_m // for unbalanced panels, default is to use inexog_dm local inexog `inexog' `__cons' local exexog `exexog_dm' `exexog_m' `inexog_dm' } else if `usemeansflag' { // for unbalanced panels, use inexog_m instead of inexog_dm local inexog `inexog' `__cons' local exexog `exexog_dm' `exexog_m' `inexog_m' } else { di as err "internal underid error after ec2sls" exit 198 } } } // Hausman-Taylor-type RE models if "`xtmodel'" == "htaylor" | "`xtmodel'" == "amacurdy" { foreach vlist in depvar TVexog TVendo TIexog TIendo { fvrevar ``vlist'' if `touse' local `vlist' `r(varlist)' } tempvar i_obs theta sort `ivar' `touse' qui by `ivar' `touse': egen `i_obs'=count(`touse') if `touse' qui sum `i_obs' if `touse' local balanced = (r(min)==r(max)) qui gen double `theta' = 1 - sqrt( `sig_e2'/(`sig_u2'*`i_obs' +`sig_e2' ) ) if `touse' if `cons' { tempvar __cons qui gen double `__cons' = 1 -`theta' if `touse' } local cons 0 local noconstant noconstant // Dep var tempvar mean qui by `ivar' `touse': gen double `mean'=sum(`depvar') if `touse' qui by `ivar' `touse': replace `mean' =`mean'[_N]/_N if `touse' recast double `depvar' qui replace `depvar' = `depvar'-`theta'*`mean' // Time-varying exog => demeaned and mean (HT) // => demeaned and current/leads/lags (AM) (balanced panels only) // do this first, before transforming TVexog if "`xtmodel'" == "amacurdy" { if "`TVexog'"~="" { sort `ivar' `touse' `tvar' foreach var of varlist `TVexog' { forvalues i = 1/`Tbar' { tempvar t qui by `ivar' `touse': gen double `t'=`var'[`i'] if `touse' // Don't add group-invariant vars to t list - causes collinearity problems qui sum `t' if `touse' if r(sd) ~= 0 { local TVexog_t "`TVexog_t' `t'" } } } } } if "`TVexog'"~="" { foreach var of varlist `TVexog' { tempvar mean qui by `ivar' `touse': gen double `mean'=sum(`var') if `touse' qui by `ivar' `touse': replace `mean' =`mean'[_N]/_N if `touse' // Don't add group-invariant vars to m list - causes collinearity problems qui sum `mean' if `touse' if r(sd) ~= 0 { local TVexog_m "`TVexog_m' `mean'" } tempvar dm qui gen double `dm' = `var' - `mean' if `touse' // Don't add group-invariant vars to dm list if balanced - causes collinearity problems if ~`balanced' | r(sd) ~= 0 { local TVexog_dm "`TVexog_dm' `dm'" } recast double `var' qui replace `var' = `var'-`theta'*`mean' if `touse' } } // TVendo => demeaned and gls only if "`TVendo'"~="" { foreach var of varlist `TVendo' { tempvar mean qui by `ivar' `touse': gen double `mean'=sum(`var') if `touse' qui by `ivar' `touse': replace `mean' =`mean'[_N]/_N if `touse' tempvar dm qui gen double `dm' = `var' - `mean' if `touse' local TVendo_dm "`TVendo_dm' `dm'" recast double `var' qui replace `var' = `var'-`theta'*`mean' if `touse' } } // TIexog are rescaled by theta but also need original // ... but since time-invariant, same thing as TIexog_m if "`TIexog'"~="" { foreach var of varlist `TIexog' { tempvar orig qui gen double `orig' = `var' local TIexog_m `TIexog_m' `orig' qui recast double `var' qui replace `var' = `var'-`theta'*`var' if `touse' } } // TIendo are rescaled by theta if "`TIendo'"~="" { foreach var of varlist `TIendo' { recast double `var' qui replace `var' = `var'-`theta'*`var' if `touse' } } if "`xtmodel'" == "htaylor" { if `repstataflag' & ~`balanced' { // strange but true - if unbalanced, to replicate // official xthtaylor treat inexog as endogenous local inexog `__cons' local endo `TVendo' `TIendo' `TVexog' `TIexog' local exexog `TVendo_dm' `TVexog_dm' `TVexog_m' `TIexog_m' } else if `balanced' | ~`usemeansflag' { // default behavior // for balanced panels, can use TVexog_dm or TVexog_m // for unbalanced panels, default is to use TVexog_dm local inexog `TVexog' `TIexog' `__cons' local endo `TVendo' `TIendo' local exexog `TVendo_dm' `TVexog_dm' } else if `usemeansflag' { // for unbalanced panels, use TVexog_m instead of TVexog_dm local inexog `TVexog' `TIexog' `__cons' local endo `TVendo' `TIendo' local exexog `TVendo_dm' `TVexog_m' } else { di as err "internal underid error after xthtaylor" exit 198 } } else if "`xtmodel'" == "amacurdy" { local inexog `TVexog' `TIexog' `__cons' local endo `TVendo' `TIendo' local exexog `TVexog_t' `TVendo_dm' } else { di in red "error: unknown model `xtmodel'" exit 198 } } // special treatment for xtabond2 // xtabond2 settings: // xtmodel = diff, lev or sys // transform = first differences or orthogonal deviations // flags: haslevel, uselevel, hasdiff, usediff, clustflag // cluster-robust required // no H matrix is equivalent to H=I // just diff w/FD, h(1): no H matrix // just diff w/FD, h(2) or h(3): use H matrix // just diff w/OD: no H matrix // just lev: no H matrix // sys = FD + lev, h(1): no H matrix // h(2) or h(3): use H matrix // sys = OD + lev, h(1) or h(2): no H matrix // h(3): use H matrix if "`cmd'"=="xtabond2" { if `clustflag'==0 { di as err "Error: underid supports xtabond2 with a cluster-robust VCE only" exit 198 } local xtabond2options ivar(`panelvar') if "`transform'"=="first differences" & `h'>=2 { local xtabond2options `xtabond2options' h(`H') hvar(`hvar') } if "`transform'"=="orthogonal deviations" & `uselevel' & `h'==3 { local xtabond2options `xtabond2options' h(`H') hvar(`hvar') } } // special treatment for wtexp macro. // if empty and [] is provided to _rmcollright, it crashes. // need it to be COMPLETELY empty. if "`wtexp'"=="[]" { local wtexp } *************************************************************************************************** // Counts local nendog : word count `endo' local nexexog : word count `exexog' local ninexog : word count `inexog' // Count modified to include constant if appropriate local ninexog = `ninexog' + `cons' local nexog = `nexexog' + `ninexog' // Error checking if "`endo'"=="" { di as err "error - no endogenous regressors specified" exit 198 } if `debugflag' { di "model: `model'" di "xtmodel: `xtmodel'" di "vceopt: `vceopt'" di "cons: `cons'" di "cons var: `__cons'" di "nocons: `noconstant'" di "depvar: `depvar'" di "inexog: `inexog'" di "endo: `endo'" di "todrop: `todrop'" di "exexog: `exexog'" di "clustvar: `clustvar'" di "clustvar1: `clustvar1'" di "clustvar2: `clustvar2'" di "robust: `robust'" di "kernel: `kernel'" di "bw: `bw'" di "nendog: `nendog'" di "ninexog: `ninexog'" di "nexexog: `nexexog'" di "wtexp: `wtexp'" di "wtype: `wtype'" di "dofminus: `dofminus'" di "ivar: `ivar'" di "panelvar: `panelvar'" foreach vlist in depvar endo inexog exexog { di "`vlist':" if "``vlist''"~="" { sum ``vlist'' if `touse' } } if "`clustvar'" ~= "" { sum `clustvar' if `touse' } } // maineq option di // used with ivreg2 only: partial-out included exogenous unless otherwise specificed if `nopartialflag' == 0 { local partialinexog "partial(`inexog')" } if "`maineqn'" == "iv" { // Store IV estimation for later restore. tempname ivestimate _estimates hold `ivestimate', restore di as text "MAIN EQUATION USING IVREG2 AND RETRIEVED DATA: BASIC IV" ivreg2 `depvar' (`endo' = `exexog') `inexog' `wtexp' if `touse' /// , /// `vceopt' /// `noconstant' /// `partialinexog' /// `ecenter' /// center option specified in original eqn `esmall' /// small option specified in original eqn dofminus(`dofminus') di _estimates unhold `ivestimate' } else if "`maineqn'" == "gmm2s" { // Store IV estimation for later restore. tempname ivestimate _estimates hold `ivestimate', restore di as text "MAIN EQUATION USING IVREG2 AND RETRIEVED DATA: TWO-STEP GMM" ivreg2 `depvar' (`endo' = `exexog') `inexog' `wtexp' if `touse' /// , /// `vceopt' /// `noconstant' /// gmm2s /// `partialinexog' /// `ecenter' /// center option specified in original eqn `esmall' /// small option specified in original eqn dofminus(`dofminus') di _estimates unhold `ivestimate' } else if "`maineqn'" == "cue" { // Store IV estimation for later restore. tempname ivestimate _estimates hold `ivestimate', restore di as text "MAIN EQUATION USING IVREG2 AND RETRIEVED DATA: CUE GMM" di as text " (with included exog partialled out)" ivreg2 `depvar' (`endo' = `exexog') `inexog' `wtexp' if `touse' /// , /// `vceopt' /// `noconstant' /// partial(`inexog') /// `ecenter' /// center option specified in original eqn `esmall' /// small option specified in original eqn cue /// dofminus(`dofminus') di _estimates unhold `ivestimate' } else if "`maineqn'" ~= "" { di as err "overid error: unknown estimation method `maineqn'" exit 198 } ****************************** overid and underid ********************************************** // used in all ranktest calls - augment user-supplied rkopt macro local rkopt `rkopt' `wald' `small' // special treatment for xtabond2 + KP stat; requires ranktest option nosvd // option ignored by ranktest if rkstat is not KP if "`rkstat'"=="kp" & "`cmd'"=="xtabond2" { local hasnosvd : list posof "nosvd" in rkopt if ~`hasnosvd' { // nosvd is not in the options for ranktest, so add it local rkopt `rkopt' nosvd } } // special treatment for partialling-out // default: vlist_1 = dep var, endo // vlist_2 = exexog // plist = inexog (and constant IMplicit if present) // nopartial: vlist_1 = dep var, endo, inexog and explicit constant if present // vlist_2 = exexog, inexog and EXplicit constant if present // hence we require adjustment to both varlists AND the constant option // SW treated separately if `nopartialflag' { if `cons' { tempname one qui gen byte `one'=1 } local pinlist `inexog' `one' local poutlist local pnocons noconstant } else { local pinlist local poutlist `inexog' local pnocons `noconstant' } if `swnopartialflag' { if `cons' { tempname swone qui gen byte `swone'=1 } local swpinlist `inexog' `swone' local swpoutlist local swpnocons noconstant } else { local swpinlist local swpoutlist `inexog' local swpnocons `noconstant' } if `collincheckflag' { local XZ `inexog' `exexog' local YX `endo' `inexog' // bug in _rmcollright - if wtexp is just [] is sent, _rmcollright can crash // need it to be completely empty, hence fix above at end of collecting options qui _rmcollright `XZ' `wtexp' if `touse', `noconstant' local XZdropped `r(dropped)' local XZdflag ="`XZdropped'"~="" local XZtilde : list XZ - XZdropped qui _rmcollright `YX' `wtexp' if `touse', `noconstant' local YXdropped `r(dropped)' local YXdflag ="`YXdropped'"~="" local YXtilde : list YX - YXdropped local YXZtilde `YXtilde' `XZtilde' local YXZtilde : list uniq YXZtilde qui _rmcollright `YXZtilde' `wtexp' if `touse', `noconstant' local YXZdropped `r(dropped)' local YXZdflag ="`YXZdropped'"~="" local XZYtilde `XZtilde' `YXtilde' local XZYtilde : list uniq XZYtilde qui _rmcollright `XZYtilde' `wtexp' if `touse', `noconstant' local XZYdropped `r(dropped)' local XZYdflag ="`XZYdropped'"~="" if `XZdflag' | `YXdflag' | `YXZdflag' | `XZYdflag' { di as text "collinearity check..." } if `XZdflag' { di as text "collinearities detected in [X Z] (right to left): `XZdropped'" } if `YXdflag' { di as text "collinearities detected in [Y X] (right to left): `YXdropped'" } if `YXZdflag' { di as text "collinearities detected in [Y X Z] (right to left): `YXZdropped'" } if `XZYdflag' { di as text "collinearities detected in [X Z Y] (right to left): `XZYdropped'" } if `XZdflag' | `YXdflag' | `YXZdflag' | `XZYdflag' { di as text "warning: collinearities detected, reparameterization may be advisable" di } } if `overidflag' { local overid_options /// `rkstat' /// full /// `vceopt' /// `rkopt' /// `center' /// `xtabond2options' /// dofminus(`dofminus') local overid_options : list clean overid_options `qui' di as text "Calling ranktest to obtain overid statistic..." `qui' di as text "Options passed to ranktest: `overid_options'" `qui' ranktest /// (`depvar' `endo' `pinlist') /// (`exexog' `pinlist') /// `wtexp' if `touse', /// partial(`poutlist') /// `pnocons' /// `overid_options' if `debugflag' { return list } `qui' di tempname j_oid p_oid b_oid b0_oid S_oid V_oid local N = r(N) local N_clust = r(N_clust) scalar `j_oid' = r(chi2) scalar `p_oid' = r(p) local df_oid = r(df) local testdesc `r(testdesc)' local vcedesc1 `r(vcedesc1)' local vcedesc2 `r(vcedesc2)' local vcedesc3 `r(vcedesc3)' mat `b_oid' = r(b) mat `b0_oid' = r(b0) mat `S_oid' = r(S) mat `V_oid' = r(V) if `nopartialflag' & `cons' { local cnames : colnames `b_oid' local cnames : subinstr local cnames "`one'" "_cons" mat colnames `b_oid' = `cnames' mat colnames `b0_oid' = `cnames' mat colnames `V_oid' = `cnames' mat rownames `V_oid' = `cnames' local cnames : colnames `S_oid' local cnames : subinstr local cnames "`one'" "_cons" mat colnames `S_oid' = `cnames' mat rownames `S_oid' = `cnames' } // check that original equation wasn't exactly identified if r(K1)>r(K2) { // was exactly identified, so replace J with zero etc. scalar `j_oid' = 0 scalar `p_oid' = 1 local df_oid = 0 } di as text "Overidentification test: `testdesc'" if "`vcedesc1'"~="" { di as text " `vcedesc1'" } if "`vcedesc2'"~="" { di as text " `vcedesc2'" } if "`vcedesc3'"~="" { di as text " `vcedesc3'" } di as text "j=" as res %8.2f `j_oid' as text " Chi-sq(" as res %3.0f `df_oid' as text ") p-value=" as res %6.4f `p_oid' _c if `df_oid'==0 { di as text " (equation exactly identified)" } else { di } } if `underidflag' { if `overidflag' { di // blank line to separate from overid } local underid_options /// `rkstat' /// full /// `vceopt' /// `rkopt' /// `center' /// `xtabond2options' /// dofminus(`dofminus') `qui' di as text "Calling ranktest to obtain underid statistic..." `qui' di as text "Options passed to ranktest: `underid_options'" `qui' ranktest /// (`endo' `pinlist') /// (`exexog' `pinlist') /// `wtexp' if `touse', /// partial(`poutlist') /// `pnocons' /// `underid_options' if `debugflag' { return list } `qui' di tempname j_uid p_uid K L b_uid b0_uid S_uid V_uid local N = r(N) local N_clust = r(N_clust) scalar `j_uid' = r(chi2) scalar `p_uid' = r(p) local df_uid = r(df) scalar `K' = r(K) scalar `L' = r(L) local testdesc `r(testdesc)' local vcedesc1 `r(vcedesc1)' local vcedesc2 `r(vcedesc2)' local vcedesc3 `r(vcedesc3)' mat `b_uid' = r(b) mat `b0_uid' = r(b0) mat `S_uid' = r(S) mat `V_uid' = r(V) if `nopartialflag' & `cons' { local cnames : colnames `b_uid' local cnames : subinstr local cnames "`one'" "_cons" mat colnames `b_uid' = `cnames' mat colnames `b0_uid' = `cnames' mat colnames `V_uid' = `cnames' mat rownames `V_uid' = `cnames' local cnames : colnames `S_uid' local cnames : subinstr local cnames "`one'" "_cons" mat colnames `S_uid' = `cnames' mat rownames `S_uid' = `cnames' } di as text "Underidentification test: `testdesc'" if "`vcedesc1'"~="" { di as text " `vcedesc1'" } if "`vcedesc2'"~="" { di as text " `vcedesc2'" } if "`vcedesc3'"~="" { di as text " `vcedesc3'" } di as text "j=" as res %8.2f `j_uid' as text " Chi-sq(" as res %3.0f `df_uid' as text ") p-value=" as res %6.4f `p_uid' // swflag = jgmm2s, regressor-by-regressor // always use xtabond2 options if available if `swflag' & `K'>1 { tempname umat local nendo : word count `endo' if `jgmm2sflag' { // no need to repeat results for first regressor mat `umat' = (`j_uid', `p_uid') // set up loop for other endog gettoken v1 vrest : endo local vlist `vrest' `v1' local firstvar 2 } else { local vlist `endo' local firstvar 1 } local sw_options /// jgmm2s /// force jgmm2s full /// `vceopt' /// `rkopt' /// `center' /// `xtabond2options' /// dofminus(`dofminus') forvalues i=`firstvar'/`nendo' { gettoken v1 vrest : vlist `qui' di as text "Calling ranktest to obtain jgmm2s underid statistic with first var=`v1'..." _c `qui' di as text "Options passed to ranktest: `sw_options'" `qui' ranktest /// (`v1' `vrest' `swpinlist') /// (`exexog' `swpinlist') /// `wtexp' if `touse', /// partial(`swpoutlist') /// `swpnocons' /// `sw_options' mat `umat' = nullmat(`umat') \ (`r(chi2)', `r(p)') local vlist `vrest' `v1' } mat colnames `umat' = chi2 p mat rownames `umat' = `endo' di di as text "2-step GMM J underidentification stats by regressor:" tokenize `endo' forvalues i=1/`nendo' { di as text "j=" as res %8.2f el(`umat',`i',1) /// as text " Chi-sq(" as res %3.0f `df_uid' /// as text ") p-value=" as res %6.4f el(`umat',`i',2) /// as text _col(40) "``i''" } } } ******************* estimations complete ************************************************ return scalar N = `N' if `N_clust'~=. { return scalar N_clust = `N_clust' } if `overidflag' { return scalar j_oid = `j_oid' return scalar p_oid = `p_oid' return scalar df_oid = `df_oid' if `b_oid'[1,1] ~= . { return matrix b0_oid = `b0_oid' return matrix S_oid = `S_oid' return matrix V_oid = `V_oid' return matrix b_oid = `b_oid' } } if `underidflag' { return scalar j_uid = `j_uid' return scalar p_uid = `p_uid' return scalar df_uid = `df_uid' if `swflag' & `K'>1 { return mat sw_uid = `umat' } if `b_uid'[1,1] ~= . { return matrix b0_uid = `b0_uid' return matrix S_uid = `S_uid' return matrix V_uid = `V_uid' return matrix b_uid = `b_uid' } } return local vceopt `vceopt' return local rkstat `rkstat' return local rkopt `rkopt' end // end underid ******************************************************************************** program define get_model_specs, rclass version 13.1 syntax [ , /// esample(varname) /// specifically refers to original estimation sample touse(varname) /// may refer to created sample with more obs as in xtabond2 wvar(varname) /// EQxtabond2(string) /// specific to xtabond2 keepall /// specific to xtabond2 debugflag(int 0) /// * /// ] return clear // Need to pass `wvar' so that values saved in e(wt) can be assigned to it if "`e(cmd)'" == "xtabond2" { // require matafavor = speed if c(matafavor) ~= "speed" { di as err "error: support for xtabond2 requires matafavor to be set to speed" di as err " see {help mata_set:help mata set}" exit 198 } make_xtabond2_data, wvar(`wvar') touse(`touse') eq(`eqxtabond2') `keepall' debugflag(`debugflag') } if "`e(cmd)'"=="xtdpdgmm" { make_xtdpdgmm_data, touse(`touse') wvar(`wvar') debugflag(`debugflag') } if "`e(cmd)'"=="ivreg2" | "`e(cmd)'"=="ivreg2h" { parse_ivreg2, touse(`touse') wvar(`wvar') } if "`e(cmd)'"=="ivregress" { parse_ivregress, touse(`touse') wvar(`wvar') } if "`e(cmd)'"=="xtivreg2" { parse_xtivreg2, touse(`touse') wvar(`wvar') } if "`e(cmd)'"=="xtivreg" { parse_xtivreg, touse(`touse') wvar(`wvar') } if "`e(cmd)'"=="xthtaylor" { parse_xthtaylor, touse(`touse') wvar(`wvar') } // Assemble options spec for vce calc by avar // `cluster' = "cluster( )" // `clustvar' = "`clustvar1' `clustvar2'" local vceopt "`r(robust)' `r(cluster)' bw(`r(bw)') kernel(`r(kernel)') `r(psd)'" return add return local cmd "`e(cmd)'" return local vceopt "`vceopt'" end // end get_model_specs program define parse_ivreg2, rclass version 13.1 syntax [ , /// touse(varname) /// wvar(varname) /// ] if `e(endog_ct)'==0 { di as err "error - no endogenous regressors in IV estimation" exit 198 } qui replace `touse'=e(sample) if "`e(wexp)'"~="" { qui replace `wvar' `e(wexp)' } local kernel `e(kernel)' local bw `e(bw)' if "`e(vcetype)'"=="Robust" { local robust robust } if "`e(clustvar)'"~="" { // enter if 1- or 2-way clustering local cluster cluster(`e(clustvar)') // = "cluster( )" local clustvar `e(clustvar)' // = (1- or 2-way clustering) if "`e(clustvar1)'"=="" { local clustvar1 `clustvar' // 1-way clustering } else { local clustvar1 `e(clustvar1)' // var1 of 2-way clustering } if "`e(clustvar2)'"~="" { // 2-way clustering local clustvar2 `e(clustvar2)' } } local cons = e(cons) + e(partialcons) // spec of ORIGINAL model, not after cons possibly partialled out if ~`cons' { local noconstant noconstant } local small `e(small)' local depvar `e(depvar)' local endo `e(instd)' local inexog `e(inexog)' local exexog `e(exexog)' if e(center) { local center center } // ivreg2h generated instruments if "`e(cmd)'"=="ivreg2h" { local exexog `exexog' `e(geninsts)' } // ivreg2h panel option(s) not currently supported if "`e(cmd)'"=="ivreg2h" & "`e(xtmodel)'"~="" { di as err "Error: ivreg2h panel-data estimation not currently supported" exit 601 } // misc if "`e(vce'"=="psd0" | "`e(vce'"=="psda" { local psd `e(vce)' } * Return values return local depvar `depvar' return local endo `endo' return local inexog `inexog' return local exexog `exexog' return scalar N = e(N) return scalar N_clust = e(N_clust) // in case of 2-way clustering, N_clust=min(N_clust1,N_clust2) return scalar N_clust1 = e(N_clust1) return scalar N_clust2 = e(N_clust2) return local cluster `cluster' // = "cluster( )" return local clustvar `clustvar' // = = list of cluster variables (can be 1 or 2) return local clustvar1 `clustvar1' // = return local clustvar2 `clustvar2' // = return local kernel `kernel' return local bw `bw' return scalar dofminus = e(dofminus) return local psd `psd' return scalar cons = `cons' return local noconstant `noconstant' return local small `small' return local robust `robust' return local wtype `e(wtype)' return local wexp `e(wexp)' return local wtexp [`e(wtype)'`e(wexp)'] return local center `center' if "`model'"=="gmm2s" { return local gmm2s gmm2s } end // end parse_ivreg2 program define parse_xtivreg2, rclass version 13.1 syntax [ , /// touse(varname) /// wvar(varname) /// ] local xtmodel "`e(xtmodel)'" if "`xtmodel'"~="fe" & "`xtmodel'"~="fd" { di as err "error - only FE and FD estimation supported with xtivreg2" exit 198 } // Most of the parsing is done by parse_ivreg2 parse_ivreg2, touse(`touse') wvar(`wvar') if "`xtmodel'"=="fe" { local singleton "`e(singleton)'" } else { local singleton =0 } // Add macros to those returned by parse_ivreg2 return add return local singleton `singleton' return local xtmodel `xtmodel' return local ivar `e(ivar)' return scalar N_g = e(N_g) return scalar g_min = e(g_min) return scalar g_max = e(g_max) return scalar g_avg = e(g_avg) return scalar dofminus = e(dofminus) // For iid FE case sigmas, adjustment for #groups needed end // end parse_xtivreg2 program define parse_xtivreg, rclass version 13.1 syntax [ , /// touse(varname) /// wvar(varname) /// ] qui replace `touse'=e(sample) if "`e(wexp)'"~="" { qui replace `wvar' `e(wexp)' } local xtmodel `e(model)' if "`xtmodel'"=="fe" { local dofminus = e(N_g) // For iid FE case sigmas, adjustment for #groups needed } else { local dofminus = 0 } // xtivreg uses small-sample adjustment; "small" option changes only z or t etc. local small "small" // Bizarrely, xtivreg,fd puts a D operator in front of depvar but nowhere else local depvar "`e(depvar)'" tsunab depvar : `depvar' if "`xtmodel'"=="fd" { local endo "d.(`e(instd)')" tsunab endo : `endo' local insts "d.(`e(insts)')" tsunab insts : `insts' } else { local endo "`e(instd)'" tsunab endo : `endo' local insts "`e(insts)'" tsunab insts : `insts' } // Full colnames have TS operators in front of them already local x : colfullnames(e(b)) local x : subinstr local x "_cons" "", count(local cons) local inexog : list x - endo local exexog : list insts - inexog // Exog to include in tests ... but check first local check : list tinexog - inexog local check : word count `check' if `check' > 0 { di as err "syntax error - variable listed in testexog(.) but not in exogenous regressors" exit 198 } local inexog : list inexog - tinexog // remove from inexog and add to endo local endo : list endo | tinexog local exexog : list exexog | tinexog if "`xtmodel'"=="fe" { // We impose no constant in FE model local cons =0 // Overrides cons created by count above } if ~`cons' { local noconstant "noconstant" } tokenize `e(vce)' if "`e(vce)'" == "robust" { local robust "robust" } if "`e(clustvar)'"~="" { // 1-way clustering local cluster "cluster(`e(clustvar)')" // = "cluster( )" local clustvar1 "`e(clustvar)'" // = local robust "robust" // cluster=>robust } // Return values return local tvar `e(tvar)' return local ivar `e(ivar)' return local depvar `depvar' return local endo `endo' return local inexog `inexog' return local exexog `exexog' return local cons = `cons' return local noconstant `noconstant' return local small `small' return local robust `robust' return local cluster `cluster' // = "cluster( )" return local clustvar `clustvar' // = = list of cluster variables (can be 1 or 2) return local clustvar1 `clustvar1' // = return scalar N = e(N) return scalar dofminus = `dofminus' return scalar N_g = e(N_g) return scalar g_min = e(g_min) return scalar g_max = e(g_max) return scalar g_avg = e(g_avg) return scalar Tbar = e(Tbar) return local xtmodel `xtmodel' return scalar sig_e2 = (e(sigma_e))^2 return scalar sig_u2 = (e(sigma_u))^2 ******* zeros by default or if not supported ******** return local singleton =0 end // end parse_xtivreg program define parse_xthtaylor, rclass version 13.1 syntax [ , /// touse(varname) /// wvar(varname) /// ] qui replace `touse'=e(sample) if "`e(wexp)'"~="" { qui replace `wvar' `e(wexp)' } if "`e(title)'"=="Amemiya-MaCurdy" { local xtmodel amacurdy } else { local xtmodel htaylor } local dofminus = 0 local depvar `e(depvar)' local TVexog `e(TVexogenous)' local TVendo `e(TVendogenous)' local TIexog `e(TIexogenous)' local TIendo `e(TIendogenous)' // Full colnames have TS operators in front of them already local x : colfullnames(e(b)) local x : subinstr local x "_cons" "", count(local cons) if ~`cons' { local noconstant "noconstant" } tokenize `e(vce)' if "`e(vce)'" == "robust" { local robust "robust" } if "`e(clustvar)'"~="" { // 1-way clustering local cluster cluster(`e(clustvar)') // = "cluster( )" local clustvar1 `e(clustvar)' // = local robust robust // cluster=>robust } // Return values return local tvar `e(tvar)' return local ivar `e(ivar)' return local depvar `depvar' return local endo `endo' return local TVexog `TVexog' return local TVendo `TVendo' return local TIexog `TIexog' return local TIendo `TIendo' return local cons = `cons' return local noconstant `noconstant' return local small `small' return local robust `robust' return local cluster `cluster' // = "cluster( )" return local clustvar `clustvar' // = = list of cluster variables (can be 1 or 2) return local clustvar1 `clustvar1' // = return scalar N = e(N) return scalar dofminus = `dofminus' return scalar N_g = e(N_g) return scalar g_min = e(g_min) return scalar g_max = e(g_max) return scalar g_avg = e(g_avg) return scalar Tbar = e(Tbar) return local xtmodel `xtmodel' return scalar sig_e2 = (e(sigma_e))^2 return scalar sig_u2 = (e(sigma_u))^2 ******* zeros by default or if not supported ******** return local singleton =0 end // end parse_xthtaylor program define parse_ivregress, rclass version 13.1 syntax [ , /// touse(varname) /// wvar(varname) /// ] qui replace `touse'=e(sample) if "`e(wexp)'"~="" { qui replace `wvar' `e(wexp)' } tokenize `e(vce)' if "`1'" == "hac" { local kernel "`e(hac_kernel)'" local bw =`3'+1 local robust "robust" } if "`e(vce)'" == "robust" { local robust "robust" } if "`e(clustvar)'"~="" { // 1-way clustering local cluster "cluster(`e(clustvar)')" // = "cluster( )" local clustvar1 "`e(clustvar)'" // = local robust "robust" // cluster=>robust } if "`e(moments)'"=="centered" { local center center } local noconstant `e(constant)' local cons = ~("`noconstant'"=="noconstant") local small `e(small)' local depvar `e(depvar)' local endo `e(instd)' local inexog `e(exogr)' local insts `e(insts)' local exexog : list insts - inexog // Return values return local depvar `depvar' return local endo `endo' return local inexog `inexog' return local exexog `exexog' return local cluster `cluster' // = "cluster( )" return local clustvar `clustvar1' // = return local clustvar1 `clustvar1' // = return local kernel `kernel' return local bw `bw' return scalar N = e(N) return scalar N_clust = e(N_clust) return scalar dofminus = 0 return local cons = `cons' return local noconstant `noconstant' return local small `small' return local robust `robust' return local wtype `e(wtype)' return local wexp `e(wexp)' return local wtexp [`e(wtype)'`e(wexp)'] return local center `center' end // end parse_ivregress ******************************************************************************* ******************************************************************************* ************************* misc utilities ************************************** ******************************************************************************* // internal version of fvstrip 1.01 ms 24march2015 // identical to ivreg2_fvstrip in ivreg2 4.1.01 // takes varlist with possible FVs and strips out b/n/o notation // returns results in r(varnames) // optionally also omits omittable FVs // expand calls fvexpand either on full varlist // or (with onebyone option) on elements of varlist program define fvstrip, rclass version 12.1 syntax [anything] [if] , [ dropomit expand onebyone NOIsily ] if "`expand'"~="" { // force call to fvexpand if "`onebyone'"=="" { fvexpand `anything' `if' // single call to fvexpand local anything `r(varlist)' } else { foreach vn of local anything { fvexpand `vn' `if' // call fvexpand on items one-by-one local newlist `newlist' `r(varlist)' } local anything : list clean newlist } } foreach vn of local anything { // loop through varnames if "`dropomit'"~="" { // check & include only if _ms_parse_parts `vn' // not omitted (b. or o.) if ~`r(omit)' { local unstripped `unstripped' `vn' // add to list only if not omitted } } else { // add varname to list even if local unstripped `unstripped' `vn' // could be omitted (b. or o.) } } // Now create list with b/n/o stripped out foreach vn of local unstripped { local svn "" // initialize _ms_parse_parts `vn' if "`r(type)'"=="variable" & "`r(op)'"=="" { // simplest case - no change local svn `vn' } else if "`r(type)'"=="variable" & "`r(op)'"=="o" { // next simplest case - o.varname => varname local svn `r(name)' } else if "`r(type)'"=="variable" { // has other operators so strip o but leave . local op `r(op)' local op : subinstr local op "o" "", all local svn `op'.`r(name)' } else if "`r(type)'"=="factor" { // simple factor variable local op `r(op)' local op : subinstr local op "b" "", all local op : subinstr local op "n" "", all local op : subinstr local op "o" "", all local svn `op'.`r(name)' // operator + . + varname } else if"`r(type)'"=="interaction" { // multiple variables forvalues i=1/`r(k_names)' { local op `r(op`i')' local op : subinstr local op "b" "", all local op : subinstr local op "n" "", all local op : subinstr local op "o" "", all local opv `op'.`r(name`i')' // operator + . + varname if `i'==1 { local svn `opv' } else { local svn `svn'#`opv' } } } else if "`r(type)'"=="product" { di as err "ivreg2_fvstrip error - type=product for `vn'" exit 198 } else if "`r(type)'"=="error" { di as err "ivreg2_fvstrip error - type=error for `vn'" exit 198 } else { di as err "ivreg2_fvstrip error - unknown type for `vn'" exit 198 } local stripped `stripped' `svn' } local stripped : list retokenize stripped // clean any extra spaces if "`noisily'"~="" { // for debugging etc. di as result "`stripped'" } return local varlist `stripped' // return results in r(varlist) end * Utility to provide matching names. * varnames is list of names to look up. * namelist1 is where the names are looked for. * namelist2 has the corresponding names that are selected/returned. program define matchnames, rclass version 12.1 args varnames namelist1 namelist2 local k1 : word count `namelist1' local k2 : word count `namelist2' /* if `k1' ~= `k2' { di as err "namelist error - lengths of two lists do not match" exit 198 } */ foreach vn in `varnames' { local i : list posof `"`vn'"' in namelist1 if `i' > 0 { local newname : word `i' of `namelist2' } else { * Keep old name if not found in list local newname "`vn'" } local names "`names' `newname'" } local names : list clean names return local names "`names'" end * Utility to list varnames program define Disp version 8.2 syntax [anything] [, _col(integer 15) ] local len = 80-`_col'+1 local piece : piece 1 `len' of `"`anything'"' local i 1 while "`piece'" != "" { di in gr _col(`_col') "`first'`piece'" local i = `i' + 1 local piece : piece `i' `len' of `"`anything'"' } if `i'==1 { di } end // Utility for creating xtabond2-transformed data * make_xtabond2_data version 1.00.01 2jul2020 * author mes program define make_xtabond2_data, rclass version 12.1 syntax [ , /// wvar(name) /// touse(name) /// will refer to created sample with more obs panelvar(name) /// eqvar(name) /// timevar(name) /// hvar(name) /// consvar(name) /// cluster(namelist) /// keepall /// eq(string) /// lev, diff, sys; default is estimation used REPORTonly /// report only; restore data after running debugflag(int 0) /// debug /// ] // All these will need to be created based on saved xtabond2 matrices: // depvar endo inexog insts exexog clustvar1 clustvar2 wvar // flags local robustflag = "`e(robust)'"~="" local debugflag = `debugflag' | "`debug'"~="" local reportonlyflag = "`reportonly'"~="" local weightflag = "`e(wtype)'"~="" local pcaflag = "`e(pca)'"~="" // In case of weights, need to work out mean of original weight variable, so do this first. if `weightflag' { local wtype "`e(wtype)'" // summarize doesn't like pweights but aweights will yield same results if "`wtype'"=="pweight" { local wtype "aweight" } tempvar tempwvar qui gen double `tempwvar' `e(wexp)' if e(sample) // xtabond2 saved normalized weights for pw and aw if "`wtype'"=="aweight" | `robustflag' { sum `tempwvar' if e(sample), meanonly // so get mean of original for later de-normalizing local wvarmean = r(mean) } else { // ...but not for fweights + classical VCE. local wvarmean = 1 } } // before going further, preserve if this is only for reporting purposes if `reportonlyflag' { preserve } // defaults if "`touse'"=="" { // default touse variable = __touse local touse __touse qui gen byte `touse' = . } else { cap confirm numeric variable `touse' if _rc { qui gen byte `touse' = . } } if "`wvar'"=="" & `weightflag' { // default weight variable = __wvar local wvar __wvar qui gen double `wvar' = . } else if `weightflag' { cap confirm numeric variable `wvar' if _rc { qui gen double `wvar' = . } else { qui recast double `wvar' } } // default names: __id, __eq, __t if "`panelvar'"=="" { local panelvar __id qui gen long `panelvar' = . } else { cap confirm numeric variable `panelvar' if _rc { qui gen long `panelvar' = . } } if "`eqvar'"=="" { local eqvar __eq qui gen long `eqvar' = . } else { cap confirm numeric variable `eqvar' if _rc { qui gen long `eqvar' = . } } if "`timevar'"=="" { local timevar __t qui gen long `timevar' = . } else { cap confirm numeric variable `timevar' if _rc { qui gen long `timevar' = . } } if "`consvar'"=="" { local consvar __cons qui gen double `consvar' = . } else { cap confirm numeric variable `consvar' if _rc { qui gen double `consvar' = . } } if "`hvar'"=="" { local hvar __h qui gen long `hvar' = . } else { cap confirm numeric variable `hvar' if _rc { qui gen long `hvar' = . } } // do this before manipulating data; needed for H matrix qui xtset local tmin `r(tmin)' local tmax `r(tmax)' local delta `r(tdelta)' tempname b V Y X Z ideqt wt clustmat1 clustmat2 A1 A2 H // used for matrices mat `Y' = e(Y) mat `X' = e(X) mat `Z' = e(Z) mat `A1' = e(A1) mat `A2' = e(A2) mat `H' = e(H) // A2 may be missing local A2missing = (`A2'[1,1]==.) // If one of Y, X or Z is missing, it's because svmat option wasn't used. if rowsof(`Y')==1 & `Y'[1,1]==. { di as err "Error: svmat option of xtabond2 required." exit 198 } // increase number of obs local nobs = rowsof(`Y') // `nobs' can be < obs in untransformed dataset if there are unused rows etc. if `nobs' > _N { set ob `nobs' } // ideqt matrix added in xtabond2 version 03.04.00. Catch if not present. mat `ideqt'=e(ideqt) if rowsof(`ideqt')==1 & `ideqt'[1,1]==. { di as err "Error: xtabond2 saved matrix e(ideqt) not found" di as err "Must have xtabond2 version 03.04.00 or greater installed" di as err "To install, from within Stata type " _c di in smcl "{stata ssc install xtabond2 :ssc install xtabond2}" exit 111 } // weight variable (if needed) if `weightflag' { mat `wt'=e(wt) // retrieve saved weight variable if rowsof(`wt')==1 & `wt'[1,1]==. { // and put values into tempvar `wvar' di as err "Error: xtabond2 weights variable e(wt) missing from saved results" exit 198 } qui svmat double `wt' // xtabond2 weight variable has been normalized to mean=1; qui replace `wvar' = `wt' // will fix this below using `wvarmean' local wtexp "[`wtype'=`wvar']" // e.g. "[aw=]"; used below } // clustvar matrices may or may not exist // apparently #1 is panel if only 1-way, #1 is time and #2 is panel if 2-way // if neither exist, either there is no clustering (e(robust) empty) // or the cluster variable is the id variable mat `clustmat1' = e(clustid2) if rowsof(`clustmat1')==1 { // if the above didn't work, then e(clustid1) has the matrix if it exists mat `clustmat1' = e(clustid1) } else { // it worked, so e(clustid1) has the 2nd clustermatrix mat `clustmat2' = e(clustid1) } // Panel id (1), equation number (2), and time variable (3) // rename cols of matrix so that vars created have these names tempvar ideqt1 ideqt2 ideqt3 mat colnames `ideqt' = `ideqt1' `ideqt2' `ideqt3' qui svmat long `ideqt', names(col) qui replace `panelvar' = `ideqt1' qui replace `eqvar' = `ideqt2' qui replace `timevar' = `ideqt3' // (re-)create panel and id vars local ivar `e(ivar)' local tvar `e(tvar)' cap drop `ivar' cap drop `tvar' qui gen `ivar' = `panelvar' qui gen `tvar' = `timevar' // Work out whether to use levels data, diff data or both. tempname iv gmm ivgmm mat `iv' =e(ivequation) mat `gmm' =e(gmmequation) mat `ivgmm' = nullmat(`iv') , nullmat(`gmm') qui count if `eqvar'==0 local hasdiff = r(N)>0 & r(N)<. qui count if `eqvar'==1 local haslevel = r(N)>0 & r(N)<. local usediff = 0 local uselevel = 0 local numcols=colsof(`ivgmm') forvalues i=1/`numcols' { if `ivgmm'[1,`i']==0 { local uselevel =1 } if `ivgmm'[1,`i']==1 { local usediff =1 } if `ivgmm'[1,`i']==2 { local uselevel =1 local usediff =1 } } // Above is overridden by user-provided eq(.) if provided if "`eq'" ~= "" { if "`eq'"=="diff" { // diff data always present local usediff =1 local uselevel =0 } else if "`eq'"=="lev" { // but level data might not be present if `haslevel'==0 { di as err "error - xtabond2 did not save level equation data" exit 198 } local usediff =0 local uselevel =1 } else if "`eq'"=="sys" { // but level data might not be present if `haslevel'==0 { di as err "error - xtabond2 did not save level equation data" exit 198 } local usediff =1 local uselevel =1 } else { di as err "illegal option: eq(`eq')" exit 198 } } // Set touse and xtmodel macro. // xtmodel corresponds to underid estimation rather than original xtabond2 estimation. if `usediff' { qui replace `touse'=1 if `eqvar'==0 } if `uselevel' { qui replace `touse'=1 if `eqvar'==1 } qui replace `touse'=0 if `touse'==. if `usediff' & `uselevel' { local xtmodel sys } else if `usediff' { local xtmodel diff } else if `uselevel' { local xtmodel lev } else { // should never reach here di as err "internal underid error in parsing xtabond2" exit 198 } // e(esttype) = "system" or "difference" // ... except estimation may use level equation only and still call it "system". // e(transform) = "first differences" or "orthogonal deviations" // ... estimation may use level equation only so no transform implied if `usediff' { local transform `e(transform)' } if `debugflag' { di "hasdiff = `hasdiff'" di "usediff = `usediff'" di "haslevel = `haslevel'" di "uselevel = `uselevel'" } // Clustering tokenize `e(clustvar)' // may be empty, 1 var or 2 vars local clustname1 `1' // at least 1-way clustering local clustname2 `2' // possibly 2-way clustering if ("`e(clustvar)'"=="") & ~`robustflag' { // no clustering unusual in xtabond2 estimation but allowed local clustvar1 // ... so do nothing and clear macros just in case local clustvar2 local N_clust = . local N_clust1 = . local N_clust2 = . local vceopt } else if ("`e(clustvar)'"=="") & `robustflag' { // in xtabond2, robust => cluster on default id variable local clustvar1 `ivar' local clustvar2 local clustname1 `ivar' // for display purposes local clustname2 local N_clust = `e(N_g)' local N_clust1 = `e(N_g)' local N_clust2 = . local vceopt cluster(`ivar') } else if "`clustname1'"~="" & "`clustname2'"=="" { // one clustvar specified in e(.) matrix tempvar c1 // name of column = name of variable mat colnames `clustmat1' = `c1' svmat long `clustmat1', names(col) // cluster variable is now tempvar `c1' if "`cluster'"=="" { // no variable or varname provided local clustvar1 __cluster_`clustname1' // in case the name is already used by e.g. ivar rename `c1' __cluster_`clustname1' } else { // use first one only tokenize `cluster' local clustvar1 `1' cap confirm numeric variable `clustvar1' if _rc { qui gen long `clustvar1' = `c1' } else { qui recast long `clustvar1', force qui replace `clustvar1' = `c1' } } local clustvar2 local clustname2 local N_clust = `e(Nclust1)' local N_clust1 = `e(Nclust1)' local N_clust2 = . local vceopt cluster(`clustvar1') } else if "`clustname1'"~="" & "`clustname2'"~="" { // two clustvars specified in e(.) matrix tempvar c1 c2 // name of column = name of variable mat colnames `clustmat1' = `c1' mat colnames `clustmat2' = `c2' svmat long `clustmat1', names(col) if "`cluster'"=="" { // no variable or varname provided local clustvar1 __cluster_`clustname1' // in case the name is already used by e.g. ivar rename `c1' __cluster_`clustname1' } else { // use first one only tokenize `cluster' local clustvar1 `1' cap confirm numeric variable `clustvar1' if _rc { qui gen long `clustvar1' = `c1' } else { qui recast long `clustvar1', force qui replace `clustvar1' = `c1' } } svmat long `clustmat2', names(col) if "`cluster'"=="" { // no variable or varname provided local clustvar2 __cluster_`clustname2' // in case the name is already used by e.g. ivar rename `c2' __cluster_`clustname2' } else { // use second one only tokenize `cluster' local clustvar2 `2' cap confirm numeric variable `clustvar2' if _rc { qui gen long `clustvar2' = `c2' } else { qui recast long `clustvar2', force qui replace `clustvar2' = `c2' } } local N_clust = `e(Nclust1)' local N_clust1 = `e(Nclust1)' local N_clust2 = `e(Nclust2)' local vceopt cluster(`clustvar1' `clustvar2') } else { di as err "Error: cannot determine cluster variables if any" exit 198 } // Now clustering, set remaining vars // Create lists of col names of X and Z matrices. local Xnames : colnames `X' local Znames : colfullnames `Z' // Fix spaces in full names local Znames : subinstr local Znames "Diff eq:" "Diff_eq:" , all local Znames : subinstr local Znames "Levels eq:" "Levels_eq:" , all local Znames : subinstr local Znames "Orthog eq:" "Orthog_eq:" , all if `debugflag' { di di "Column dimensions:" di "X: " colsof(`X') di "Z: " colsof(`Z') di "A1: " colsof(`A1') di "A2: " colsof(`A2') di "H: " colsof(`H') di "Znames: `: word count `Znames''" di } // xtabond2 e(Z) matrix may have empty (all zeros) column at the RHS. // These may NOT have column names. // Hence the number of columns of Z may > number of colnames of Z. // Address this here by removing empty columns. local lastZcol : word count `Znames' if `lastZcol' < colsof(`Z') { // Have to do this in Mata since matrix too big for Stata's matrix commands. mata: st_matrix("`Z'", st_matrix("`Z'")[ ., (1..`lastZcol')]) mat `A1' = `A1'[1..`lastZcol', 1..`lastZcol'] if ~`A2missing' { mat `A2' = `A2'[1..`lastZcol', 1..`lastZcol'] } if `debugflag' { di "Removing extraneous columns from Z..." di "Column dimensions:" di "X: " colsof(`X') di "Z: " colsof(`Z') di "A1: " colsof(`A1') di "A2: " colsof(`A2') di "Znames: `: word count `Znames''" } } // Y (depvar) local depvar "`e(depvar)'" tempvar depvar_t mat colnames `Y' = `depvar_t' qui svmat double `Y', names(col) // X (regressors) local colsofX = colsof(`X') forvalues i=1/`colsofX' { tempvar x`i' local Xnames_t `Xnames_t' `x`i'' } mat colnames `X' = `Xnames_t' qui svmat double `X', names(col) // Z (IVs) local colsofZ = colsof(`Z') forvalues i=1/`colsofZ' { tempvar z`i' local Znames_t `Znames_t' `z`i'' } mat colnames `Z' = `Znames_t' qui svmat double `Z', names(col) if `weightflag' { // xtabond2 incorporates weights in Y and Xs, so remove foreach var of varlist `depvar_t' `Xnames_t' { qui replace `var' = `var'/`wvar' } if ("`e(wtype)'"~="fweight") { qui replace `wvar' = `wvar' * `wvarmean' // and now finally recreate weight var by de-normalizing } } // Get original Stata names of endo and inexog variables from e(b). mat `b'=e(b) mat `V'=e(V) // xtabond2 may not have marked vars as omitted _ms_findomitted `b' `V' local bnames : colfullnames `b' local cons : list posof "_cons" in bnames local cons = (`cons'>0) // Collect list of omitted regressors. // Will exclude these from both X and Z lists unless keepall option specified. // Note that a var may be marked as omitted in b but not x or visa-versa, // so go through both and remove duplicates. local consomitflag =0 foreach var in `Xnames' `bnames' { _ms_parse_parts `var' if r(omit) { local omitted `omitted' `var' local consomitflag =("`var'"=="_cons") } } local omitted : list uniq omitted // omitted macro has clean varnames with no b/n/o operators. fvstrip `omitted' local omitted_stripped `r(varlist)' if `debugflag' { di "omitted: `omitted'" di " `omitted_stripped'" } // Process Xs and Zs. // X = endo + inexog // Z = inexog + exexog // First Zs = inexog + exexog // Znames have FV notation in Xs and spaces removed from Z, // e.g. 1982b.year and Diff_eq:L4.y/1987 if `debugflag' { di di "Znames (`: word count `Znames''): `Znames'" di "Znames_t (`: word count `Znames_t''): `Znames_t'" di } // pre-process pca names // pca option means "varnames" are numbers // change to have "pca_" prefix if `pcaflag' { local zcount : word count `Znames' tokenize `Znames' local Znames // clear it forvalues i=1/`zcount' { if real("``i''")<. { local Znames `Znames' pca:``i'' } else { local Znames `Znames' ``i'' } } } // Process Xnames and Znames. // if names the same and eq name prefix is used (GMM style), Z vars are identifiable by name, // and if the name is the same the variable should be identical // if names the same and no eq name prefix is used (IV) style, Z vars can be different // depending on whether they appear in the lev eqn, diff eqn, or both // relevent only for sys estimation local numXnames : word count `Xnames' local numZnames : word count `Znames' // classify regressors as sys, diff-only, level-only if (`hasdiff' & `haslevel') { // sys estimation so both eqns present forvalues i=1/`numXnames' { local Xvar : word `i' of `Xnames' local Xvar_t : word `i' of `Xnames_t' qui count if `Xvar_t'~=0 & `touse' & `eqvar'==0 local isdiff = r(N)>0 qui count if `Xvar_t'~=0 & `touse' & `eqvar'==1 local islevel = r(N)>0 if `isdiff' & `islevel' { local Xnames_sys `Xnames_sys' `Xvar' } else if `isdiff' { local Xnames_diff_only `Xnames_diff_only' `Xvar' } else { local Xnames_lev_only `Xnames_lev_only' `Xvar' } } } if (`hasdiff' & `haslevel') { // sys estimation so both eqns present // restart Znames list // nb: prefix = "Orthog_eq:" treated the same as prefix = "Diff_eq:" forvalues i=1/`numZnames' { local Zvar : word `i' of `Znames' local Zvar_t : word `i' of `Znames_t' local Zvar : subinstr local Zvar ":" ":", count(local has_eq_prefix) local Zvar : subinstr local Zvar "Diff_eq:" "Diff_eq:", count(local has_diff_prefix) local Zvar : subinstr local Zvar "Orthog_eq:" "Orthog_eq:", count(local has_orthog_prefix) local Zvar : subinstr local Zvar "Levels_eq:" "Levels_eq:", count(local has_level_prefix) local Zvar : subinstr local Zvar "pca:" "pca:", count(local has_pca_prefix) if ~`has_eq_prefix' { // no equation prefix // 3 possibilities: variable is IV for diff only, lev only, or both // if diff only or lev only, change name qui count if `Zvar_t'~=0 & `touse' & `eqvar'==0 local isdiff = r(N)>0 qui count if `Zvar_t'~=0 & `touse' & `eqvar'==1 local islevel = r(N)>0 if `isdiff' & ~`islevel' { // IV for diff eqn but not level eqn local Znames_new `Znames_new' Diff_eq:`Zvar' local Znames_diff_only `Znames_diff_only' Diff_eq:`Zvar' } else if ~`isdiff' & `islevel' { // IV for level eqn but not diff eqn local is_X_lev_only : list posof "`Zvar'" in Xnames_lev_only if `is_X_lev_only' { // if also a regressor, then should treat as exogenous and no renaming needed local Znames_new `Znames_new' `Zvar' local Znames_lev_only `Znames_lev_only' `Zvar' } else { // not a regressor, so renaming needed local Znames_new `Znames_new' Levels_eq:`Zvar' local Znames_lev_only `Znames_lev_only' Levels_eq:`Zvar' } } else { // IV for both diff and level eqns local Znames_new `Znames_new' `Zvar' local Znames_sys_only `Znames_sys_only' `Zvar' } } else { // IV has equation prefix so nothing to change // will be either diff prefix or orthog prefix local Znames_new `Znames_new' `Zvar' if `has_diff_prefix' | `has_orthog_prefix' { local Znames_diff_only `Znames_diff_only' `Zvar' } else if `has_level_prefix' { local Znames_lev_only `Znames_lev_only' `Zvar' } else { local Znames_sys_only `Znames_sys_only' `Zvar' } } } if `debugflag' { di "Znames (`: word count `Znames'') = `Znames'" di "Znames_new (`: word count `Znames_new'') = `Znames_new'" } local Znames `Znames_new' } else if `hasdiff' { // only diff eqn present local Znames_diff_only `exexog' } else if `haslevel' { // only lev eqn present local Znames_lev_only `exexog' } else { di as err "internal make_xtabond2_data error" exit 198 } local endo : list Xnames - Znames matchnames "`endo'" "`Xnames'" "`Xnames_t'" local endo_t `r(names)' local Xinexog : list Xnames - endo matchnames "`Xinexog'" "`Xnames'" "`Xnames_t'" local Xinexog_t `r(names)' local exexog : list Znames - Xinexog matchnames "`exexog'" "`Znames'" "`Znames_t'" local exexog_t `r(names)' local Zinexog : list Znames - exexog matchnames "`Zinexog'" "`Znames'" "`Znames_t'" local Zinexog_t `r(names)' if `hasdiff' { local exexog_diff : list exexog - Znames_lev_only local exexog_diff : list exexog_diff - Znames_sys_only matchnames "`exexog_diff'" "`Znames'" "`Znames_t'" local exexog_diff_t `r(names)' } if `haslevel' { local exexog_lev : list exexog - Znames_diff_only local exexog_lev : list exexog_lev - Znames_sys_only matchnames "`exexog_lev'" "`Znames'" "`Znames_t'" local exexog_lev_t `r(names)' } if `hasdiff' & `haslevel' { local exexog_sys : list exexog - Znames_lev_only local exexog_sys : list exexog_sys - Znames_diff_only matchnames "`exexog_sys'" "`Znames'" "`Znames_t'" local exexog_sys_t `r(names)' } if `debugflag' { di di "Xnames (`: word count `Xnames''): `Xnames'" di "Xnames_t (`: word count `Xnames_t''): `Xnames_t'" di "Znames (`: word count `Znames''): `Znames'" di "Znames_t (`: word count `Znames_t''): `Znames_t'" di "Znames_diff_only (`: word count `Znames_diff_only'') = `Znames_diff_only'" di "Znames_lev_only (`: word count `Znames_lev_only'') = `Znames_lev_only'" di "Znames_sys_only (`: word count `Znames_sys_only'') = `Znames_sys_only'" di di "endo (`: word count `endo''): `endo'" di "endo_t (`: word count `endo_t''): `endo_t'" di "Xinexog (`: word count `Xinexog''): `Xinexog'" di "Xinexog_t (`: word count `Xinexog_t''): `Xinexog_t'" di "Zinexog (`: word count `Zinexog''): `Zinexog'" di "Zinexog_t (`: word count `Zinexog_t''): `Zinexog_t'" di "exexog (`: word count `exexog''): `exexog'" di "exexog_t (`: word count `exexog_t''): `exexog_t'" di "exexog_diff (`: word count `exexog_diff''): `exexog_diff'" di "exexog_lev (`: word count `exexog_lev''): `exexog_lev'" di "exexog_sys (`: word count `exexog_sys''): `exexog_sys'" di } // create macro with first lags used in diff eqn local num_exexog_diff : word count `exexog_diff' if `num_exexog_diff' & ~`pcaflag' { mata: M = J(0,3,"") foreach vn of local exexog_diff { _ms_parse_parts `vn' local ts_op `r(ts_op)' if "`ts_op'"=="L" { local ts_op L1 } mata: M = M \ ("`vn'", "`ts_op'", "`r(name)'") } mata: M = sort(M,(3,2)) local numz : word count `exexog_diff' mata: st_local("thisvar", M[1,3]) mata: st_local("firstlags", M[1,1]) forvalues i=1/`numz' { mata: st_local("var", M[`i',3]) if "`var'"~="`thisvar'" { mata: st_local("thislag", M[`i',1]) local firstlags `firstlags' `thislag' local thisvar `var' } } matchnames "`firstlags'" "`Znames'" "`Znames_t'" local firstlags_t `r(names)' } // Error checks if `: word count `exexog'' ~= `: word count `exexog_t'' { di as err "internal underid/xtabond2 error - number of exexog names differs from number of temp names" exit 198 } if `: word count `Xinexog'' ~= `: word count `Xinexog_t'' { di as err "internal underid/xtabond2 error - number of inexog names differs from number of temp names" exit 198 } if `: word count `Zinexog'' ~= `: word count `Zinexog_t'' { di as err "internal underid/xtabond2 error - number of inexog names differs from number of temp names" exit 198 } if `: word count `endo'' ~= `: word count `endo_t'' { di as err "internal underid/xtabond2 error - number of endo names differs from number of temp names" exit 198 } local X_missing : list Zinexog - Xinexog if "`X_missing'" ~= "" { di as err "internal make_xtabond2_data error: `X_missing' from Zinexog" exit 198 } local Z_missing : list Xinexog - Zinexog if "`Z_missing'" ~= "" { di as err "internal make_xtabond2_data error: `Z_missing' from Xinexog" exit 198 } // Now create final list of included exogenous local inexog `Xinexog' local inexog_t `Xinexog_t' // Remove omitted vars and base factor vars from inexog and endo lists. // Also remove factor variable b/n/o notation. if "`omitted'"~="" & "`keepall'"=="" { di as text "Dropping `omitted' (omitted or base factor variable)..." // First endo. fvstrip `endo' local endo_stripped `r(varlist)' local endo_dropped : list omitted_stripped & endo_stripped if "`endo_dropped'" ~= "" { // Remove from endo list. matchnames "`endo_dropped'" "`endo_stripped'" "`endo_t'" local endo_dropped_t `r(names)' local endo : list endo_stripped - endo_dropped local endo_t : list endo_t - endo_dropped_t } // inexog fvstrip `inexog' local inexog_stripped `r(varlist)' if `debugflag' { di di "omitted=`omitted'" di "omitted_stripped=`omitted_stripped'" di "inexog=`inexog'" di "inexog_stripped=`inexog_stripped'" di } local inexog_dropped : list omitted_stripped & inexog_stripped if "`inexog_dropped'" ~= "" { // Remove from inexog list. matchnames "`inexog_dropped'" "`inexog_stripped'" "`inexog_t'" local inexog_dropped_t `r(names)' local inexog : list inexog_stripped - inexog_dropped local inexog_t : list inexog_t - inexog_dropped_t } } // useful macros local consname_old _cons local consname_new `consvar' // _cons, if it exists, needs special treatment, since _cons not a legal varname. // NB: won't exist or be used if level data not used. // replace with name __cons (default) or what user provied local Xnames : subinstr local Xnames "`consname_old'" "`consname_new'", word local Znames : subinstr local Znames "`consname_old'" "`consname_new'", word local inexog : subinstr local inexog "`consname_old'" "`consname_new'", word // Clean lists local exexog : list clean exexog local exexog_t : list clean exexog_t local inexog : list clean inexog local inexog_t : list clean inexog_t local endo : list clean endo local endo_t : list clean endo_t if `debugflag' { di di "exexog (`: word count `exexog''): `exexog'" di "exexog_t (`: word count `exexog_t''): `exexog_t'" di "inexog (`: word count `inexog''): `inexog'" di "inexog_t (`: word count `inexog_t''): `inexog_t'" di "endo (`: word count `endo''): `endo'" di "endog_t (`: word count `endo_t''): `endo_t'" di } // Check: does original number of coeffs match number of Xs? if colsof(`X') ~= colsof(`b') { di as err "underid/xtabond2 error - number of coefficients does not match number of columns in e(X)" exit 103 } if `debugflag' { di di "exexog (`: word count `exexog''): `exexog'" di "exexog_t (`: word count `exexog_t''): `exexog_t'" di "inexog (`: word count `inexog''): `inexog'" di "inexog_t (`: word count `inexog_t''): `inexog_t'" di "endo (`: word count `endo''): `endo'" di "endog_t (`: word count `endo_t''): `endo_t'" di } // If level data available, constant can appear in coef list bnames. // But if using only diff data, won't appear in inexogcnames. // So remove. if `haslevel'==1 & `uselevel'==0 & `cons' { local posofcons : list posof "`consname_new'" in inexog local consname_new_t : word `posofcons' of `inexog_t' local inexog : list inexog - consname_new local inexog_t : list inexog_t - consname_new_t di as text "Dropping constant (in lev but not in diff data)..." } if `debugflag' { di di "exexog (`: word count `exexog''): `exexog'" di "exexog_t (`: word count `exexog_t''): `exexog_t'" di "inexog (`: word count `inexog''): `inexog'" di "inexog_t (`: word count `inexog_t''): `inexog_t'" di "endo (`: word count `endo''): `endo'" di "endog_t (`: word count `endo_t''): `endo_t'" di } // Error checks if `: word count `exexog'' ~= `: word count `exexog_t'' { di as err "internal underid/xtabond2 error - number of exexog names differ from number of temp names" exit 198 } if `: word count `inexog'' ~= `: word count `inexog_t'' { di as err "internal underid/xtabond2 error - number of inexog names differ from number of temp names" exit 198 } if `: word count `endo'' ~= `: word count `endo_t'' { di as err "internal underid/xtabond2 error - number of endo names differ from number of temp names" exit 198 } // deal with duplicates in IV list local exexog_unique : list uniq exexog local exexog_dups : list dups exexog if "`exexog_dups'"~="" { // Remove from exexog list. matchnames "`exexog_unique'" "`exexog'" "`exexog_t'" local exexog_unique_t `r(names)' local exexog `exexog_unique' local exexog_t `exexog_unique_t' } // Variable counts. local nendog : word count `endo_t' local ninexog : word count `inexog_t' local nexexog : word count `exexog_t' // Prepare and report basic xtabond2 estimation details // Do this now so that counts refer to xtabond2 estimation sum `touse' `wtexp' if `touse', meanonly local N = r(N) // Observation counts reported to user if `usediff' { sum `touse' if `eqvar'==0 `wtexp', meanonly local N_diff = r(N) } else { local N_diff = 0 } if `uselevel' { sum `touse' if `eqvar'==1 `wtexp', meanonly local N_lev = r(N) } else { local N_lev = 0 } di di as text "Estimation using xtabond2-transformed data:" di as text "Number of obs: diff eqn = " `N_diff' ", lev eqn = " `N_lev' ", total = " `N' di as text "Number of panels: `e(N_g)'" if "`clustname1'`clustname2'"~="" { di as text "Clustering on: `clustname1' `clustname2'" } di as text "Dep var: `depvar'"" di as text "Endog Xs (`nendog'):" _c Disp `endo', _col(20) di as text "Exog Xs (`ninexog'):" _c Disp `inexog', _col(20) di as text "Excl IVs (`nexexog'):" _c Disp `exexog', _col(20) // Now rename variables etc. local dict_o `depvar' `inexog' `endo' `exexog' local dict_t `depvar_t' `inexog_t' `endo_t' `exexog_t' if `debugflag' { di di as text "xtabond2 initial dictionary names:" di as res "dict_o `: word count `dict_o'': `dict_o'" di as res "dict_t `: word count `dict_t'': `dict_t'" di } // Start creating display names in dict_d. // If any factor variables in varlists, prefix with "FV_" foreach vn in `depvar' `inexog' `endo' `exexog' { _ms_parse_parts `vn' if r(type)=="factor" { local dict_d `dict_d' FV_`vn' } else { local dict_d `dict_d' `vn' } } // get rid of "/", ":", "." and replace with "_" local dict_d : subinstr local dict_d "/" "_", all local dict_d : subinstr local dict_d ":" "_", all local dict_d : subinstr local dict_d "." "_", all if `debugflag' { di di as text "xtabond2 dictionary names:" di as res "dict_t `: word count `dict_t'': `dict_t'" di as res "dict_d `: word count `dict_d'': `dict_d'" di } // error check if `: word count `dict_d'' ~= `: word count `dict_t'' { di as err "error - list of varnames and tempnames have different number of elements" exit 499 } // Rename variables in varlists matchnames "`endo'" "`dict_o'" "`dict_d'" local endo_o `endo' local endo `r(names)' matchnames "`inexog'" "`dict_o'" "`dict_d'" local inexog_o `inexog' local inexog `r(names)' matchnames "`exexog'" "`dict_o'" "`dict_d'" local exexog_o `exexog' local exexog `r(names)' matchnames "`exexog_diff'" "`dict_o'" "`dict_d'" local exexog_diff_o `exexog_diff' local exexog_diff `r(names)' matchnames "`exexog_lev'" "`dict_o'" "`dict_d'" local exexog_lev_o `exexog_lev' local exexog_lev `r(names)' matchnames "`exexog_sys'" "`dict_o'" "`dict_d'" local exexog_sys_o `exexog_sys' local exexog_sys `r(names)' matchnames "`firstlags'" "`dict_o'" "`dict_d'" local firstlags_o `firstlags' local firstlags `r(names)' matchnames "`Znames'" "`dict_o'" "`dict_d'" local Znames_o `Znames' local Znames `r(names)' if `debugflag' { di di "exexog (`: word count `exexog''): `exexog'" di "inexog (`: word count `inexog''): `inexog'" di "Znames (`: word count `Znames''): `Znames'" di "endo (`: word count `endo''): `endo'" di } // Put matrix stripes on A matrices // Need to allow for special case of vars that are endog and exog in diff eqns matchnames "`Znames'" "`old_inexog'" "`new_exexog'" local newstripe `r(names)' mat colnames `A1' = `newstripe' mat rownames `A1' = `newstripe' if ~`A2missing' { mat colnames `A2' = `newstripe' mat rownames `A2' = `newstripe' } // Put matrix stripes on H matrix. // Time range is for all obs in dataset, even if not used. // Two strips needed if level equation also used. if `hasdiff' { forvalues t=`tmin'(`delta')`tmax' { local hstripe `hstripe' Diff:t`t' } } if `haslevel' { forvalues t=`tmin'(`delta')`tmax' { local hstripe `hstripe' Lev:t`t' } } mat colnames `H' = `hstripe' mat rownames `H' = `hstripe' // drop original vars, keep temp vars and rename keep `dict_t' `touse' `clustvar1' `clustvar2' `wvar' `panelvar' `eqvar' `timevar' `hvar' if `debugflag' { di di "dict_t (`: word count `dict_t''): `dict_t'" di "dict_d (`: word count `dict_d''): `dict_d'" rename (`dict_t') (`dict_d'), dryrun di } rename (`dict_t') (`dict_d') if "`exexog_dups'"~="" { di as text "Duplicates found in excluded IV list:" di as text "{p 0 10}Removing `exexog_dups'{p_end}" di as text "from exexog." } // create identifier for H matrix local tlength = (`hasdiff'+`haslevel')*((`tmax' - `tmin')/`delta' + 1) qui replace `hvar' = _n - `tlength'*(ceil(_n/`tlength')-1) order `hvar', after(`timevar') // Collinearity check (xtabond2 can keep in list of vars even if dropped). if "`keepall'"=="" { // Put cons at start so it's dropped last. // But only if level data being used, since diff has no constant. if `cons' & `uselevel' & `consomitflag'==0 { local inexog : list inexog - consname_new local inexog `consname_new' `inexog' } qui _rmcollright `inexog' `exexog' if `touse', nocons local collin `r(dropped)' if "`collin'" ~= "" { matchnames "`collin'" "`dict_d'" "`dict_o'" di as text "Collinearities/empty variables detected within exog Xs & IVs:" di as text "{p 0 9}Removing `r(names)'{p_end}" di as text "from inexog and/or exexog." local inexog : list inexog - collin local exexog : list exexog - collin } // and then put it back at the end if `cons' & `uselevel' & `consomitflag'==0 { local inexog : list inexog - consname_new local inexog `inexog' `consname_new' } // now loop through A1 and A2 matrices, dropping rows/columns tempname A1temp A2temp // foreach var of local Znames { foreach var of local newstripe { local notdropped : list var - collin if "`notdropped'"~="" { mat `A1temp' = nullmat(`A1temp'), `A1'[1...,"`var'"] if ~`A2missing' { mat `A2temp' = nullmat(`A2temp'), `A2'[1...,"`var'"] } } } mat drop `A1' if ~`A2missing' { mat drop `A2' } // foreach var of local Znames { foreach var of local newstripe { local notdropped : list var - collin if "`notdropped'"~="" { mat `A1' = nullmat(`A1') \ `A1temp'["`var'", 1...] if ~`A2missing' { mat `A2' = nullmat(`A2') \ `A2temp'["`var'", 1...] } } } } if `weightflag' { // use original weight type return local wtexp [`e(wtype)'=`wvar'] return local weightvar `wvar' } return local hvar `hvar' return local panelvar `panelvar' return local timevar `timevar' return local eqvar `eqvar' return local depvar `depvar' return local endo_o `endo_o' return local inexog_o `inexog_o' return local exexog_o `exexog_o' return local exexog_diff_o `exexog_diff_o' return local exexog_lev_o `exexog_lev_o' return local exexog_sys_o `exexog_sys_o' return local firstlags_o `firstlags_o' return local endo `endo' return local inexog `inexog' return local exexog `exexog' return local exexog_diff `exexog_diff' return local exexog_lev `exexog_lev' return local exexog_sys `exexog_sys' return local firstlags `firstlags' return local omitted `omitted_stripped' return local collin `collin' return local pca `e(pca)' return local touse `touse' return local wvar `wvar' return local cluster `cluster' return local clustvar `clustvar1' `clustvar2' return local clustvar1 `clustvar1' return local clustvar2 `clustvar2' return scalar N = `N' return scalar N_clust = `N_clust' return scalar N_clust1 = `N_clust1' return scalar N_clust2 = `N_clust2' return scalar N_g = `e(N_g)' return scalar g_min = `e(g_min)' return scalar g_max = `e(g_max)' return scalar g_avg = `e(g_avg)' return local model linear return local transform `transform' return local xtmodel `xtmodel' return local robust `e(robust)' // always ="robust" under clustering return scalar cons = 0 // if constant present, xtabond2 will have 1s column in the data matrix return scalar h = e(h) // = 1, 2 or 3. note case! return scalar haslevel = `haslevel' return scalar uselevel = `uselevel' return scalar hasdiff = `hasdiff' return scalar usediff = `usediff' return local noconstant noconstant return local small `e(small)' if "`e(twostep)'"~="" { return local gmm2s gmm2s } return scalar dofminus = 0 return local robust `robust' return local vceopt `vceopt' return matrix A1 = `A1' return matrix A2 = `A2' return matrix H = `H' if `reportonlyflag' { restore } end // end make_xtabond2_data // utility for creating xtdpdgmm-transformed data * make_xtdpdgmm_data version 1.00.00 18jul2019 * author mes program define make_xtdpdgmm_data, rclass version 12.1 syntax [ , /// touse(varname) /// wvar(varname) /// NOIsily /// debugflag(int 0) /// ] if "`noisily'"=="" { loc qui qui } if "`touse'"=="" { qui gen byte touse = e(sample) local touse touse } else { qui replace `touse'=e(sample) } // code doesn't support nonlinear moment conditions if e(zrank_nl) >0 { di as err "error - nonlinear moment conditions not supported" exit 198 } // xtdpdgmm doesn't yet support weights but keep the code anyway if "`wvar'"=="" & "`e(wexp)'"=="" { qui gen byte wvar=1 local wvar wvar } else if "`wvar'"=="" & "`e(wexp)'"~="" { qui gen double wvar `e(wexp)' local wvar wvar } else if "`wvar'"~="" & "`e(wexp)'"=="" { qui replace `wvar' = 1 } else { qui replace `wvar' `e(wexp)' } local N_clust = e(N_clust) if `N_clust' < . { // clustering local cluster cluster(`e(ivar)') local clustvar1 `e(ivar)' } tempname b mat `b' = e(b) loc indepvars : coln `b' // indepvars does not include the constant loc indepvars : subinstr loc indepvars "_cons" "", w c(loc cons) if `cons' { // use for display local consname _cons } else { // returned local local noconstant noconstant } cap drop __alliv_* qui predict double __alliv_*, iv unab alliv : __alliv_* *--------------------------------------------------* // The only included exogenous variable is the constant (if present). // All other regressors are treated as endogenous. loc depvar `e(depvar)' loc endo `indepvars' loc exexog `alliv' *--------------------------------------------------* loc N_endo : word count `endo' // N_inexog does not include the constant loc N_inexog : word count `inexog' loc N_exexog = e(zrank) - `N_inexog' - `cons' loc N_iv = e(zrank) - `cons' di as text "Number of obs: `e(N)'" di as text "Number of panels: `e(N_g)'" di as text "Dep var: `depvar'"" di as text "Endog Xs (`N_endo'):" _c Disp `endo', _col(20) di as text "Exog Xs (" `N_inexog'+`cons' "):" _c Disp `inexog' `consname', _col(20) di as text "Excl IVs (`N_exexog'):" _c Disp `exexog', _col(20) if `debugflag' { di "cons=`cons'" di as text "underidindepvars: `indepvars'" di as text "underidivvars: `e(ivvars)'" di as text "underidgmmivvars: `e(gmmivvars)'" di as text "underiddivvars: `e(divvars)'" di as text "underiddgmmivvars: `e(dgmmivvars)'" di as text "underidecivvars: `e(ecivvars)'" di as text "underidecgmmivvars: `e(ecgmmivvars)'" di as text "underidmdivvars: `e(mdivvars)'" di as text "underidmdgmmivvars: `e(mdgmmivvars)'" } return local panelvar `panelvar' return local timevar `timevar' return local depvar `depvar' return local endo `endo' return local inexog `inexog' return local exexog `exexog' return local tinexog `tinexog' return local cluster `cluster' // = "cluster( )" return local clustvar `clustvar1' // = return local clustvar1 `clustvar1' // = return scalar N = e(N) return scalar N_clust = e(N_clust) return scalar dofminus = 0 return local cons = `cons' return local noconstant `noconstant' return local robust `robust' end // end make_xtdpdgmm_data exit