*! version 2.2.3 06feb2023 MJC /* History MJC 06feb2023: version 2.2.3 - added error check for delayed entry MJC 12oct2022: version 2.2.2 - bug fix; touse caused predictions to fail MJC 02dec2021: version 2.2.1 - bug fix: would error out when no covariates specified; now fixed MJC 16dec2020: version 2.2.0 - synced & doc'd distribution(pwexponential) MJC 03oct2020: version 2.1.0 - now requires merlin 1.12.0: --> requires Stata 15.1 --> bug fix; re-synced distribution(rcs) --> added distribution(ggamma) --> added distribution(lognormal) --> added distribution(loglogistic) MJC 17dec2019: version 2.0.3 - bug: from(), apstartvalues(), restartvalues() and zeros options were not passed to merlin; now fixed MJC 22aug2019: version 2.0.2 - help file edits MJC 26jul2019: version 2.0.1 - post-est help file edits MJC 30jun2019: version 2.0.0 - now parses to merlin - now needs version 14.2 MJC 02jun2014: version 1.0.1 - ln_gamma changed to ln_p when Weibull model fitted - random effects table variable labels were incorrect when random covariate effects were specified, now fixed - likelihoods in stmixed now made comparable to streg exp/weib/gomp models and stpm2 - help file description improved - warning added when only 1 random effect detected -> assumes identity MJC 23may2014: version 1.0.0 */ program stmixed, eclass sortpreserve properties(st) version 15.1 if replay() { if (`"`e(cmd2)'"'!="stmixed") error 301 merlin `0' } else Estimate `0' end program Estimate, eclass st_is 2 analysis cap which merlin if _rc { di as error "stmixed requires merlin, type: ssc install merlin" exit 198 } // model opts local modelopts `"Distribution(string)"' local modelopts `"`modelopts' BHazard(passthru)"' local modelopts `"`modelopts' COVariance(passthru)"' local modelopts `"`modelopts' DF(passthru)"' local modelopts `"`modelopts' KNOTS(passthru)"' local modelopts `"`modelopts' TVC(varlist)"' local modelopts `"`modelopts' DFTvc(string)"' local modelopts `"`modelopts' KNOTSTvc(string)"' local modelopts `"`modelopts' NOORTHog"' local modelopts `"`modelopts' LLFunction(passthru)"' local modelopts `"`modelopts' LOGHFunction(passthru)"' local modelopts `"`modelopts' HFunction(passthru)"' local modelopts `"`modelopts' CHFunction(passthru)"' local modelopts `"`modelopts' NAP(passthru)"' //Max opts local modelopts `"`modelopts' INTPoints(passthru)"' local modelopts `"`modelopts' INTMethod(passthru)"' local modelopts `"`modelopts' FROM(passthru)"' local modelopts `"`modelopts' RESTARTVALues(passthru)"' local modelopts `"`modelopts' APSTARTValues(passthru)"' local modelopts `"`modelopts' ZEROS"' local modelopts `"`modelopts' ADAPTopts(passthru)"' // mlopts local mlopts `"NONRTOLerance NRTOLerance(string)"' local mlopts `"`mlopts' TRace GRADient HESSian showstep"' local mlopts `"`mlopts' TECHnique(string) SHOWNRtolerance"' local mlopts `"`mlopts' ITERate(string) TOLerance(string)"' local mlopts `"`mlopts' LTOLerance(string) GTOLerance(string)"' local mlopts `"`mlopts' DIFficult dots depsilon(passthru) showh"' //Display opts local modelopts `"`modelopts' Level(passthru)"' local modelopts `"`modelopts' NOLOG"' local modelopts `"`modelopts' SHOWMERLIN"' //Undocumented for use by predict and parsing check local modelopts `"`modelopts' debug"' local globallow `"`modelopts' `mlopts'"' local cmdline `0' //parse _parse expand cmd glob : 0 , common(`globallow') if `cmd_n'==1 { if strpos(`"`cmd_1'"',":") { local cmd_2 `cmd_1' local cmd_1 local cmd_n = 2 } else { di as error "Missing level variable" exit 198 } } forvalues k = 1/`cmd_n' { local cmds `"`cmds' `"`cmd_`k''"'"' } _mixed_parseifin stmixed `=`cmd_n'+1' `cmds' `"`glob_if' `glob_in'"' local ifin if _st==1 if "`glob_if'"!="" local ifin `ifin' & `glob_if' if "`glob_in'"!="" local ifin `ifin' & `glob_in' //global options are in glob_op //parse model options local 0 `", `glob_op'"' syntax [ , `modelopts' *] //family local family "`distribution'" local l = length("`family'") if substr("exponential",1,max(1,`l'))=="`family'" { local family exponential } else if substr("pwexponential",1,max(3,`l'))=="`family'" { local family pwexponential } else if substr("weibull",1,max(1,`l'))=="`family'" { local family weibull } else if substr("gompertz",1,max(2,`l'))=="`family'" { local family gompertz } else if substr("ggamma",1,max(2,`l'))=="`family'" { local family ggamma } else if substr("lognormal",1,max(4,`l'))=="`family'" { local family lognormal } else if substr("loglogistic",1,max(4,`l'))=="`family'" { local family loglogistic } else if "rcs"=="`family'" { local family loghazard } else if "addrcs"=="`family'" { local family addhazard } else if "rp"=="`family'" { local family rp } else if "`distribution'"=="user" { local family user local userfunc `llfunction'`loghfunction'`hfunction' `chfunction' } else { di as error "distribution(`distribution') not supported" exit 198 } //delayed entry qui su _t0 `ifin', meanonly if (`r(min)'==0 & `r(max)'>0) { di as error "{p}delayed entry detected for a subset of " /// "observations; must be all or none{p_end}" exit 198 } if `r(max)'>0 & `r(min)'>0 { local ltruncated ltruncated(_t0) di as text "note; a delayed entry model is being fitted" } //parse mlopts mlopts mlopts , `options' //extra baseline splines for family(rcs) if "`family'"=="loghazard" | "`family'"=="addhazard" { if "`noorthog'"=="" local orth orthog local rcsbase rcs(_t, `df' `knots' `orth' log event) local timevar timevar(_t) local df } //final family local family family(`family', failure(_d) /// `userfunc' `bhazard' `ltruncated' `df' `knots' `noorthog') //parse mlopts mlopts mlopts , `options' //===================================================================// // build complex predictor local Mind = 1 //level 1 can be parsed straight off fvexpand `cmd_1' //handles var1-var15 etc local merlincp `r(varlist)' //tvcs if "`tvc'"!="" { if "`dftvc'"=="" & "`knotstvc'"=="" { di as error "dftvc() or knotstvc() required" exit 198 } if "`dftvc'"!="" local tvck df(`dftvc') else local tvck knots(`knotstvc') foreach var in `tvc' { local merlincp `merlincp' `var'#rcs(_t, `tvck' log orthog) } local timevar timevar(_t) } //baseline splines for rcs local merlincp `merlincp' `rcsbase' //random effects forval lev=2/`cmd_n' { //extract level var gettoken levvar rest : cmd_`lev', parse(":") gettoken colon rest : rest , parse(":") if `"`colon'"' == `":"' { local lev = trim("`levvar'") if "`levvar'" != "_all" { confirm variable `levvar' } else { di as error "_all not supported" exit 198 } } else { di as err "{p 0 6 2}invalid random-effects " di as err "specification; perhaps you omitted the " di as err "colon after the level " di as err "variable{p_end}" exit 198 } local levelvars `levelvars' `levvar' local lev`lev' = subinstr("`levelvars'"," ",">",.) //random effects local 0 `rest' syntax [varlist(numeric default=none)] [, NOConstant] if ("`noconstant'"!="" & "`varlist'"=="") { di as error "No random effects have been specified at level `levvar':" exit 198 } if "`noconstant'"=="" { local merlincp `merlincp' M`Mind'[`lev`lev'']@1 di as text "Random effect M`Mind': Intercept at level `levvar'" local Mind = `Mind' + 1 } local Nvars : word count of `varlist' foreach var in `varlist' { local merlincp `merlincp' `var'#M`Mind'[`lev`lev'']@1 di as text "Random effect M`Mind': `var' at level `levvar'" local Mind = `Mind' + 1 } } //===================================================================// // merlin if "`debug'"!="" { di "`merlincp'" di "`family'" } if "`showmerlin'"!="" { di "merlin (_t `merlincp', `family' `timevar') `ifin' , `mlopts' `covariance' `intmethod' `intpoints' `from' `debug' `restartvalues' `nolog' `adaptopts' `level'" } merlin (_t `merlincp', `family' `timevar') /// `ifin' , /// excalibur /// `mlopts' /// `covariance' `intmethod' /// `intpoints' `from' `debug' /// `restartvalues' `nolog' `adaptopts' /// `level' `zeros' `restartvalues' /// `apstartvalues' ereturn local cmd2 stmixed ereturn local cmdline2 stmixed `cmdline' end