*! version 3.1.3 JMGarrett 19Feb14 /* Graphs predicted values for linear, quantile, or logistic models */ /* (New: allows interactions with polynomials) */ /* Form: predxcon y, xvar(xvar) f(#) t(#) i(#) options */ /* Options required: xvar(), from(#), to(#), inc(#) */ /* Options allowed: poly, adjust, model, graph, nolist, linear, cluster */ /* Note: X variable should be continuous (interval or ordinal) */ /* (added 30Jun03: tests for linear, squared, or cubed terms) */ /* (added 30Aug04: add cluster option) */ /* (added 19Feb14: added "xsectional option for table and y-axis label */ program define predxcon version 8.0 #delimit ; syntax varlist (min=1 max=1) [if] [in] [pweight], Xvar(varlist) [From(real 0) To(real 0) Inc(real 1) Poly(real 0) CLass(string) MODel Adjust(string) NOList GRaph LINear MEDian Level(real 95) CLuster(string) SAVepred(string) XSECtional * ] ; #delimit cr marksample touse markout `touse' `xvar' tokenize "`varlist'" preserve if `from'==0 & `to'==0 { disp _n(1) as error "Both " as result "from() " as error "and " /// as result "to() " as error "must be specified" exit } if "`median'"=="median" & `poly'~=0 { #delimit ; disp _n(1) as error "Polynomial terms will not work with " as result "median" as error " options" ; #delimit cr exit } if "`cluster'"~="" & "`median'"=="median" { disp _n(1) as error "option cluster() not allowed with median" exit } quietly keep if `touse' local varlbly : variable label `1' local yvar "`1'" local varlblx : variable label `xvar' if "`poly'"~="0" { capture assert `poly'==2 | `poly'==3 if _rc~=0 { disp as error "Error: Poly() option can only contain 2 or 3" exit } } capture assert `yvar'==1 | `yvar'==0 if "`median'"=="median" & _rc==0 { disp " " #delimit ; disp as error "Error: Y is coded as " as result "0" as error " and " as result "1" as error "; " as result "median" as error " option not allowed" ; #delimit cr exit } if "`linear'"=="linear" & "`median'"=="median" { #delimit ; disp _n(1) as error "Error: Can't request both " as result "linear " "median " as error "options" ; #delimit cr exit } if _rc==0 & "`linear'"=="linear" { local reg2cat "01" } if _rc==0 { local regtype="log" } if _rc~=0 | "`linear'"=="linear" { local regtype="lin" } if _rc~=0 & "`median'"=="median" { local regtype="med" } if "`class'"~="" { local clvar="`class'" local clval : value label `clvar' quietly drop if `clvar'==. local varlblc: variable label `class' } * If there are covariates, drop missing values, calculate means tokenize "`adjust'" local numcov 0 local i 1 while "`1'"~="" { local equal=index("`1'","=") if `equal'==0 { local cov`i'="`1'" local mcov`i'="mean" } if `equal'~=0 { local cov`i'=substr("`1'",1,`equal'-1) local mcov`i'=substr("`1'",`equal'+1,length("`1'")) } quietly drop if `cov`i''==. local covlist `covlist' `cov`i'' local covdisp `covdisp' `1' local i=`i'+1 macro shift local numcov=`i'-1 } local i 1 while `i'<=`numcov' { if "`mcov`i''"=="mean" { quietly sum `cov`i'' local mcov`i'=r(mean) } local i=`i'+1 } keep `yvar' `xvar' `clvar' `covlist' `cluster' local newn=_N * If polynomial terms are requested, create them if `poly'==2 { gen x_sq=`xvar'^2 local polylst="x_sq" } if `poly'==3 { gen x_sq=`xvar'^2 gen x_cube=`xvar'^3 local polylst="x_sq x_cube" } * If there is a class variable, set up dummy variables and interactions if "`class'"~="" { quietly tab `clvar', gen(clss) local numcat=_result(2) local i 2 while `i'<=`numcat' { *** New section allows interaction terms with polynomials quietly gen Xxclss`i'=`xvar' * clss`i' if `poly'==2 | `poly'==3 { quietly gen Xxclss`i'sq=x_sq * clss`i' } if `poly'==3 { quietly gen Xxclss`i'cb=x_cube * clss`i' } local clist `clist' clss`i' if `poly'==0 { local ilist `ilist' Xxclss`i' } if `poly'==2 { local ilist `ilist' Xxclss`i' Xxclss`i'sq } if `poly'==3 { local ilist `ilist' Xxclss`i' Xxclss`i'sq Xxclss`i'cb } local i=`i'+1 } } * Run linear regression models and test for interaction if class specified if "`regtype'"=="lin" | "`regtype'"=="med" { if "`model'"~="" { if "`regtype'"=="lin" { reg `yvar' `xvar' `polylst' `covlist' `clist' `ilist', clus(`cluster') more } if "`regtype'"=="med" { qreg `yvar' `xvar' `polylst' `covlist' `clist' `ilist' more } } if "`model'"=="" { if "`regtype'"=="lin" { quietly reg `yvar' `xvar' `polylst' `covlist' `clist' `ilist', cl(`cluster') } if "`regtype'"=="med" { quietly qreg `yvar' `xvar' `polylst' `covlist' `clist' `ilist' } } if "`class'"~="" { quietly test `ilist' local df1=r(df) local df2=r(df_r) local f=r(F) local probf=r(p) } else { * tests for x, x_sq, or x_cube if `poly'==0 { quietly test `xvar' } if `poly'==2 { quietly test x_sq } if `poly'==3 { quietly test x_cube } local df1=r(df) local df2=r(df_r) local f=r(F) local probf=r(p) } } * Run logistic models and test for interaction if class specified if "`regtype'"=="log" { if "`model'"~="" { logistic `yvar' `xvar' `polylst' `covlist' `clist' `ilist', clus(`cluster') more } if "`model'"=="" { quietly logistic `yvar' `xvar' `polylst' `covlist' `clist' `ilist', cl(`cluster') } estimates store logest if "`class'"~="" { if "`cluster'"=="" { quietly logistic `yvar' `xvar' `polylst' `covlist' `clist' if e(sample) quietly lrtest logest } if "`cluster'"~="" { quietly test `ilist' } local chisq=r(chi2) local df=r(df) local probchi=r(p) } else { * tests for x, x_sq, or x_cube if "`cluster'"=="" { if `poly'==0 { quietly logistic `yvar' `covlist' `clist' if e(sample) } if `poly'==2 { quietly logistic `yvar' `xvar' `covlist' `clist' if e(sample) } if `poly'==3 { quietly logistic `yvar' `xvar' `covlist' `clist' x_sq if e(sample) } quietly lrtest logest } if "`cluster'"~="" { if `poly'==0 { quietly test `xvar' } if `poly'==2 { quietly test x_sq } if `poly'==3 { quietly test x_cube } } local df=r(df) local chisq=r(chi2) local probchi=r(p) } quietly estimates restore logest } * If there is a class variable, retain values for later if "`class'"~="" { tempvar count quietly gen `count'=1 sort `clvar' collapse `count', by(`clvar') local class1=`clvar' local i 2 while `i'<=`numcat' { local class`i'=`clvar'[_n+`i'-1] local i=`i'+1 } } * Generate the values of x to calculate the predicted values drop _all local i `from' while `i'<`to' { local i=`i'+`inc' } if `i'>`to' { local to=`i'-`inc' } local newobs=((`to'-`from')/`inc')+1 local newobs=round(`newobs',1) quietly range `xvar' `from' `to' `newobs' label var `xvar' "`varlblx'" if `poly'==2 { gen x_sq=`xvar'^2 } if `poly'==3 { gen x_sq=`xvar'^2 gen x_cube=`xvar'^3 } local i=1 while `i'<=`numcov' { quietly gen `cov`i''=`mcov`i'' local i=`i'+1 } * If interaction, expand data, create dummy and interaction variables if "`class'"~="" { quietly expand `numcat' sort `xvar' quietly by `xvar': gen `clvar'=_n local i 1 while `i'<=`numcat' { quietly replace `clvar'=`class`i'' if `clvar'==`i' local i=`i'+1 } quietly tab `clvar', gen(clss) local numcat=r(r) local i=2 while `i'<=`numcat' { *** New section allows interaction terms with polynomials quietly gen Xxclss`i'=`xvar' * clss`i' if `poly'==2 | `poly'==3 { quietly gen Xxclss`i'sq=x_sq * clss`i' } if `poly'==3 { quietly gen Xxclss`i'cb=x_cube * clss`i' } local clist `clist' clss`i' if `poly'==0 { local ilist `ilist' Xxclss`i' } if `poly'==2 { local ilist `ilist' Xxclss`i' Xxclss`i'sq } if `poly'==3 { local ilist `ilist' Xxclss`i' Xxclss`i'sq Xxclss`i'cb } local i=`i'+1 } } * Calculate the predicted values and confidence intervals if "`regtype'"=="log" { predict pred_y, p } else { predict pred_y, xb } predict se, stdp local z=invnorm((1-`level'/100)/2) if "`regtype'"=="lin" | "`regtype'"=="med" { gen lower=pred_y+`z'*se gen upper=pred_y-`z'*se } if "`regtype'"=="log" { tempvar linpred predict `linpred', xb gen lower=1/(1+exp(-`linpred'-`z'*se)) gen upper=1/(1+exp(-`linpred'+`z'*se)) } * List results if "`class'"~="" { sort `clvar' `xvar' } display " " if "`regtype'"=="lin" { if "`xsectional'"=="" { disp as text "Predicted Values and `level'% Confidence Intervals" } if "`xsectional'"=="xsectional" { disp as text "Estimated Values and `level'% Confidence Intervals" } } if "`regtype'"=="med" { disp as text "Predicted Medians and `level'% Confidence Intervals" } if "`regtype'"=="log" { if "`xsectional'"=="" { disp as text "Predicted Probabilities and `level'% Confidence Intervals" } if "`xsectional'"=="xsectional" { disp as text "Estimated Proportions and `level'% Confidence Intervals" } } display " " if "`regtype'"=="lin" { display as text " Model Type:" as result " Linear Regression" } if "`regtype'"=="lin" & "`reg2cat'"=="01" { disp " " #delimit ; disp as result " Warning:" as text " Y variable is coded as " as result "0" as text " and " as result "1" as text ". Perhaps" ; display as text " you didn't mean to use the " as result "linear" as text " option" ; #delimit cr disp " " } if "`regtype'"=="med" { display as text " Model Type:" as result " Quantile Regression" } if "`regtype'"=="log" { display as text " Model Type:" as result " Logistic Regression" } display as text " Outcome:" as result " `varlbly' -- $S_E_depv" display as text " X Variable:" as result" `varlblx' -- `xvar'" if "`class'"~="" { display as text " Class:" as result " `varlblc' -- `clvar'" display as text " Interaction:" as result " `xvar' by `clvar'" } if `poly'==2 | `poly'==3 { display as text " Polynomials:" as result " `polylst'" } if `numcov'>0 { display as text " Covariates:" as result " `covdisp'" } if `numcov'==0 { display as text " Covariates:" as result " (none)" } if "`cluster'"~="" { display as text " Cluster:" as result " `cluster'" } display as text " Observations:" as result " `newn'" if "`class'"=="" & "`nolist'"=="" { list `xvar' pred lower upper, noob separator(0) } if "`class'"~="" & "`nolist'"=="" { by `clvar': list `xvar' pred lower upper, noob separator(0) } if "`class'"=="" { disp " " if "`regtype'"=="lin" | "`regtype'"=="med" { if `poly'==0 { disp as text " Partial F test for" as result " `xvar'" as text ":" } if `poly'==2 { disp as text " Partial F test for" as result " x_sq" as text ":" } if `poly'==3 { disp as text " Partial F test for" as result " x_cube" as text ":" } disp " " disp as text " F(`df1', `df2') = " as result %6.2f `f' if `probf'>=.0001 { disp as text " Prob > F = " as result %7.4f `probf' } if `probf'<.0001 { disp as text " Prob > F < " as result "0.0001" } } if "`regtype'"=="log" { if "`cluster'"=="" { if `poly'==0 { disp as text " Likelihood ratio test for" as result " `xvar'" /// as text ":" } if `poly'==2 { disp as text " Likelihood ratio test for" as result " x_sq" /// as text ":" } if `poly'==3 { disp as text " Likelihood ratio test for" as result " x_cube" /// as text ":" } disp " " disp as text " LR Chi2(" as result `df' as text ") = " /// as result %6.2f `chisq' if `probchi'>=.0001 { disp as text " Prob > Chi2 = " as result %7.4f `probchi' } if `probchi'<.0001 { disp as text " Prob > Chi2 < " as result "0.0001" } } if "`cluster'"~="" { if `poly'==0 { disp as text " Wald test for" as result " `xvar'" /// as text ":" } if `poly'==2 { disp as text " Wald test for" as result " x_sq" /// as text ":" } if `poly'==3 { disp as text " Wald test for" as result " x_cube" /// as text ":" } disp " " disp as text " Wald Chi2(" as result `df' as text ") = " /// as result %6.2f `chisq' if `probchi'>=.0001 { disp as text " Prob > Chi2 = " as result %7.4f `probchi' } if `probchi'<.0001 { disp as text " Prob > Chi2 < " as result "0.0001" } } } } if "`class'"~="" { disp " " if "`regtype'"=="lin" | "`regtype'"=="med" { #delimit ; disp as text " Test for interaction of" as result " `xvar' * `class'" as text ":"; #delimit cr disp " " disp as text " F(`df1', `df2') = " as result %6.2f `f' if `probf'>=.0001 { disp as text " Prob > F = " as result %7.4f `probf' } if `probf'<.0001 { disp as text " Prob > F < " as result "0.0001" } } if "`regtype'"=="log" { if "`cluster'"=="" { #delimit ; disp as text " Likelihood ratio test for interaction of" as result " `xvar' * `class'" as text ":"; #delimit cr disp " " disp as text " LR Chi2(" as result `df' as text ") = " /// as result %6.2f `chisq' if `probchi'>=.0001 { disp as text " Prob > Chi2 = " as result %7.4f `probchi' } if `probchi'<.0001 { disp as text " Prob > Chi2 < " as result "0.0001" } } if "`cluster'"~="" { #delimit ; disp as text " Wald test for interaction of" as result " `xvar' * `class'" as text ":"; #delimit cr disp " " disp as text " Wald Chi2(" as result `df' as text ") = " /// as result %6.2f `chisq' if `probchi'>=.0001 { disp as text " Prob > Chi2 = " as result %7.4f `probchi' } if `probchi'<.0001 { disp as text " Prob > Chi2 < " as result "0.0001" } } } } * Save results if requested if "`savepred'"~="" { keep `clvar' `xvar' pred_y se lower upper tempfile tempprd quietly save `tempprd' } * Graph results if requested if "`graph'"~="" { if "`varlbly'"=="" { local ytitle "for $S_E_depv" } if "`varlbly'"~="" { local ytitle "for `varlbly'" } if "`varlblx'"=="" { local xtitle "`xvar'" } if "`varlblx'"~="" { local xtitle "`varlblx'" } if "`poly'"=="2" { local xtitle "`xtitle' (quadratic)" } if "`poly'"=="3" { local xtitle "`xtitle' (cubic)" } if "`class'"=="" { if "`varlblc'"=="" { local leg 'clvar' } if "`varlblc'"~="" { local leg `varlblc' } if "`regtype'"=="lin" { if "`xsectional'"=="" { local l2title "Predicted Values and `level'% CI" } if "`xsectional'"=="xsectional" { local l2title "Estimated Values and `level'% CI" } } if "`regtype'"=="med" { local l2title "Predicted Medians and `level'% CI" } if "`regtype'"=="log" { if "`xsectional'"=="" { local l2title "Predicted Probabilities and `level'% CI" } if "`xsectional'"=="xsectional" { local l2title "Estimated Proportions and `level'% CI" } } twoway (connected pred_y `xvar', sort) /// (connected upper `xvar', sort msymbol(none) clcolor(cranberry) /// clpat(dash)) /// (line lower `xvar', sort clcolor(cranberry) clpat(dash)), /// ytitle("`ytitle'") l2("`l2title'") xtitle("`xtitle'") /// legend(order(1 "Predicted Value" 2 "`level'% CI")) /// ylabel(, angle(horizontal)) `options' } if "`class'"~="" { if "`regtype'"=="lin" { if "`xsectional'"=="" { local l2title "Predicted Values" } if "`xsectional'"=="xsectional" { local l2title "Estimated Values" } } if "`regtype'"=="med" { local l2title "Predicted Medians" } if "`regtype'"=="log" { if "`xsectional'"=="" { local l2title "Predicted Probabilities" } if "`xsectional'"=="xsectional" { local l2title "Estimated Proportions" } } if "`varlblc'"=="" { local legtitle="`clvar'" } if "`varlblc'"~="" { local legtitle="`varlblc'" } if "`clval'"~="" { local i 1 while `i'<=`numcat' { local clbl`i' : label `clval' `class`i'' local i=`i'+1 } } local i 2 local cval `class1' while `i'<=`numcat' { local cval `cval' `class`i'' local i=`i'+1 } local i 1 while `i'<=`numcat' { if "`clval'"~="" { local leg`i' `i' "`clbl`i''" } if "`clval'"=="" { local leg`i' `i' "`clvar'=`class`i''" } local longleg `longleg' `leg`i'' local i=`i'+1 } rename pred_y _P keep _P `xvar' `clvar' upper lower quietly reshape wide _P upper lower, i(`xvar') j(`clvar') local i 1 while `i'<=`numcat' { if "`clval'"~="" { label var _P`class`i'' "`clvar' = `clbl`i''" } else { label var _P`class`i'' "`clvar' = `class`i''" } local i=`i'+1 } twoway connect _P* `xvar', ytitle("`ytitle'") xtitle("`xtitle'") /// legend(order("`longleg'") title("`legtitle'", size(default))) /// l2("`l2title'") ylabel(, angle(horizontal)) `options' } } if "`savepred'"~="" { disp " " use `tempprd' save "`savepred'" } end