*! version 1.0.0 18apr2012 program define xfrac_154, eclass local vv : di "version " string(_caller()) ":" version 11.0 /* 8 */ if replay() { if "`e(cmd)'" == "" | "`e(fp_cmd2)'" != "fracpoly" { error 301 } syntax [, COMpare SEQuential *] if `"`e(cmd2)'"' != "" { di in blue `"->`e(cmd2)'"' `e(cmd2)', `options' } else { di in blue `"->`e(cmd)'"' `e(cmd)', `options' } fraccomp, `compare' `sequential' exit } gettoken cmd 0 : 0, parse(" ,") xfrac_chk `cmd' if `s(bad)' { di as err "invalid or unrecognised command, `cmd'" exit 198 } /* dist=0 (normal), 1 (binomial), 2 (poisson), 3 (cox), 4 (glm), 5 (xtgee), 6 (ereg/weibull), 7 (stcox/streg). */ local dist `s(dist)' local glm `s(isglm)' local qreg `s(isqreg)' local xtgee `s(isxtgee)' local normal `s(isnorm)' if `dist' != 7 { gettoken lhs 0 : 0, parse(" ,") if `dist' == 8 { gettoken lhs2 0 : 0, parse(" ,") local lhs `lhs' `lhs2' } } gettoken star 0 : 0, parse(" ,") local star "`lhs' `star'" /* Look for fixpowers */ local done 0 gettoken nxt : 0, parse(" ,") while !`done' { local done 1 if "`nxt'"!="" & "`nxt'"!="," { cap confirm num `nxt' if _rc==0 { local fixpowe `fixpowe' `nxt' local done 0 gettoken nxt 0 : 0, parse(" ,") gettoken nxt : 0, parse(" ,") } } } local 0 `"`star' `0'"' local search = ("`fixpowe'"=="") if `search' { local srchopt ADDpowers(str) DEVthr(real 1e30) /* */ POwers(numlist) DEGree(int 2) LOg COMpare SEQuential } if `dist' == 8 local minv 3 else if `dist' != 7 local minv 2 else local minv 1 syntax varlist(min=`minv' fv) [if] [in] [aw fw pw iw] [, /// restrict(string) DEAD(str) CATzero EXPx(str) ORIgin(str) ZERo /// noCONstant noSCAling ADJust(str) CENTer(str) NAme(str) `srchopt' * ] local small 1e-6 if ("`adjust'"=="") { local adjust "`center'" } else if ("`center'"!="") { di as err "may not specify both adjust() and center()" exit 198 } if "`constant'"=="" & "`cmd'"=="regress" & "`options'"!="" { /* -regress- has syntax noConstant */ /* do not let it quietly passthru to -regress- */ /* in the options macro */ CheckForNoConstant, `options' local constant `s(constant)' local options `"`s(options)'"' } frac_cox "`dead'" `dist' local cz="`catzero'"!="" if `cz' local zero zero if `search' { if `degree'<1 | `degree'>9 { di as err "invalid degree()" exit 198 } local df=2*`degree' local odddf=(2*int(`df'/2)<`df') } else local df 1 local lin=("`fixpowe'"=="1") & ("`zero'"=="") & ("`catzero'"=="") if "`constant'"=="noconstant" { if "`cmd'"=="fit" | "`cmd'"=="cox" | "`cmd'"=="stcox" | /* */ "`cmd'"=="streg" | "`cmd'"=="clogit" | /* */ "`cmd'"=="logistic" { di as err "noconstant invalid with `cmd'" exit 198 } local options "`options' nocons" } /* Read powers to be searched into a variable, `p' */ if `search' { if "`powers'"=="" local powers "-2,-1,-.5,0,.5,1,2,3" local pwrs "`powers' `addpowers'" frac_pq "`pwrs'" 1 1 local np `r(np)' if `np'<1 { di as err "no powers given" exit 2002 } local pwrs "`r(powers)'" forvalues i=1/`np' { local p`i' `r(p`i')' } } ereturn clear /* do we want to do this ?? */ tokenize `varlist' if `dist' == 8 { // intreg local y1 `1' local y2 `2' local y `y1' `y2' local rhs `3' mac shift 3 } else if `dist' != 7 { local y `1' local rhs `2' mac shift 2 } else { // dist = 7: stcox, streg, stpm local y _t local rhs `1' mac shift } fvexpand `rhs' if "`r(fvops)'" == "true" { di as err "factor variables not allowed in this context" exit 198 } local base `*' tempvar touse x lnx quietly { mark `touse' [`weight' `exp'] `if' `in' if `dist' == 8 { replace `touse' = 0 if `y1'>=. & `y2'>=. markout `touse' `rhs' `base' `dead' } else markout `touse' `rhs' `y' `base' `dead' lab var `touse' "fracpoly sample" if "`dead'"!="" { local options "`options' dead(`dead')" } if "`restrict'"!="" { /* -restrict()- becomes part of touse for estimation purposes; only for fracgen is the original touse used. */ tempvar touse_user gen byte `touse_user' = 1 `if' // ! PR bug fix frac_restrict `touse' `restrict' local restrict restrict(`restrict') } else local touse_user `touse' /* Deal with weights. */ frac_wgt `"`exp'"' `touse' `"`weight'"' local mnlnwt = r(mnlnwt) /* mean log normalized weights */ local wgt `r(wgt)' gen double `x'=`rhs' if `touse' gen double `lnx'=. frac_xo `x' `lnx' `lin' "`expx'" "`origin'" /* */ "`zero'" "`scaling'" `rhs' `touse' local nobs = r(N) if r(shifted)==0 { local zeta `r(zeta)' local shift 0 } else local shift `r(zeta)' local kx `"`r(expxest)'"' local scalfac `r(scale)' if `cz' { tempvar catz gen byte `catz'=`x'<=0 } } if `dist' != 7 local yvar `y' /* Determine residual and model df. */ qui regress `y' `base' `wgt' if `touse' local rdf=e(df_r)+("`constant'"=="noconstant") /* Calc deviance=-2(log likelihood) for regression on covars only, allowing for possible weights. */ if "`constant'"!="" & `dist'>0 { if `dist' == 1 { /* logit will allow zero vector to be dropped */ /* by _rmcoll and complete w/out error */ tempvar z0 qui gen `z0' = 0 } else { /* all others dev0 = 0 */ local scale = 1 local dev0 = . } } if "`dev0'" == "" { `vv' /// qui `cmd' `yvar' `z0' `base' `wgt' if `touse', `options' if `xtgee' & "`base'"=="" global S_E_chi2 0 if `glm' { /* Note: with Stata 8 scale param is e(phi); */ /* was e(delta) in Stata 6 */ /* Also e(dispersp) has become e(dispers_p). */ local scale 1 if abs(e(dispers_p)/e(phi)-1)>`small' & /* */ abs(e(dispers)/e(phi)-1)>`small' { local scale = e(phi) } } frac_dv `normal' "`wgt'" `nobs' `mnlnwt' `dist' /* */ `glm' `xtgee' `qreg' "`scale'" local dev0 = r(deviance) if `normal' local rsd0= e(rmse) } if `search' { local m `degree' if "`log'"!="" { di _n as txt "Model # Deviance " _cont if `normal' di as txt " Res S.D. " _cont forvalues i=1/`m' { di as txt " Power " `i' _cont } di _n } /* Go! */ forvalues i=1/`np' { local pi `p`i'' tempvar x`i' qui gen double `x`i''=cond(`pi'==0, `lnx', /* */ cond(`pi'==1, `x', cond(`x'==0,0,`x'^`pi'))) } local i 0 while `i'<`m' { local j`i' 0 local ++i tempvar xp`i' qui gen double `xp`i''=. local j=`i'+`i'-1 local dev`j' `dev0' /* min deviance for df=j */ local ++j local dev`j' `dev0' } local j`m' 1 local i `m' local kount 0 /* no. of models processed */ local kountd 0 /* no. of models with deviance<`devthr' */ local deg `j`m'' local done 0 while !`done' { if `i'<`m' { local ji `j`i'' qui replace `xp`i''=`x`ji'' local l `i' while `l'<`m' { local l=`l'+1 local j`l' `ji' local l1=`l'-1 qui replace `xp`l''=`xp`l1''*`lnx' } if "`log'"=="" di "." _cont } else qui replace `xp`m''=`x`j`m''' /* Test for any power being 1 (i.e. odd-df model) */ local one 0 local l 0 while `l'<`m' { local ++l if "`p`j`l'''"=="1" local one 1 } if !`odddf' | (`deg'<`m') | `one' { local dfi=2*`deg'-`one' local i 1 local xlist while `i'<=`m' { if `j`i''>0 { local xlist "`xlist' `xp`i''" } local ++i } local ++kount `vv' /// cap `cmd' `yvar' `xlist' `catz' `base' `wgt' /* */ if `touse', `options' if _rc == 0 { frac_dv `normal' "`wgt'" `nobs' /* */ `mnlnwt' `dist' `glm' `xtgee' /* */ `qreg' "`scale'" local dev = r(deviance) if `normal' { local rsd=e(rmse) if `dfi'==1 local rsd1 `rsd' } } else if _rc==1 { error 1 } else local dev = . if `dev'<`dev`dfi'' { local dev`dfi' `dev' if `normal' local rsd`dfi' `rsd' local i 1 local pm`dfi' while `i'<=`m' { if `j`i''>0 { local pm `p`j`i''' local pm`dfi' /* */" `pm`dfi'' `pm'" } local ++i } } if `dev'<`devthr' local ++kountd if "`log'"!="" { di as res %5.0f `kount' /* */ _col(10) %12.3f `dev' _cont if `normal' di " " %8.0g `rsd' _cont local i `m' while `i'>0 { if `j`i''==0 di _skip(6) ". " _cont else di as res %8.1f `p`j`i''' _cont local --i } di } if `deg'==1 { local fppow `p`j`m''' local fpdev`j`m'' "`fppow' `dev'" } } /* Increment the first possible index (of loop i) among indices of loops m, m-1, m-2, ..., 1 */ local i `m' /* Finish after all indices have achieved their upper limits (np). */ while `j`i''==`np' { local --i } if `i'==0 local done 1 else { if `j`i''==0 local deg = `m'-`i'+1 local ++j`i' } } /* Update the results for even df to include odd df */ local i 2 while `i'<=`df' { local j=`i'-1 if `dev`j''<`dev`i'' { local dev`i' `dev`j'' if `normal' local rsd`i' `rsd`j'' local pm`i' "`pm`j''" } local i=`i'+2 } if "`log'"=="" di } /* Create FP transformation(s) of xvar for final model */ if `search' local pwrs `pm`df'' else local pwrs `fixpowe' if "`expx'"!="" local e "expx(`expx')" if "`origin'"!="" local o "origin(`origin')" if "`adjust'"!="" local a "adjust(`adjust')" if "`name'"!="" local n "name(`name')" if !`lin' | (`lin' & "`e'`o'`a'"!="") { fracgen `rhs' `pwrs' if `touse_user', `restrict' sayesamp replace /* */ `zero' `catzero' `scaling' `a' `e' `o' `n' local xp `r(names)' } else local xp `rhs' /* Fit final model with permanent e(sample)=`touse' filter */ `vv' /// `cmd' `yvar' `xp' `base' `wgt' if `touse', `options' if !`search' { /* Deviance for fixed-powers model. Note that `dev1' is stored in e(fp_dlin), deviance for a linear model, even when `fixpowe' is not 1; similarly for `rsd1'. */ frac_dv `normal' "`wgt'" `nobs' `mnlnwt' `dist' `glm' /* */ `xtgee' `qreg' "`scale'" local dev1 = r(deviance) if `normal' local rsd1=e(rmse) local pm1 `fixpowe' } di as txt "Deviance:" as res %9.2f `dev`df'' as txt ". " _cont local dev `dev`df'' if `search' { di as txt "Best powers of " as res "`rhs'" as txt " among " /* */ as res `kount' as txt " models fit: " as res "`pwrs'" _cont if `devthr'<1e30 { di _n as txt "Number of models with deviance < " /* */ as res `devthr' as txt ": " as res `kountd' _cont } di as txt "." _cont } di ereturn scalar fp_d0 = `dev0' cap ereturn scalar fp_s0 = `rsd0' ereturn scalar fp_dlin = `dev1' global S_E_d0 `dev0' /* double save */ global S_E_s0 `rsd0' /* double save */ global S_E_dlin `dev1' /* double save */ if `normal' { ereturn scalar fp_slin = `rsd1' * global S_E_slin `rsd1' /* double save */ } local i 2 local j 1 while `i'<=`df' { ereturn scalar fp_d`j' = `dev`i'' ereturn local fp_p`j' `pm`i'' /* PR bug fix */ global S_E_d`j' `dev`i'' /* double save */ global S_E_p`j' `pm`i'' /* double save */ if `normal' { ereturn scalar fp_s`j' = `rsd`i'' global S_E_s`j' `rsd`i'' /* double save */ } local i=`i'+2 local j=`j'+1 } /* New code in v 1.4.7 for consistency with mfracpol */ ereturn local fp_x1 `rhs' ereturn local fp_k1 `pwrs' local nbase: word count `base' local i 0 while `i'<`nbase' { local i=`i'+1 local j=`i'+1 ereturn local fp_x`j' : word `i' of `base' ereturn local fp_k`j' 1 } /* End of new code in v 1.4.7 for consistency with mfracpol */ if `search' { local i `np' while `i'>0 { ereturn local fp_bt`i' `fpdev`i'' local i=`i'-1 } } ereturn scalar fp_dev = `dev' ereturn scalar fp_catz = `cz' ereturn scalar fp_nx = `nbase'+1 ereturn scalar fp_df = `df' ereturn scalar fp_rdf = `rdf' ereturn scalar fp_N = `nobs' ereturn local fp_opts `options' ereturn local fp_t1t "Fractional Polynomial" ereturn local fp_pwrs `pwrs' ereturn local fp_wgt "`weight'" ereturn local fp_wexp "`exp'" ereturn local fp_xp `xp' ereturn local fp_base `base' ereturn local fp_rhs `rhs' ereturn local fp_depv `y' ereturn local fp_fvl `xp' `base' ereturn scalar fp_dist = `dist' ereturn local fp_fprp "no" ereturn scalar fp_srch = `search' ereturn scalar fp_sfac = `scalfac' ereturn scalar fp_shft = `shift' ereturn local fp_xpx `kx' ereturn local fp_cmd "fracpoly" ereturn local fp_cmd2 "fracpoly" global S_E_base `base' /* double save */ global S_E_df `df' /* double save */ global S_E_depv `y' /* double save */ global S_E_wgt "`weight'" /* double save */ global S_E_exp "`exp'" /* double save */ global S_E_fp fracpoly /* double save */ global S_E_fp2 fracpoly /* double save */ global S_E_nobs `nobs' /* double save */ global S_E_pwrs `pwrs' /* double save */ global S_E_rdf `rdf' /* double save */ global S_E_rhs `rhs' /* double save */ global S_E_xp `xp' /* double save */ global S_E_cmd `cmd' /* double save */ fraccomp, `compare' `sequential' end program define fraccomp /* report model comparisons */ syntax [, COMpare SEQuential ] if "`compare'`sequential'"=="" | e(fp_srch)==0 exit local normal=(e(fp_dist)==0) local cz = e(fp_catz) if `cz' local catz " (+)" local dash " {hline 2}" local ddup=63+15*`normal' di as txt _n "Fractional polynomial model comparisons:" di as txt "{hline `ddup'}" di as txt abbrev("`e(fp_rhs)'",12) _col(18) "df Deviance " _cont if `normal' di as txt " Res. SD " _cont di as txt "Dev. dif. P (*) Powers" di as txt "{hline `ddup'}" local maxdf = e(fp_df) local degree = 1+int((`maxdf'-1)/2) // PR 22mar2009 -start- frac_eqmodel k if "`sequential'"=="" { // default is closed-test-style presentation local dev0 = e(fp_d`degree') local j 0 while `j'<=`maxdf' { local m = 1 + int((`j' - 1) / 2) // degree of model being reported if `j' == 0 local idf 0 else local idf = cond(`j' == 1, `k' * (1 + `cz'), (`k' + 1) * `m' + `k' * `cz') if `j'<`maxdf' { // denominator df for F-tests (`n1' is numerator) local n2 = e(fp_rdf) - `idf' if `j'==0 { di as txt "Not in model" _col(18) as res %2.0f `idf' _col(22) _cont local dev = e(fp_d0) local rsd = e(fp_s0) if `maxdf' == 1 local n1 = `k' * (1 + `cz') else local n1 = (`k' + 1) * `degree' + `k' * `cz' local pwr } else if `j'==1 { di as txt "Linear`catz'" _col(18) as res %2.0f `idf' _col(22) _cont local dev = e(fp_dlin) local rsd = e(fp_slin) local n1 = (`k' + 1) * `degree' - `k' local pwr 1 } else { di as txt "m = `m'`catz'" _col(18) as res %2.0f `idf' _col(22) _cont local dev = e(fp_d`m') local rsd = e(fp_s`m') local n1 = (`degree' - `m') * (`k' + 1) local pwr `e(fp_p`m')' } local d = `dev'-`dev0' frac_pv `normal' "`e(fp_wgt)'" `e(fp_N)' `d' `n1' `n2' local P = r(P) if `j'==1 global S_E_Plin `P' else global S_E_P`m' `P' di as res %13.3f `dev' _cont if `normal' di as res _skip(5) %8.0g `rsd' _cont di as res _skip(3) %7.3f `d' %9.3f `P' _skip(2) "`pwr'" } else { di as txt "m = `degree'`catz'" _col(18) as res %2.0f `idf' /* */ _col(22) %13.3f `dev0' _cont if `normal' di as res _skip(5) %8.0g e(fp_s`degree') _cont di as txt _skip(1) "`dash'`dash'" as res _skip(2) "`e(fp_p`degree')'" } local j = `j' + cond(`j'<2, 1, 2) } } else { di as txt "Not in model" as res _col(18) " 0" /* */ _col(22) %13.3f e(fp_d0) _cont if `normal' di as res _skip(5) %8.0g e(fp_s0) _cont di as txt _skip(1) "`dash'`dash'" local i 1 while `i'<=`maxdf' { local m = 1 + int((`i' - 1) / 2) // degree of model being reported local idf = cond(`i' == 1, `k' * (1 + `cz'), (`k' + 1) * `m' + `k' * `cz') if `i'==1 { di as txt "Linear`catz'" _col(18) as res /* */ %2.0f `idf' _col(22) _cont local dev = e(fp_dlin) local rsd = e(fp_slin) local d = e(fp_d0)-`dev' local n1 `idf' local n2 = e(fp_rdf) - `idf' local pwr 1 } else { di as txt "m = `m'`catz'" _col(18) as res /* */ %2.0f `idf' _col(22) _cont local dev = e(fp_d`m') local rsd = e(fp_s`m') local d = `devlast'-`dev' local n1 = cond(`m'==1, 1, `k' + 1) local n2 = e(fp_rdf) - `idf' local pwr `e(fp_p`m')' } // PR 22mar2009 -end- frac_pv `normal' "`e(fp_wgt)'" `e(fp_N)' `d' `n1' `n2' local P = r(P) if `i'==1 global S_E_Plin `P' else global S_E_P`m' `P' di as res %13.3f `dev' _cont if `normal' di as res _skip(5) %8.0g `rsd' _cont di as res _skip(3) %7.3f `d' %9.3f `P' _skip(2) "`pwr'" local devlast `dev' local i = `i' + cond(`i'==1, 1, 2) } } di as txt "{hline `ddup'}" if "`sequential'"=="" /// di as txt "(*) P-value from deviance difference comparing reported model with m = `degree' model" else /// di as txt "(*) P-value from dev. dif. comparing reported model with next lower df model" if `cz' /// di as txt "(+) indicates dummy variable for `e(fp_rhs)'==0 included in model" end program CheckForNoConstant, sclass syntax [, noConstant * ] sreturn local constant `constant' sreturn local options `"`options'"' end exit 1.2.0/PR/JSP:- replace -all- option with -restrict()- option 1.1.13/PR:- mods in output for compare option for Stata 10. 1.1.12/PR:- translated to Stata 8 1.1.11/JML:- support for extended missing values 1.1.10/PR:- fixed bug in support for streg, stcox 1.1.9/RG:- added support for streg, stcox 1.1.8/WG:- %9.2g changed to %9.2f 1.1.4/WG:- minor title changes 1.1.3/PR:- saves adjustments stored by -fracgen-. - change frac_pp to frac_pq and avoid storing powers in a variable. 1.1.2/PR:- kludge to avoid bug in -glm- with no covariate and noconstant. 1.1.1/PR:- bug fixed, not saving fp_p`j'. Flag fp_cmd2 added and checked. 1.1.0/WG:- translated to Stata 6 1.0.2/PR:- `all' option added to facilitate out-of-sample predictions. Double precision for transformations of xvar. 1.0.1/PR:- added name() option to be passed to fracgen to enable more careful name control by calling program (fracpoly or mfracpol). Version 1.5.4 of old fracpoly (12Jul98). Now used as slave routine for fracpoly.ado and mfracpol.ado.