*! version 1.1.1 04June2017 Mauricio Caceres Bravo, caceres@nber.org *! (In)attentive logit regression post-estimation using C plugins capture program drop alogit_p_fast program alogit_p_fast, sclass sortpreserve version 13.1 syntax [anything] [if] [in], [*] if ( "`e(method)'" != "exact" ) { di as err "-algorithm(`e(algorithm)')- only available for -method(exact)-" exit 198 } /* Step 1: place command-unique options in local myopts Note that standard options are LR: Index XB Cooksd Hat REsiduals RSTAndard RSTUdent STDF STDP STDR noOFFset SE: Index XB STDP noOFFset */ local myopts "py pyc pa u a p0 mp0 mp1 dydx(passthru) fit(str) counterfactual(passthru) sorted" /* Step 2: call _propts, exit if done, else collect what was returned. */ local 0: list 0 - replace _pred_se "`myopts'" `0' if ( `s(done)' ) { exit } local vtyp `s(typ)' local varn `s(varn)' local 0 `"`s(rest)'"' /* Step 3: Parse your syntax. */ syntax [if] [in] [, `myopts' noOFFset] /* Step 4: Concatenate switch options together */ local type "`py'`pyc'`pa'`u'`a'`p0'`mp0'`mp1'`dydx'`counterfactual'" /* Step 5: quickly process default case if you can Do not forget -nooffset- option. */ /* Step 6: mark sample (this is not e(sample)). */ marksample touse qui count if `touse' & !e(sample) if ( ("`e(method)'" == "importance") & (`r(N)' > 0) ) { di as err "{p}out-of-sample predictions with " /// "-method(`e(method)'`)- are not possible{p_end}" di as err "see {manhelp alogit_postestimation##warning R:alogit postestimation}" exit 400 } /* Step 7: handle options that take argument one at a time. Comment if restricted to e(sample). Be careful in coding that number of missing values created is shown. Do all intermediate calculations in double. */ /* Step 8: handle switch options that can be used in-sample or out-of-sample one at a time. Be careful in coding that number of missing values created is shown. Do all intermediate calculations in double. */ tempvar notouse gen byte `notouse' = !`touse' local _cons _cons local markvars `e(depvar)' `e(indepvars)' `e(avars)' markout `touse' `:list markvars - _cons' * Parse counterfactual if regexm("`type'", "counterfactual\(.+\)") { local mcapture capture local 0 , `counterfactual' syntax, counterfactual(str) local 0 , `counterfactual' syntax, [u_ij(varname) phi_ij(varname) GRoup(varname) DEFault(varname) CONSider(varname) checksetup] if ( "`default'" == "" ) local default `e(default)' if ( "`consider'" == "" ) local consider `e(consider)' if ( "`group'" == "" ) local cgroup `e(group)' else local cgroup `group' markout `touse' `default' `consider' `u_ij' `phi_ij' markout `touse' `cgroup', strok } else { markout `touse' `e(default)' `e(consider)' markout `touse' `e(group)', strok local default `e(default)' local consider `e(consider)' } * Check the default good is sane if ( "`default'`consider'" == "" ) { di as err "Specify one of -default()- or -consider()-" exit 198 } if ( ("`default'" != "") & ("`consider'" != "") ) { di as err "Specify only one of -default()- or -consider()-" exit 198 } cap assert inlist(`default'`consider', 0, 1) != 0 if `touse' if ( _rc != 0 ) { di as err "`default'`consider' should be a 0/1 variable" exit 400 } tempvar maxd egen `maxd' = total(`default'`consider'), by(`notouse' `e(group)') cap assert `maxd' >= 1 if `touse' if ( _rc != 0 ) { di as err "`default'`consider' should specify at least 1 good per group" exit 400 } if ( "`default'" != "" ) { cap assert inlist(`maxd', 0, 1) != 0 if `touse' if (_rc != 0) { di as err "`default' should specify only one default per individual" exit 400 } } if ( ("`e(model)'" == "dsc") & ("`default'" == "") ) { di as err "-model(dsc)- requires option -default()-" exit 198 } * Check the outcome variable is sane tempvar maxy egen `maxy' = total(`e(depvar)'), by(`notouse' `e(group)') cap assert inlist(`e(depvar)', 0, 1) != 0 if `touse' if ( _rc != 0 ) { di as err "outcome should be a 0/1 variable" exit 400 } cap assert `maxy' >= 1 if `touse' if ( _rc != 0 ) { di as err "encountered goods with no positive outcomes; these will be dropped" } cap assert inlist(`maxy', 0, 1) if `touse' if ( _rc != 0 ) { di as err "encountered goods with multiple positive outcomes; these will be dropped" } * Data has to be sorted to be read correctly if ( "`sorted'" == "" ) sort `notouse' `e(group)' `consider', stable local group `e(group)' local avars `e(avars)' local ivars `e(indepvars)' * Add a constant if the model had one if ( `:list _cons in avars' ) { tempvar cons gen byte `cons' = 1 local avars `:list avars - _cons' `cons' } * Set up for predict in C if ( "`type'" == "" ) local type py qui count if `touse' local N = `r(N)' tempvar in1 in2 index nj tag gen `index' = _n by `notouse' `e(group)': gen `tag' = (_n == 1) by `notouse' `e(group)': gen `in1' = `index'[1] by `notouse' `e(group)': gen `in2' = `index'[_N] by `notouse' `e(group)': gen `nj' = _N qui count if `touse' & `tag' local J = `r(N)' local kx: list sizeof ivars local kxz: list sizeof avars local ktot = `kx' + `kxz' matrix __alogit_b = e(b) if ( `e(expb)' ) mata: st_matrix("__alogit_b", log(st_matrix("__alogit_b"))) scalar __alogit_ll = . scalar __alogit_kx = `kx' scalar __alogit_kxz = `kxz' scalar __alogit_ktot = `ktot' scalar __alogit_getdef = `:di ("`default'" != "") & ("`consider'" == "")' local cvarlist `e(depvar)' `default'`consider' `in1' `in2' `nj' `ivars' `avars' local plugargs if `touse' & `tag' in 1 / `N', `J' local plugcall plugin call aloglik_`e(algorithm)' *********************************************************************** * Call the predict function * *********************************************************************** tempvar pred qui gen double `pred' = . local afit "`e(afit)'" local adjust = 1 if ( ("`type'" == "") | ("`type'" == "py") ) local lvar "P(Y_ij)" else if ( "`type'" == "pyc" ) { if ( "`e(model)'" == "alogit" ) local lvar "P(Y_ij | all goods considered)" else if ( "`e(model)'" == "dsc" ) local lvar "P(Y_ij | attention)" } else if ( "`type'" == "pa" ) local lvar "P(A_ij)" else if ( "`type'" == "u" ) local lvar "u_ij" else if ( "`type'" == "a" ) local lvar "A_ij" else if ( "`type'" == "p0" ) { if ( "`e(model)'" == "alogit" ) local lvar "P(c_i = empty)" else if ( "`e(model)'" == "dsc" ) local lvar "P(I_i | x_id)" } else if ( "`type'" == "mp0" ) { // Nothing } else if ( "`type'" == "mp1" ) { if ( "`e(model)'" == "alogit" ) { di as err "Option -mp1- not available with -model(alogit)-" exit 198 } } else if regexm("`type'", "dydx\(.+\)") { local 0 , `dydx' syntax, dydx(str) local 0 `dydx' syntax varname, [elasticity] if ( `:list varlist in ivars' ) local dpyc dpyc if ( `:list varlist in avars' ) local dpc dpc local type "`dpyc'`dpc'" local ipos `:list posof "`varlist'" in ivars' local apos `:list posof "`varlist'" in avars' if ( (`ipos' == 0) & (`apos' == 0) ) { di as err "`varlist' not used in model fit" /// _n(1) " utility vars: `e(indepvars)'" /// _n(1) " attention vars: `e(avars)'" exit 198 } tempvar adjust gen double `adjust' = 1 if ( "`elasticity'" != "" ) { `plugcall' `cvarlist' `adjust' `plugargs' `e(model)'_p py if ( `ipos' > 0 ) { qui replace `adjust' = `:word `ipos' of `ivars'' / `adjust' } else if ( `apos' > 0 ) { qui replace `adjust' = `:word `apos' of `avars'' / `adjust' } } } else if regexm("`type'", "counterfactual\(.+\)") { local gsort `notouse' if ( "`cgroup'" != "" ) { local gsort `gsort' `cgroup' } else { di as err "please specify -group(varname)-" error 198 } if ( "`default'`consider'" != "" ) { local cvarlist `e(depvar)' `default'`consider' `in1' `in2' `nj' `ivars' `avars' } else { di as err "please specify -default(varname)- or -consider(varname)-" error 198 } if ( "`sorted'" == "" ) sort `gsort' `consider', stable if ( "`u_ij'" == "" ) { tempvar uij alogit_p_linear `uij' if `touse', type(u) ivars(`ivars') avars(`avars') } else { local uij `u_ij' } if ( "`phi_ij'" == "" ) { tempvar pij alogit_p_linear `pij' if `touse', type(pa) ivars(`ivars') avars(`avars') consider(`consider') } else { local pij `phi_ij' } qui count if `touse' local N = `r(N)' tempvar in1 in2 index nj tag gen `index' = _n by `gsort': gen `tag' = (_n == 1) by `gsort': gen `in1' = `index'[1] by `gsort': gen `in2' = `index'[_N] by `gsort': gen `nj' = _N qui count if `touse' & `tag' local J = `r(N)' local counter_cvarlist `default'`consider' `in1' `in2' `nj' `uij' `pij' local counter_plugargs if `touse' & `tag' in 1 / `N', `J' qui gen double `varn' = . `plugcall' `varn' `counter_cvarlist' `counter_plugargs' `e(model)'_c exit 0 } else { di as err "can only handle one option at a time; pass: `myopts'" error 198 } *********************************************************************** * Fit using user-specified parameters * *********************************************************************** if ( "`fit'" != "" ) { local 0 , `fit' syntax, [b0(numlist) g0(numlist) d0(numlist) last] local avars `e(avars)' local ivars `e(indepvars)' local kx `:list sizeof ivars' local kz `:list sizeof avars' tempname bb b matrix `bb' = e(b) matrix b0 = `bb'[1, 1..`kx'] matrix d0 = `bb'[1, `:di `kx' + 1'..`:di `kx' + `kz''] * Parse the custom parameters if ( "`b0'" != "" ) { local ki = `:word count `b0'' local bb0 `:di subinstr("`b0'", " ", ", ", .)' if ( `ki' < `kx' ) { if ( "`last'" == "" ) { matrix b0 = `bb0', b0[1, `:di `ki' + 1'..`kx'] } else { matrix b0 = b0[1, 1..`:di `kx' - `ki''], `bb0' } } else { matrix b0 = `bb0' } } if ( "`g0'" != "" ) { local ka = `:word count `g0'' local gg0 `:di subinstr("`g0'", " ", ", ", .)' } else { local ka = 0 } if ( "`d0'" != "" ) { local ka = `ka' + `:word count `d0'' if ( "`gg0'" == "" ) { local gg0 `:di subinstr("`d0'", " ", ", ", .)' } else { local gg0 `gg0', `:di subinstr("`d0'", " ", ", ", .)' } } if ( ("`d0'" != "") | ("`g0'" != "") ) { if ( `ka' < `kz' ) { if ( "`last'" == "" ) { matrix g0 = `gg0', d0[1, `:di `ka' + 1'..`kz'] } else { matrix g0 = d0[1, 1..`:di `kz' - `ka''], `gg0' } } else { matrix g0 = `gg0' } } * Correct number of variables cap assert `:list sizeof ivars' == `:word count `:colnames b0'' if ( _rc != 0 ) { di as err "Must specify equal number of covariates and parameters." exit 198 } cap assert `:list sizeof avars' == `:word count `:colnames g0'' if ( _rc != 0 ) { di as err "Must specify equal number of covariates and parameters." exit 198 } matrix __alogit_b = b0, g0 if ( `e(expb)' ) mata: st_matrix("__alogit_b", log(st_matrix("__alogit_b"))) } *********************************************************************** * mp0 and mp1 * *********************************************************************** if ( "`type'" == "mp0" ) { scalar __alogit_mp0 = . `plugcall' `cvarlist' `plugargs' `e(model)'_p mp0 local mp0 = scalar(__alogit_mp0) if ( "`e(model)'" == "alogit" ) di "Average P(c_i = empty) = `:di %5.4f `mp0''" else if ( "`e(model)'" == "dsc" ) di "Average P(I_i | x_id) = `:di %5.4f `mp0''" sreturn local `varn' = `mp0' exit } else if ( "`type'" == "mp1" ) { scalar __alogit_mp1 = . `plugcall' `cvarlist' `plugargs' `e(model)'_p mp1 di "Average P(A_i | x_id) = `:di %5.4f `mp1''" sreturn local `varn' = `mp1' exit } *********************************************************************** * Put the variable into Stata * *********************************************************************** if inlist("`type'", "u", "a", "pa") { if ( ("`type'" == "pa") & ("`e(model)'" == "dsc") ) { `plugcall' `cvarlist' `pred' `plugargs' `e(model)'_p `type' `ipos' `apos' gen double `varn' = `pred' * `adjust' } else { alogit_p_linear `varn' if `touse', type(`type') ivars(`ivars') avars(`avars') consider(`consider') } } else { `plugcall' `cvarlist' `pred' `plugargs' `e(model)'_p `type' `ipos' `apos' gen double `varn' = `pred' * `adjust' } label var `varn' "`lvar'" exit end capture program drop alogit_p_linear program alogit_p_linear syntax newvarlist(max = 1) [if] [in], type(str) ivars(varlist) avars(varlist) [consider(varname)] cap matrix drop __alogit_bb cap matrix drop __alogit_bg forvalues k = 1 / `:di scalar(__alogit_kx)' { matrix __alogit_bb = nullmat(__alogit_bb), __alogit_b[1, `k'] } forvalues k = `:di scalar(__alogit_kx) + 1' / `:di scalar(__alogit_ktot)' { matrix __alogit_bg = nullmat(__alogit_bg), __alogit_b[1, `k'] } matrix colnames __alogit_bb = `ivars' matrix colnames __alogit_bg = `avars' if ( "`type'" == "u" ) matrix score double `varlist' = __alogit_bb `if' `in' if ( "`type'" == "a" ) matrix score double `varlist' = __alogit_bg `if' `in' if ( "`type'" == "pa" ) { tempvar pa matrix score double `pa' = __alogit_bg `if' `in' gen double `varlist' = invlogit(`pa') `if' `in' qui if ( "`consider'" != "" ) replace `varlist' = 1 if (`consider' == 1) & !mi(`varlist') } end cap program drop aloglik_fast if ( inlist("`c(os)'", "Unix") & (`c(bit)' == 64) ) cap program aloglik_fast, plugin using("aloglik_fast.plugin") cap program drop aloglik_faster if ( inlist("`c(os)'", "Unix") & (`c(bit)' == 64) ) cap program aloglik_faster, plugin using("aloglik_faster.plugin")