*! version 1.0.0 12sep2025 S. Derya Uysal, Tymon Sloczynski, and Jeffrey M. Wooldridge * SPDX-License-Identifier: MIT * Copyright (c) 2025 S. Derya Uysal, Tymon Sloczynski, and Jeffrey M. Wooldridge * See the LICENSE file in this distribution for full text. capture program drop _teffects2_ipw program define _teffects2_ipw, byable(onecall) version 17 if _by() { local BY `"by `_byvars'`_byrc0':"' } _teffects2_parse_canonicalize ipw : `0' if `s(eqn_n)'==1 { _teffects2_error_msg, cmd(ipw) case(1) } if `s(eqn_n)'>2 { _teffects2_error_msg, cmd(ipw) case(2) } local omodel `"`s(eqn_1)'"' local tmodel `"`s(eqn_2)'"' local if `"`s(if)'"' local in `"`s(in)'"' local wt `"`s(wt)'"' local options `"`s(options)'"' `BY' Estimate_ipw `if' `in' `wt', omodel(`omodel') tmodel(`tmodel') `options' end capture program drop Estimate_ipw program define Estimate_ipw, eclass byable(recall) version 17 syntax [if] [in] [pw], [ /// omodel(string) /// tmodel(string) /// ate atet /// nrm unnrm /// PSTOLerance(numlist max=1) /// OSample(name) /// * ] quietly { _get_diopts diopts rest, `options' local diopts `diopts' _teffects2_gmmopts, `rest' local gmmopts `s(gmmopts)' local rest `s(rest)' local vce `s(vce)' local vcetype `s(vcetype)' local clustvar `s(clustvar)' local iteropt `s(iteropt)' local iteroptml `s(iteroptml)' _teffects_options ipw : `rest' local teopts `s(teopts)' local rest `s(rest)' if "`rest'"!="" { local wc: word count `rest' di as err `"{p} `=plural(`wc',"option")' {bf:`rest'} "' /// `"`=plural(`wc',"is","are")' not allowed{p_end}"' exit 198 } if "`vce'"=="cluster" { local `vce' "cluster `clustvar'" } if "`pstolerance'"=="" { local pstolerance 1E-5 } if "`pstolerance'"!="" { if `pstolerance'<0 | `pstolerance'>=1 { di as err "{p}{bf:pstolerance()} must be greater " /// "than or equal to 0 and less than 1{p_end}" exit 198 } } if "`osample'"!="" { cap confirm variable `osample' if !c(rc) { di as err "{p}invalid option " /// "{bf:osample({it:newvarname})}; variable " /// "{bf:`osample'} already exists{p_end}" exit 110 } } _teffects2_getstatsipw, `ate' `atet' `nrm' `unnrm' local stat1 "`s(stat1)'" local stat `stat1' if "`stat'"=="atet" local stat att local stat2 "`s(stat2)'" local statnorm `stat2' ParseDepvar `omodel' local depvar `s(depvar)' marksample touse markout `touse' `depvar' _teffects2_count_obs `touse' if "`weight'"!="" { tempvar samplew gen double `samplew' `exp' if `touse' } else if "`pw'"=="" { tempvar samplew gen double `samplew' = 1 if `touse'==1 } ExtractVarlist `tmodel' local tvarlist `s(varlist)' local tops `s(options)' _teffects2_parse_tvarlist `tvarlist', `tops' touse(`touse') stat(`stat') cmd(ipw) binary local tvar `s(tvar)' local tvarlist `s(tvarlist)' local fvtvarlist `s(fvtvarlist)' local ktvar = `s(k)' local kfvtvar = `s(kfv)' local tmodel `s(tmodel)' local control = `s(control)' if "`tops'"=="" { local tmodel ipt } if "`tmodel'"=="cbps" & "`stat'"=="att" { noi display as error "CBPS not allowed for ATT" exit 198 } // Expand the factor variable list fvexpand `fvtvarlist' // Store expanded variable list local xvarst "`r(varlist)'" // Start with original xvars local cleanedvarst "" local tempmapt "" // Step 1: standardize all c.var inside interactions or plain c.var local testline "`xvarst'" while regexm("`testline'", "c\.([a-zA-Z0-9_]+)") { local match = regexm("`testline'", "c\.([a-zA-Z0-9_]+)") local vart = regexs(1) local testline = subinstr("`testline'", "c.`vart'", "", 1) tempvar stdvart sum `vart' if `touse'==1 [iw = `samplew'] gen double `stdvart' = (`vart' - r(mean))/r(sd) if `touse'==1 // Replace in xvars (c.var --> c.stdvar) local xvarst : subinstr local xvarst "c.`vart'" "c.`stdvart'", all local tempmapt `tempmapt' `stdvart' } // Step 2: tokenize updated xvars and rebuild cleaned varlist safely tokenize "`xvarst'" while "`1'"!="" { local token "`1'" macro shift // Default: keep token unchanged local newtokent "`token'" // Skip interactions, i., c., dummies, etc. if !strpos("`token'", "#") & !regexm("`token'", "^[0-9]+[a-z]?\.") & !regexm("`token'", "[\.]") & substr("`token'", 1, 2)!="i." & substr("`token'", 1, 2)!="c." { capture confirm variable `token' if _rc==0 { capture tab `token' if `touse'==1 if _rc==0 & r(r)>2 { // Not binary --> standardize tempvar stdvart sum `token' if `touse'==1 [iw = `samplew'] gen double `stdvart' = (`token' - r(mean))/r(sd) if `touse'==1 local newtokent "`stdvart'" local tempmapt `tempmapt' `stdvart' } } } // Add newtoken to cleaned varlist local cleanedvarst "`cleanedvarst' `newtokent'" } // Final cleaned varlist local xvarst "`cleanedvarst'" tempvar ps psxb1 psxb2 ps_1 psxb1_1 psxb2_1 ps_0 psxb1_0 psxb2_0 y1hatw y0hatw wt1 wt0 tempname bps bps1 bps_1 bps_0 bps1_1 bps1_0 bps2_1 bps2_0 bps2 starting initial I nums by1w by0w num1ws num0ws ateipwras bd1 bd0 num1s num0s num_norms tempname ate_ipw vc_ate_ipw r_ate_ipw var_ate_ipw tempname ate_ipwra vc_ate_ipwra r_ate_ipwra var_ate_ipwra tempname ate_nipw vc_ate_nipw r_ate_nipw var_ate_nipw tempname ate_aipw vc_ate_aipw r_ate_aipw var_ate_aipw tempname ate_naipw vc_ate_naipw r_ate_naipw var_ate_naipw nob tempname att_ipw vc_att_ipw r_att_ipw var_att_ipw tempname att_ipwra vc_att_ipwra r_att_ipwra var_att_ipwra tempname att_nipw vc_att_nipw r_att_nipw var_att_nipw tempname att_aipw vc_att_aipw r_att_aipw var_att_aipw tempname att_naipw vc_att_naipw r_att_naipw var_att_naipw // If estimating ATE if "`stat'"=="ate" { // Estimation of the propensity score if "`tmodel'"=="logit" { capture `tmodel' `tvar' `xvarst' [pw = `samplew'] if `touse'==1, asis `iteroptml' if e(converged)==0 { // Check perfect predictions, if >0 exit similar to teffects local ncd = 0 if e(N_cds) & !missing(e(N_cds)) local ncd = e(N_cds) if e(N_cdf) & !missing(e(N_cdf)) local ncd = `ncd' + e(N_cdf) if `ncd'!=0 { local obs = plural(`ncd', "observation") noi di as error "{p}Treatment model has {bf:`ncd'} `obs' " /// "completely determined; the model, as specified, is not identified{p_end}" exit 322 } } if _rc!=0 | e(converged)==0 { noi di as error "convergence not achieved for `tmodel' estimation" exit 430 } matrix `bps' = e(b) predict double `ps' if `touse'==1 gen double `wt1' = `tvar'/`ps' if `touse'==1 gen double `wt0' = (1-`tvar')/(1-`ps') if `touse'==1 local eqps (eqps:`tvar' - exp({that:`xvarst'} + {b0})/(1+exp({that:}+ {b0}))) local eqps_inst instruments(eqps: `xvarst') } else if "`tmodel'"=="cbps" { // Determine starting values from logit capture logit `tvar' `xvarst' [pw = `samplew'] if `touse'==1 local rc_init = _rc if `rc_init'==0 { matrix `initial' = e(b) local k = colsof(`initial') matrix `I' = I(`k') } local eqps (eqps: (`tvar'/(exp({that:`xvarst'} + {b0})/(1+exp({that:}+ {b0})))-(1-`tvar')/(1/(1+exp({that:}+{b0}))))) local eqps_inst instruments(eqps: `xvarst') // GMM estimation of the propensity score using CBPS moments if `rc_init'==0 capture gmm `eqps' if `touse' [pw = `samplew'], `eqps_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' `iteropt' else capture gmm `eqps' if `touse' [pw = `samplew'], `eqps_inst' onestep quickderivatives `gmmopts' `iteropt' if _rc!=0 | e(converged)==0 { noi di as error "convergence not achieved for CBPS estimation" exit 430 } matrix `bps1' = e(b) predict double `psxb1' if `touse'==1 gen double `ps' = exp(`psxb1'+_b[b0:_cons])/(1+exp(`psxb1'+_b[b0:_cons])) if `touse'==1 matrix `bps' = `bps1' gen double `wt1' = `tvar'/`ps' if `touse'==1 gen double `wt0' = (1-`tvar')/(1-`ps') if `touse'==1 } else if "`tmodel'"=="ipt" { // Determine starting values from logit capture logit `tvar' `xvarst' [pw = `samplew'] if `touse'==1 local rc_init = _rc if `rc_init'==0 { matrix `initial' = e(b) local k = colsof(`initial') matrix `I' = I(`k') } // Moment function local eqps1 (eqps1: (`tvar'*(1+exp({that1: `xvarst'} + {b1}))/(exp({that1:}+ {b1})) - 1)) local eqps1_inst instruments(eqps1: `xvarst') // GMM estimation if `rc_init'==0 capture gmm `eqps1' if `touse' [pw = `samplew'], `eqps1_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' `iteropt' else capture gmm `eqps1' if `touse' [pw = `samplew'], `eqps1_inst' onestep quickderivatives `gmmopts' `iteropt' if _rc!=0 | e(converged)==0 { noi di as error "convergence not achieved for IPT estimation" exit 430 } predict double `psxb1_1' if `touse'==1 gen double `ps_1' = exp(`psxb1_1'+_b[b1:_cons])/(1+exp(`psxb1_1'+_b[b1:_cons])) if `touse'==1 gen double `wt1' = `tvar'/`ps_1' if `touse'==1 matrix `bps_1' = e(b) // Moment function local eqps0 (eqps0: ((1-`tvar')*(1+exp({that0: `xvarst'} + {b0})) - 1)) local eqps0_inst instruments(eqps0: `xvarst') // GMM estimation if `rc_init'==0 capture gmm `eqps0' if `touse' [pw = `samplew'], `eqps0_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' `iteropt' else capture gmm `eqps0' if `touse' [pw = `samplew'], `eqps0_inst' onestep quickderivatives `gmmopts' `iteropt' if _rc!=0 | e(converged)==0 { noi di as error "convergence not achieved for IPT estimation" exit 430 } predict double `psxb1_0' if `touse'==1 gen double `ps_0' = exp(`psxb1_0'+_b[b0:_cons])/(1+exp(`psxb1_0'+_b[b0:_cons])) if `touse'==1 gen double `wt0' = (1-`tvar')/(1-`ps_0') if `touse'==1 matrix `bps_0' = e(b) gen double `ps' = . if `touse'==1 replace `ps' = `ps_1' if `tvar'==1 & `touse'==1 replace `ps' = `ps_0' if `tvar'==0 & `touse'==1 } // Check for overlap violations tempvar violators gen byte `violators' = (`ps' < `pstolerance' | `ps' > (1 - `pstolerance')) if `touse'==1 count if `violators'==1 local fail = r(N) if "`osample'"!="" { gen byte `osample' = `violators' if `touse'==1 label variable `osample' "overlap violation indicator" } if `fail' { di as err "{p}" r(N) " observation" cond(r(N)>1, "s", "") /// " violate" cond(r(N)==1, "s", "") " the overlap assumption with " /// "a propensity score outside the range [" /// trim(strofreal(`pstolerance', "%9.3e")) /// ", 1 - " /// trim(strofreal(`pstolerance', "%9.3e")) "]{p_end}" di as err "{p}treatment overlap assumption has been violated" _c local link teffects2_ipw##osample:osample if "`osample'"!="" { di as err " by observations identified in variable " /// "{helpb `link'}{bf:(`osample')}{p_end}" } else { di as err "; use option {helpb `link'}" /// "{bf:()} to identify the overlap violators{p_end}" } exit 498 } // Estimation of ATE with estimated propensity score if "`statnorm'"=="unnrm" { tempvar y1ipw y0ipw tempname num1ipws num0ipws ateipws gen double `y1ipw' = `wt1'*`depvar' if `touse'==1 gen double `y0ipw' = `wt0'*`depvar' if `touse'==1 sum `y1ipw' if `touse'==1 [iw = `samplew'] matrix `num1ipws' = r(mean) sum `y0ipw' if `touse'==1 [iw = `samplew'] matrix `num0ipws' = r(mean) matrix `ateipws' = `num1ipws'-`num0ipws' } else if "`statnorm'"=="nrm" { tempvar y1nipw y0nipw tempname by1nipw by0nipw num1nipws num0nipws atenipws regress `depvar' if `tvar'==1 & `touse'==1 [pw = `samplew'/`ps'] matrix `by1nipw' = e(b) predict double `y1nipw' if `touse'==1 regress `depvar' if `tvar'==0 & `touse'==1 [pw = `samplew'/(1-`ps')] matrix `by0nipw' = e(b) predict double `y0nipw' if `touse'==1 sum `y1nipw' if `touse'==1 [iw = `samplew'] matrix `num1nipws' = r(mean) sum `y0nipw' if `touse'==1 [iw = `samplew'] matrix `num0nipws' = r(mean) matrix `atenipws' = `num1nipws'-`num0nipws' } // Plug everything in GMM if "`tmodel'"=="ipt" { if "`statnorm'"=="unnrm" { local eqy0ipw (eqy0ipw: (((1-`tvar')/(1-(exp({that0:}+ {b0})/(1+exp({that0:}+ {b0})))))*`depvar')-({y0})) local eqy0ipw_inst instruments(eqy0ipw: ) local eqy1ipw (eqy1ipw: ((`tvar'/(exp({that1:}+ {b1})/(1+exp({that1:}+ {b1}))))*`depvar')-({y1})) local eqy1ipw_inst instruments(eqy1ipw: ) local ipw (ipw: {ipw}-(({y1})-({y0}))) matrix `initial' = (`bps_0', `bps_1', `num0ipws', `num1ipws', `ateipws') local k = colsof(`initial') matrix `I' = I(`k') gmm `eqps0' `eqps1' `eqy0ipw' `eqy1ipw' `ipw' if `touse' [pw = `samplew'], `eqps0_inst' `eqps1_inst' `eqy0ipw_inst' `eqy1ipw_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' iterate(0) scalar `ate_ipw' = _b[ipw:_cons] matrix `vc_ate_ipw' = e(V) scalar `r_ate_ipw' = rownumb(`vc_ate_ipw', "ipw:_cons") scalar `var_ate_ipw' = `vc_ate_ipw'[`r_ate_ipw', `r_ate_ipw'] tempname muhat0_ipw r_muhat0_ipw var_muhat0_ipw scalar `muhat0_ipw' = _b[y0:_cons] scalar `r_muhat0_ipw' = rownumb(`vc_ate_ipw', "y0:_cons") scalar `var_muhat0_ipw' = `vc_ate_ipw'[`r_muhat0_ipw', `r_muhat0_ipw'] } else if "`statnorm'"=="nrm" { local eqy0nipw (eqy0nipw: ((0.`tvar'/(1-(exp({that0:} + {b0})/(1+exp({that0:} + {b0})))))*(`depvar'-({y0})))) local eqy0nipw_inst instruments(eqy0nipw: ) local eqy1nipw (eqy1nipw: ((1.`tvar'/(exp({that1:}+ {b1})/(1+exp({that1:}+ {b1}))))*(`depvar'-({y1})))) local eqy1nipw_inst instruments(eqy1nipw: ) local nipw (nipw: {nipw}-(({y1})-({y0}))) matrix `initial' = (`bps_0', `bps_1', `num0nipws', `num1nipws', `atenipws') local k = colsof(`initial') matrix `I' = I(`k') gmm `eqps0' `eqps1' `eqy0nipw' `eqy1nipw' `nipw' if `touse' [pw = `samplew'], `eqps0_inst' `eqps1_inst' `eqy0nipw_inst' `eqy1nipw_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' iterate(0) scalar `ate_nipw' = _b[nipw:_cons] matrix `vc_ate_nipw' = e(V) scalar `r_ate_nipw' = rownumb(`vc_ate_nipw', "nipw:_cons") scalar `var_ate_nipw' = `vc_ate_nipw'[`r_ate_nipw', `r_ate_nipw'] tempname muhat0_nipw r_muhat0_nipw var_muhat0_nipw scalar `muhat0_nipw' = _b[y0:_cons] scalar `r_muhat0_nipw' = rownumb(`vc_ate_nipw', "y0:_cons") scalar `var_muhat0_nipw' = `vc_ate_nipw'[`r_muhat0_nipw', `r_muhat0_nipw'] } } else if "`tmodel'"!="ipt" { if "`statnorm'"=="unnrm" { local eqy0ipw (eqy0ipw: (((1-`tvar')/(1/(1+exp({that:}+ {b0}))))*`depvar')-({y0})) local eqy0ipw_inst instruments(eqy0ipw: ) local eqy1ipw (eqy1ipw: ((`tvar'/(exp({that:}+ {b0})/(1+exp({that:}+ {b0}))))*`depvar')-({y1})) local eqy1ipw_inst instruments(eqy1ipw: ) local ipw (ipw: {ipw}-(((`tvar'/(exp({that:}+ {b0})/(1+exp({that:}+ {b0}))))*`depvar')-(((1-`tvar')/(1/(1+exp({that:}+ {b0}))))*`depvar'))) matrix `initial' = (`bps', `num0ipws', `ateipws') local k = colsof(`initial') matrix `I' = I(`k') gmm `eqps' `eqy0ipw' `ipw' if `touse' [pw = `samplew'], `eqps_inst' `eqy0ipw_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' iterate(0) scalar `ate_ipw' = _b[ipw:_cons] matrix `vc_ate_ipw' = e(V) scalar `r_ate_ipw' = rownumb(`vc_ate_ipw', "ipw:_cons") scalar `var_ate_ipw' = `vc_ate_ipw'[`r_ate_ipw', `r_ate_ipw'] tempname muhat0_ipw r_muhat0_ipw var_muhat0_ipw scalar `muhat0_ipw' = _b[y0:_cons] scalar `r_muhat0_ipw' = rownumb(`vc_ate_ipw', "y0:_cons") scalar `var_muhat0_ipw' = `vc_ate_ipw'[`r_muhat0_ipw', `r_muhat0_ipw'] } else if "`statnorm'"=="nrm" { local eqy0nipw (eqy0nipw: ((0.`tvar'/(1-(exp({that:}+ {b0})/(1+exp({that:}+ {b0})))))*(`depvar'-({y0})))) local eqy0nipw_inst instruments(eqy0nipw: ) local eqy1nipw (eqy1nipw: ((1.`tvar'/(exp({that:}+ {b0})/(1+exp({that:}+ {b0}))))*(`depvar'-({y1})))) local eqy1nipw_inst instruments(eqy1nipw: ) local nipw (nipw: {nipw}-(({y1})-({y0}))) matrix `initial' = (`bps', `num0nipws', `num1nipws', `atenipws') local k = colsof(`initial') matrix `I' = I(`k') gmm `eqps' `eqy0nipw' `eqy1nipw' `nipw' if `touse' [pw = `samplew'], `eqps_inst' `eqy0nipw_inst' `eqy1nipw_inst' onestep winitial(`I') from(`initial') quickderivatives iterate(0) `gmmopts' scalar `ate_nipw' = _b[nipw:_cons] matrix `vc_ate_nipw' = e(V) scalar `r_ate_nipw' = rownumb(`vc_ate_nipw', "nipw:_cons") scalar `var_ate_nipw' = `vc_ate_nipw'[`r_ate_nipw', `r_ate_nipw'] tempname muhat0_nipw r_muhat0_nipw var_muhat0_nipw scalar `muhat0_nipw' = _b[y0:_cons] scalar `r_muhat0_nipw' = rownumb(`vc_ate_nipw', "y0:_cons") scalar `var_muhat0_nipw' = `vc_ate_nipw'[`r_muhat0_nipw', `r_muhat0_nipw'] } } } // If estimating ATT if "`stat'"=="att" { // Estimation of the propensity score if "`tmodel'"=="logit" { capture `tmodel' `tvar' `xvarst' if `touse'==1 [pw = `samplew'], asis `iteroptml' if e(converged)==0 { // Check perfect predictions, if >0 exit similar to teffects local ncd = 0 if e(N_cds) & !missing(e(N_cds)) local ncd = e(N_cds) if e(N_cdf) & !missing(e(N_cdf)) local ncd = `ncd' + e(N_cdf) if `ncd'!=0 { local obs = plural(`ncd', "observation") noi di as error "{p}Treatment model has {bf:`ncd'} `obs' " /// "completely determined; the model, as specified, is not identified{p_end}" exit 322 } } if _rc!=0 | e(converged)==0 { noi di as error "convergence not achieved for `tmodel' estimation" exit 430 } matrix `bps' = e(b) predict double `ps' if `touse'==1 local eqps (eqps:`tvar' - exp({that:`xvarst'} + {b0})/(1+exp({that:}+ {b0}))) local eqps_inst instruments(eqps: `xvarst') } else if "`tmodel'"=="ipt" { // Determine starting values from logit capture logit `tvar' `xvarst' if `touse'==1 [pw = `samplew'] local rc_init = _rc if `rc_init'==0 { matrix `initial' = e(b) local k = colsof(`initial') matrix `I' = I(`k') } local eqps (eqps: (`tvar' - ((exp({that: `xvarst'} + {b0}))*(1-`tvar')))) local eqps_inst instruments(eqps: `xvarst') // GMM estimation if `rc_init'==0 capture gmm `eqps' if `touse' [pw = `samplew'], `eqps_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' `iteropt' else capture gmm `eqps' if `touse' [pw = `samplew'], `eqps_inst' onestep quickderivatives `gmmopts' `iteropt' if _rc!=0 | e(converged)==0 { noi di as error "convergence not achieved for IPT estimation" exit 430 } matrix `bps1_0' = e(b) predict double `psxb1_0' if `touse'==1 gen double `wt0' = exp(`psxb1_0'+_b[b0:_cons]) if `touse'==1 matrix `bps' = e(b) gen double `ps' = `wt0'/(1+`wt0') if `touse'==1 } // Check for overlap violations tempvar violators gen byte `violators' = `ps' > 1-`pstolerance' if `touse'==1 count if `violators'==1 local fail = r(N) if "`osample'"!="" { gen byte `osample' = `violators' if `touse'==1 label variable `osample' "overlap violation indicator" } if `fail' { di as err "{p}" r(N) " observation" cond(r(N)>1, "s", "") /// " violate" cond(r(N)==1, "s", "") " the overlap assumption with " /// "a propensity score greater than 1 - " %9.3e `pstolerance' "{p_end}" di as err "{p}treatment overlap assumption has been violated" _c local link teffects2_ipw##osample:osample if "`osample'"!="" { di as err " by observations identified in variable " /// "{helpb `link'}{bf:(`osample')}{p_end}" } else { di as err "; use option {helpb `link'}" /// "{bf:()} to identify the overlap violators{p_end}" } exit 498 } // Estimation of ATT with estimated propensity score if "`tmodel'"=="logit" { if "`statnorm'"=="unnrm" { tempvar omega1 omega0 y1hatipw y0hatipw tempname w1s w1 num0ipws num1ipws attipws sum `tvar' if `touse'==1 [iw = `samplew'] matrix `w1s' = r(mean) sum `tvar' if `touse'==1 [iw = `samplew'] scalar `w1' = r(mean) gen double `omega1' = (`tvar')/`w1' if `touse'==1 gen double `omega0' = (((1-`tvar')*`ps')/(1-`ps'))/`w1' if `touse'==1 gen double `y1hatipw' = `omega1'*`depvar' if `touse'==1 gen double `y0hatipw' = `omega0'*`depvar' if `touse'==1 sum `y1hatipw' if `touse'==1 [iw = `samplew'] matrix `num1ipws' = r(mean) sum `y0hatipw' if `touse'==1 [iw = `samplew'] matrix `num0ipws' = r(mean) matrix `attipws' = `num1ipws'-`num0ipws' } else if "`statnorm'"=="nrm" { tempvar y0hatnipw tempname by0nipw num1nipws num0nipws attnipws regress `depvar' if `tvar'==1 & `touse'==1 [pw = `samplew'] matrix `by1w' = e(b) predict double `y1hatw' if `touse'==1 regress `depvar' if `tvar'==0 & `touse'==1 [pw = `samplew'*(`ps'/(1-`ps'))] matrix `by0nipw' = e(b) predict double `y0hatnipw' if `touse'==1 sum `y1hatw' if `tvar'==1 & `touse'==1 [iw = `samplew'] matrix `num1nipws' = r(mean) sum `y0hatnipw' if `tvar'==1 & `touse'==1 [iw = `samplew'] matrix `num0nipws' = r(mean) matrix `attnipws' = `num1nipws'-`num0nipws' } } else if "`tmodel'"=="ipt" { tempvar y0hatnipw tempname by0nipw num1nipws num0nipws attnipws regress `depvar' if `tvar'==1 & `touse'==1 [pw = `samplew'] matrix `by1w' = e(b) predict double `y1hatw' if `touse'==1 regress `depvar' if `tvar'==0 & `touse'==1 [pw = `samplew'*(`wt0')] matrix `by0nipw' = e(b) predict double `y0hatnipw' if `touse'==1 sum `y1hatw' if `tvar'==1 & `touse'==1 [iw = `samplew'] matrix `num1nipws' = r(mean) sum `y0hatnipw' if `tvar'==1 & `touse'==1 [iw = `samplew'] matrix `num0nipws' = r(mean) matrix `attnipws' = `num1nipws'-`num0nipws' } // GMM estimation if "`tmodel'"=="logit" { if "`statnorm'"=="unnrm" { local eqw1ipw (eqw1ipw: (`tvar' - {w1})) local eqw1ipw_inst instruments(eqw1ipw: ) local eqy1ipw (eqy1ipw: (`tvar'*(`depvar'/{w1})-({y1}))) local eqy1ipw_inst instruments(eqy1ipw: ) local eqy0ipw (eqy0ipw: (((1-`tvar')*(exp({that:}+ {b0}))*`depvar'/{w1})-({y0}))) local eqy0ipw_inst instruments(eqy0ipw: ) local ipw (ipw: ({ipw}-({y1}-{y0}))) matrix `initial' = (`w1s', `bps',`num0ipws', `num1ipws', `attipws') local k = colsof(`initial') matrix `I' = I(`k') gmm `eqw1ipw' `eqps' `eqy0ipw' `eqy1ipw' `ipw' if `touse' [pw = `samplew'], `eqw1ipw_inst' `eqps_inst' `eqy0ipw_inst' `eqy1ipw_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' iterate(0) scalar `att_ipw' = _b[ipw:_cons] matrix `vc_att_ipw' = e(V) scalar `r_att_ipw' = rownumb(`vc_att_ipw', "ipw:_cons") scalar `var_att_ipw' = `vc_att_ipw'[`r_att_ipw', `r_att_ipw'] tempname muhat01_ipw r_muhat01_ipw var_muhat01_ipw scalar `muhat01_ipw' = _b[y0:_cons] scalar `r_muhat01_ipw' = rownumb(`vc_att_ipw', "y0:_cons") scalar `var_muhat01_ipw' = `vc_att_ipw'[`r_muhat01_ipw', `r_muhat01_ipw'] } else if "`statnorm'"=="nrm" { local eqy0nipw (eqy0nipw: ((0.`tvar'*((exp({that:}+ {b0}))))*(`depvar'-({y0})))) local eqy0nipw_inst instruments(eqy0nipw: ) local eqy1nipw (eqy1nipw: (1.`tvar'*(`depvar'-({y1})))) local eqy1nipw_inst instruments(eqy1nipw: ) local nipw (nipw: (1.`tvar'*({nipw}-(({y1})-({y0}))))) matrix `initial' = (`bps', `by0nipw', `num1nipws', `attnipws') local k = colsof(`initial') matrix `I' = I(`k') gmm `eqps' `eqy0nipw' `eqy1nipw' `nipw' if `touse' [pw = `samplew'], `eqps_inst' `eqy0nipw_inst' `eqy1nipw_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' iterate(0) scalar `att_nipw' = _b[nipw:_cons] matrix `vc_att_nipw' = e(V) scalar `r_att_nipw' = rownumb(`vc_att_nipw', "nipw:_cons") scalar `var_att_nipw' = `vc_att_nipw'[`r_att_nipw', `r_att_nipw'] tempname muhat01_nipw r_muhat01_nipw var_muhat01_nipw scalar `muhat01_nipw' = _b[y0:_cons] scalar `r_muhat01_nipw' = rownumb(`vc_att_nipw', "y0:_cons") scalar `var_muhat01_nipw' = `vc_att_nipw'[`r_muhat01_nipw', `r_muhat01_nipw'] } } else if "`tmodel'"=="ipt" { local eqy0nipw (eqy0nipw: ((0.`tvar'*((exp({that:}+ {b0}))))*(`depvar'-({y0})))) local eqy0nipw_inst instruments(eqy0nipw: ) local eqy1nipw (eqy1nipw: (1.`tvar'*(`depvar'-({y1})))) local eqy1nipw_inst instruments(eqy1nipw: ) local nipw (nipw: (1.`tvar'*({nipw}-(({y1})-({y0}))))) matrix `initial' = (`bps', `by0nipw', `num1nipws', `attnipws') local k = colsof(`initial' ) matrix `I' = I(`k') gmm `eqps' `eqy0nipw' `eqy1nipw' `nipw' if `touse' [pw = `samplew'], `eqps_inst' `eqy0nipw_inst' `eqy1nipw_inst' onestep winitial(`I') from(`initial') quickderivatives `gmmopts' iterate(0) scalar `att_nipw' = _b[nipw:_cons] matrix `vc_att_nipw' = e(V) scalar `r_att_nipw' = rownumb(`vc_att_nipw', "nipw:_cons") scalar `var_att_nipw' = `vc_att_nipw'[`r_att_nipw', `r_att_nipw'] tempname muhat01_nipw r_muhat01_nipw var_muhat01_nipw scalar `muhat01_nipw' = _b[y0:_cons] scalar `r_muhat01_nipw' = rownumb(`vc_att_nipw', "y0:_cons") scalar `var_muhat01_nipw' = `vc_att_nipw'[`r_muhat01_nipw', `r_muhat01_nipw'] } } scalar `nob' = e(N) local N = `nob' local N_clust = e(N_clust) } if "`stat'"=="ate" { tempname b V if "`statnorm'"=="unnrm" { matrix `b' = (`ate_ipw', `muhat0_ipw') matrix `V' = (`var_ate_ipw', 0 \ 0, `var_muhat0_ipw') } else if "`statnorm'"=="nrm" { matrix `b' = (`ate_nipw', `muhat0_nipw') matrix `V' = (`var_ate_nipw', 0 \ 0, `var_muhat0_nipw') } matrix rownames `b' = " " matrix colnames `b' = "ATE" "POmean" matrix rownames `V' = "ATE" "POmean" matrix colnames `V' = "ATE" "POmean" ereturn post `b' `V', obs(`N') esample(`touse') } else if "`stat'"=="att" { tempname b V if "`statnorm'"=="unnrm" { if "`tmodel'"!="ipt" { matrix `b' = (`att_ipw', `muhat01_ipw') matrix `V' = (`var_att_ipw', 0 \ 0, `var_muhat01_ipw') } else if "`tmodel'"=="ipt" { matrix `b' = (`att_nipw', `muhat01_nipw') matrix `V' = (`var_att_nipw', 0 \ 0, `var_muhat01_nipw') } } else if "`statnorm'"=="nrm" { matrix `b' = (`att_nipw', `muhat01_nipw') matrix `V' = (`var_att_nipw', 0 \ 0, `var_muhat01_nipw') } matrix rownames `b' = " " matrix colnames `b' = "ATT" "POmean" matrix rownames `V' = "ATT" "POmean" matrix colnames `V' = "ATT" "POmean" ereturn post `b' `V', obs(`N') esample(`touse') } ereturn local enseparator `r(enseparator)' ereturn local title "Treatment effect estimation" if "`weight'"!="" { ereturn local wexp "`exp'" ereturn local wtype "`weight'" } ereturn local stat `stat1' ereturn local statnorm `statnorm' ereturn local tmodel `tmodel' ereturn local cmd teffects2 ereturn local subcmd ipw ereturn local tvar `tvar' ereturn local depvar `depvar' ereturn local tmodel `tmodel' ereturn hidden local fvtvarlist `fvtvarlist' ereturn local vce `vce' ereturn local vcetype `vcetype' ereturn local clustvar `clustvar' if `N_clust'!=. ereturn scalar N_clust = `N_clust' _teffects2_replay, `diopts' end capture program drop ParseDepvar program define ParseDepvar, sclass version 17 cap noi syntax varname(numeric) local rc = c(rc) if `rc' { if `rc'==103 { _teffects2_error_msg, cmd(ipw) case(4) rc(`rc') } else { di as txt "{phang}The outcome model is " /// "misspecified.{p_end}" exit `rc' } } sreturn local depvar `varlist' end capture program drop ExtractVarlist program define ExtractVarlist, sclass version 17 cap noi syntax varlist(numeric fv), [ * ] local rc = c(rc) if `rc' { _teffects2_error_msg, cmd(ipw) case(5) rc(`rc') } sreturn local varlist `"`varlist'"' sreturn local options `"`options'"' end exit