*!multigmelogit 1.0 Jan 21, 2015 * Paul Corral program define gmemultinomial, eclass version 11.2 syntax varlist(min=2 numeric fv) [if] [in] [,GENerate(string) NOCons BASEoutcome(numlist)] //mark estimation sample marksample touse //Check if we have categorical variable tokenize `varlist' qui:tab `1' if `touse' if (r(r)<2 | r(r)==.){ display as error "You must specify a categorical variable" error 498 } local numdep=r(r) // Local for dependent variable local depend `1' // obtain the independent variables macro shift local indeps `*' //Remove collinear explanatory vars _rmcoll `indeps' if `touse', forcedrop local indeps `r(varlist)' if "`baseoutcome'"!=""{ qui:levelsof `depend', local(eqns) separate(,) if (inlist(`baseoutcome',`eqns'))!=1{ display as error "Baseoutcome is not a member of the dependent variable" exit } } else{ qui:levelsof `depend',local(eqns) tokenize `eqns' local baseoutcome `1' } ///Okay now create the depvars local check:value label `depend' qui: levelsof `depend' if `depend'!=`baseoutcome', local(eqns) local eqns `baseoutcome' `eqns' foreach x of local eqns{ tempvar d`x' gen `d`x''=(`depend'==`x') local depvars `depvars' `d`x'' } if "`check'"==""{ tokenize `eqns' macro shift local eqnames `*' } else{ tokenize `eqns' macro shift local EQ `*' foreach x of local EQ{ local nm: label `check' `x' local wc=wordcount("`nm'") if `wc'!=1{ local a=1 foreach z of local nm{ if `a'!=1{ local AH `AH'_`z' } else{ local AH `z' } local a=`a'+1 } local eqnames `eqnames' `AH' } else{ local eqnames `eqnames' `nm' } } } ** ** Names for matrices local wc=wordcount("`eqnames'") if "`nocons'"=="nocons" { mata: multigme_discrete("`depvars'", "`indeps'", 1, "`touse'") forvalues c=1/`wc'{ tokenize `eqnames' foreach x in `indeps'{ local EQn `EQn' ``c'' local Varn `Varn' `x' } } } else{ mata: multigme_discrete("`depvars'", "`indeps'", 0, "`touse'") local eqs = `wc' forvalues c=1/`wc'{ tokenize `eqnames' foreach x in `indeps' _cons{ local EQn `EQn' ``c'' local Varn `Varn' `x' } } } tempname s mat `s' = r(Prob) tempname b V mat `b' = r(beta) mat `V' = r(V) mat coleq `b' = `EQn' mat coln `b' = `Varn' mat coleq `V' = `EQn' mat roweq `V' = `EQn' mat rown `V' = `Varn' mat coln `V' = `Varn' // Predicted results: if "`generate'"!=""{ tokenize `generate' local wc=wordcount("`generate'") if `wc'!=1{ display as error "You must specify a name for predicted variable, only one" } else{ capture confirm name `1' if _rc!=0{ display as error "Invalid name for new variable" } else{ capture confirm variable `1' if _rc==0{ display as error "For predicted values, specify variable not already in use" } else{ foreach i of local eqns{ qui: gen double `generate'`i'=. if `touse' local pred `pred' `generate'`i' } mata:predict_gmulti("`indeps'", "`b'", "`pred'", "`touse'") } } } } ************************************************** ************************************************** ************************************************** local N=r(N) ereturn post `b' `V', depname(`depend') obs(`N') esample(`touse') //Number of observations ereturn scalar N = r(N) //Degs of freedom ereturn scalar d_fm = (r(K)-1) //Log likelihood ereturn scalar lnf = r(lnf) //Log likelihood ereturn scalar lnf0 = r(lnf0) //Normalized entropy ereturn scalar Sp = r(Sp) //Pseudo R2 ereturn scalar R2 = (1- r(Sp)) //Entropy for probs. ereturn scalar S = r(S) //Entropy ratio statistic ereturn scalar ERS = 2*r(N)*ln(2)*(1- r(Sp)) // P value for LR ereturn scalar pv = chiprob(e(d_fm),e(ERS)) display _newline in gr "Generalized Maximum Entropy (MLogit)" _col(52) in gr "Number of obs" _col(71) in gr "=" _col(72) in ye %7.0f e(N) display _col(52) in gr "Entropy for probs." _col(71) in gr "=" _col(72) in ye %7.1f e(S) display _col(52) in gr "Normalized entropy" _col(71) in gr "=" _col(72) in ye %7.4f e(Sp) display _col(52) in gr "Ent. ratio stat." _col(71) in gr "=" _col(72) in ye %7.1f e(ERS) display _col(1) in gr "Criterion F (log L) = " in ye e(lnf) _col(52) in gr "Pseudo R2" _col(71) in gr "=" _col(72) in ye %7.4f e(R2) ereturn display end mata: mata set matastrict on mata: // Discrete GME 1.0.0 Jan 21, 2015 function multigme_discrete(string scalar yname, string scalar xname, real scalar nc, string scalar touse) { real matrix Y, X, vcov real vector cons, beta, v1, P,B,omega real scalar K, N, lnf, lnf0, s, Sp, S // Use st_data to import variables from stata Y=st_data(., tokens(yname), touse) X=st_data(., tokens(xname), touse) if (nc==0){ cons = J(rows(X),1,1) X=X,cons } // Observations N=rows(X) // Variables K=cols(X) // Create error vector, Symmetric error support vector v1=-1/sqrt(rows(Y))\0\1/sqrt(rows(Y)) // Optimization s=optimize_init() optimize_init_evaluator(s,&multidis()) optimize_init_evaluatortype(s,"d1") optimize_init_which(s,"min") optimize_init_technique(s,"nr") optimize_init_argument(s,1,Y) optimize_init_argument(s,2,X) optimize_init_argument(s,3,v1) optimize_init_params(s,J(1,(cols(X)*(cols(Y)-1)),0)) beta=-optimize(s) vcov=optimize_result_V_oim(s) lnf=-optimize_result_value(s) lnf0=-optimize_result_value0(s) // Normalized entropy B=J(1,cols(X),0)\colshape(beta, cols(X)) omega=rowsum(exp(cross(X',B'))) P=vec(exp(cross(X',B')):/omega) S=-sum(P:*log(P)) Sp=S/(rows(X)*log(cols(Y))) P=exp(cross(X',B')):/omega // Return results to Stata st_matrix("r(beta)",beta) st_matrix("r(Prob)",B) st_matrix("r(V)",vcov) st_numscalar("r(lnf)", lnf) st_numscalar("r(lnf0)", lnf0) st_numscalar("r(N)", N) st_numscalar("r(K)", K) st_numscalar("r(Sp)", Sp) st_numscalar("r(S)", S) } end mata: mata set matastrict off // Multinomial GME optimization Jan 21, 2015 function multidis (todo, R, Y, X,v, L, g, H) ///J categories { B=J(1,cols(X),0)\colshape(R, cols(X)) P1=cross(X',B') z=cross((vec(Y)),(I(cols(Y))#X)) A=cross(z',(vec(B'))) omega=rowsum(exp(-P1)) psi=rowsum(exp(vec(-P1)*v')) p=vec(exp(-P1):/omega) w=exp(vec(-P1)*v'):/psi L=A+sum(log(omega))+sum(log(psi)) if (todo==1){ dep=cross((vec(Y)),(I(cols(Y))#X)) ex=cross((vec(p)),(I(cols(Y))#X)) error=cross(cross(w',v),(I(cols(Y))#X)) grad=(dep-ex-error) g=grad[|1,(cols(X)+1)\.,.|] } } end mata: mata set matastrict on mata: function predict_gmulti (string scalar xname, string scalar bname, string scalar pname, string scalar touse) { real matrix X, omega, P real vector beta, newvar X=st_data(., tokens(xname), touse) X=X,J(rows(X),1,1) st_view(newvar,., tokens(pname), touse) beta=st_matrix(bname) beta=J(1,cols(X),0)\colshape(beta, cols(X)) // Normalized entropy omega=rowsum(exp(cross(X',beta'))) P=exp(cross(X',beta')):/omega newvar[.,.]=P } end mata: mata set matastrict off