*! version 1.3.2 15aug2012 MJC /* History MJC 15aug2012: version 1.3.2 - erroneous sort caused fulldata to be invoked when unnecessary, now fixed MJC 11aug2012: version 1.3.1 - renamed to stjm11 - bug with delayed entry fpm models fixed - fulldata option added - adaptit() default changed to 5 MJC 02feb2012: version 1.3.0 - Implemented adaptive GH quadrature which is now the default. timeinteraction, assoccovariates options added. MJC 20oct2011: version 1.2.0 - Added Gompertz and Exponential survival submodels. Added covariance options consistent with xtmixed. MJC 14oct2011: version 1.1.0 - Weibull survival submodel now allowed. Delayed entry re-written, now allowing time-varying covariates in survival submodel. - Bug fix: fixed error when rfracp or ffracp was 0 with min(_t0) = 0 MJC 10oct2011: version 1.0.0 */ program stjm11 version 11.2 if replay() { if (`"`e(cmd)'"' !="stjm11") error 301 Replay `0' } else Estimate `0' end program Estimate, eclass sortpreserve st_is 2 analysis syntax varlist(min=1 numeric) [if] [in] , /// Panel(varname) /// -Patient identifier- SURVModel(string) /// -Survival submodel choice- /// [ /// /* Longitudinal model options */ /// RFRACPoly(numlist max=5 asc) /// -Random time power variables- FFRACPoly(numlist max=5 asc) /// -Fixed time power variables- TIMEINTERACtion(varlist numeric) /// -Covariates to interact with fixed time variables- COVariance(string) /// -Covariance structure- /// /* Survival model options */ /// SURVCov(varlist numeric) /// -Covariates to include in the survival submodel- DF(string) /// -Degrees of freedom for FPM- KNOTS(numlist) /// -Knot locations for baseline hazard function- NOORTHog /// -Do not orthoganalise splines- /// /* Association options */ /// ASSOCCOVariates(varlist) /// -Adjust association parameters by covariates- NOCurrent /// -Assciation not based on current value- DERIVASSOCiation /// -Association based on derivatives- INTASSOCiation /// -Association based on random intercept- ASSOCiation(numlist max=5) /// -Association based on random slope/etc.- /// /* Results display options */ /// SHOWINITial /// -Show output from fitting initial value models- VARiance /// -Display variances-covariances in random effects table- SHOWCons /// -Show spline constraints- KEEPCons /// -Do not drop constraints used in ml routine- Level(cilevel) /// -Statistical significance level- /// /* Maximisation options */ /// GH(string) /// -Number of Gauss-Hermite nodes- GK(string) /// -Number of Gauss-Kronrod nodes- ADAPTIT(string) /// -Number of adaptive iterations to do- NONADAPT /// -Use non-adaptive quadrature- NULLAssoc /// -Initial values for association parameters set to zero- FULLdata /// -Use all rows of survival data in estimation- NOLOG /// -Suppress log-likelihood iteration log- * /// -ML options- ] /******************************************************************************************************************************************************************************************/ /* ERROR CHECKS */ local l = length("`survmodel'") if substr("exponential",1,max(1,`l')) == "`survmodel'" { local smodel "e" } else if substr("weibull",1,max(1,`l')) == "`survmodel'" { local smodel "w" } else if substr("gompertz",1,max(1,`l')) == "`survmodel'" { local smodel "g" } else if "fpm" == "`survmodel'" { local smodel "fpm" } else { di as error "Unknown survival submodel" exit 198 } global smodel "`smodel'" if "`covariance'"=="" { local cov "unstr" global labtextvcv "Unstructured" } else { local l = length("`covariance'") if substr("independent",1,max(3,`l')) == "`covariance'" { local cov "ind" global labtextvcv "Independent" } else if substr("exchangeable",1,max(2,`l')) == "`covariance'" { local cov "exch" global labtextvcv "Exchangeable" } else if substr("identity",1,max(2,`l')) == "`covariance'" { local cov "iden" global labtextvcv "Identity" } else if substr("unstructured",1,max(2,`l')) == "`covariance'" { local cov "unstr" global labtextvcv "Unstructured" } else { di as error "Unknown variance-covariance structure" exit 198 } } global cov "`cov'" /* Weights not allowed */ if "`weight'" != "" { display as err "weights not allowed" exit 198 } local wt: char _dta[st_w] if "`wt'" != "" { display as err "weights not allowed" exit 198 } /* Factor variables not allowed */ fvexpand `varlist' `survcov' `timeinteraction' `assoccovariates' if "`r(fvops)'" != "" { display as error "Factor variables not allowed. Create your own dummy varibles." exit 198 } if "`smodel'"=="fpm" { capture which stpm2 if _rc >0 { display in yellow "You need to install the command stpm2. This can be installed using," display in yellow ". {stata ssc install stpm2}" exit 198 } capture which rcsgen if _rc >0 { display in yellow "You need to install the command rcsgen. This can be installed using," display in yellow ". {stata ssc install rcsgen}" exit 198 } /* Check stpm2 is up to date */ qui findfile stpm2.ado mata: fh = fopen(st_global("r(fn)"),"r") mata: st_local("line1",fget(fh)) mata: fclose(fh) local line1 = trim("`line1'") local l = length("`line1'") local date = lower(substr("`line1'",`=`l'-9',`l')) local datenum = td("`date'") if `datenum'<18879 { di as error "You need to update the command stpm2. This can be installed using," display in yellow ". {stata ssc install stpm2, replace}" exit 198 } } if "`smodel'"!="fpm" & ("`df'"!="" | "`knots'"!="") { di as error "Can only specify df/knots when survmodel = fpm" exit 198 } if "`rfracpoly'"=="" & "`ffracpoly'"=="" { di as error "One of rfracpoly and ffracpoly must be specified" exit 198 } if "`rfracpoly'"=="" & "`decomp'"!="" { di as error "Decomposition can only be used when multiple random effects are specified" exit 198 } if ("`nocurrent'"!="" & "`intassociation'"=="" & "`association'"=="" & "`derivassociation'"=="") { di as error "No association between submodels has been specified" exit 198 } if ("`derivassociation'"!="" & "`rfracpoly'"=="") { di as error "Random time variables must be specified for derivative association." exit 198 } if ("`association'"!="" & "`rfracpoly'"=="") { di as error "Random time variables must be specified for separate association." exit 198 } if "`rfracpoly'"!="" { foreach re of numlist `rfracpoly' { if (`re'!=-5 & `re'!=-4 & `re'!=-3 & `re'!=-2 & `re'!=-1 & `re'!=-0.5 & `re'!=0 & `re'!=0.5 & `re'!=1 & `re'!=2 & `re'!=3 & `re'!=4 & `re'!=5) { di as error "FP1 powers must be one of -2, -1, -.5, 0, .5, 1, 2, 3" exit 198 } } } if "`ffracpoly'"!="" { foreach fe of numlist `ffracpoly' { if (`fe'!=-5 & `fe'!=-4 & `fe'!=-3 & `fe'!=-2 & `fe'!=-1 & `fe'!=-0.5 & `fe'!=0 & `fe'!=0.5 & `fe'!=1 & `fe'!=2 & `fe'!=3 & `fe'!=4 & `fe'!=5) { di as error "FP1 powers must be one of -2, -1, -.5, 0, .5, 1, 2, 3" exit 198 } } } local dumcheck = 0 if "`rfracpoly'"!="" & "`ffracpoly'"!="" { foreach re of numlist `rfracpoly' { foreach fe of numlist `ffracpoly' { if "`re'"=="`fe'" { local dumcheck = 1 } } } } if `dumcheck'==1 { di as error "You cannot specify both a fixed and random fracpoly with the same power" exit 198 } if ("`association'"!="" & "`rfracpoly'"!="") { /*check separate associations are specified in rfracpoly */ local dumcheck = 0 local finalcheck = 0 foreach a of numlist `association' { foreach b of numlist `rfracpoly' { if `a'==`b' { local dumcheck = 1 } } if `dumcheck'==0 { local finalcheck = 1 } } if `finalcheck'==1 { di as error "Elements of association must be in rfracpoly" exit 198 } } if "`showcons'"!="" & "`smodel'"!="fpm" { di as error "showcons only allowed when survmodel = fpm" exit 198 } if "`gk'"!="" { if "`gk'"!="15" & "`gk'"!="7" { di as error "gk must be 7 or 15" exit 198 } } if "`smodel'"=="fpm" & "`df'"=="" & "`knots'"=="" { di as error "One of df or knots must be specified" exit 198 } if "`smodel'"=="fpm" { if "`df'"!="" & "`knots'"!="" { di as error "Only one of df and knots can be specified" exit 198 } } if "`adaptit'"!="" { cap confirm integer number `adaptit' if _rc>0 { di as error "adaptit must be an integer" exit 198 } if `adaptit'<0 { di as error "adaptit must be >0" exit 198 } } else local adaptit = 5 if "`gh'"!="" { cap confirm integer number `gh' if _rc>0 { di as error "gh must be an integer" exit 198 } if `gh'<2 { di as error "gh must be > 1" exit 198 } } else { if "`nonadapt'"=="" { local gh = 5 } else { local gh = 15 } } /******************************************************************************************************************************************************************************************/ /* DEFAULTS */ if "`showinitial'"!="" { local noisily "noisily" } if "`noorthog'"!="" { local orthog "noorthog" } else { local orthog } if "`smodel'"!="fpm" & "`gk'"==""{ local gk = 15 } if "`timeinteraction'"!="" { global timeinterac yes } else { global timeinterac no } /******************************************************************************************************************************************************************************************/ /* Preliminaries */ /* Mark estimation sample */ marksample touse markout `touse' `survcov' `timeinteraction' `assoccovariates' global touse `touse' qui replace `touse' = 0 if _st==0 /* Extract longitudinal outcome and any fixed covariates in long. submodel */ gettoken lhs rhs : varlist /* Extract any ml options to pass to ml model */ mlopts mlopts , `options' local extra_constraints `s(constraints)' /* Generate temporary patient ID variable */ tempvar _tempid qui egen `_tempid' = group(`panel') if `touse'==1 global MY_panel "`_tempid'" /* Calculate number of repeated measurements */ qui count if `touse'==1 global nmeasures = `r(N)' /* Generate final row indicator variable */ tempvar surv_ind qui bys `_tempid' (_t0): gen `surv_ind'= (_n==_N & `touse'==1) global surv_indlab "`surv_ind'" /* Calculate number of patients */ qui count if `surv_ind'==1 global Npat = `r(N)' /* Number of covariates in each submodel */ local n_scovs : word count `survcov' //list sizeof in extended macros local n_lcovs : word count `rhs' /* Number of measurements per patient */ tempvar n_meas qui bys `_tempid' (_t0): gen `n_meas' = _N if `touse'==1 global nmeasvar `n_meas' /* Numbers */ global n_ftime : word count `ffracpoly' /* Number of fixed fractional polynomials of time - d0 and results table */ global n_rtime : word count `rfracpoly' /* Number of random fractional polynomials of time - results table */ global n_tot_long_eqns = $n_rtime + $n_ftime +1 /* Number of model equations in longitudinal submodel - results table */ global npows = $n_ftime + $n_rtime /* Number of time variables */ global n_re = $n_rtime + 1 /* Total number of random effects */ /* Drop previously created timevars */ cap drop _time_* /* Put fixed and random FP's in ascending order */ numlist "`ffracpoly' `rfracpoly'", sort local fps `r(numlist)' /* Use fracgen to extract `shift' if needed */ local firstpow : word 1 of `fps' if `firstpow' <= 0 { qui fracgen _t0 `fps' if `touse', noscaling nogen local shift = `r(shift)' } else { local shift = 0 } mata: shift = `shift' /* Adjust _t and _t0 for centring of FP's using tempvars */ tempvar stime basetime qui gen double `stime' = _t + `shift' if `touse'==1 qui gen double `basetime' = _t0 + `shift' if `touse'==1 local survtimevar `stime' /* To read into Mata */ local basetimevar `basetime' /* Check time origin for delayed entry models */ global del_entry = 0 tempvar del_surv_ind cap sort `_tempid' _t0 by `_tempid': gen `del_surv_ind' = (_n==1 & `touse'==1) //summary passed to below quick/slow check if "`association'"!="" { global n_time_assoc : word count `association' mat timeassoc_fixed_ind = J($n_time_assoc,1,.) } /******************************************************************************************************************************************************************************************/ /* Things to pass to results table */ global panel `panel' /* Name of panel variable */ if "`cov'"=="ind" | "`cov'"=="iden" { global n_cov_params = 0 } else if "`cov'"=="unstr" { local cov_list "0 1 3 6 10 15" global n_cov_params : word $n_re of `cov_list' /* Number of covariance parameters */ } else { global n_cov_params = 1 } /******************************************************************************************************************************************************************************************/ /* Quick or slow */ if "`fulldata'"=="" & "`survmodel'"!="fpm" { if "`survcov'"!="" | "`assoccovariates'"!="" { local nvardiffs = 0 foreach var of varlist `survcov' `assoccovariates' { tempvar ind_`var' qui bys `_tempid' (_t0): gen `ind_`var'' = (`var'[_n]==`var'[_n+1]) if _n<_N & _N>1 qui bys `_tempid' (_t0): replace `ind_`var'' = (`var'[_n]==`var'[_n-1]) if _n==_N & _N>1 qui count if `ind_`var''==0 local nvardiffs = `nvardiffs' + `r(N)' } if `nvardiffs'==0 { local quick quick } } else local quick quick } if "`quick'"=="" | "`survmodel'"=="fpm" { local newdelsurvtouse "`touse'" local newsurvtouse "`touse'" local nsurvrows = $nmeasures global quick di in yellow "Warning -> all rows of data are being used in the survival component of the likelihood." di in yellow " -> care must be taken if missing data is present, see the help file for details." di "" } else { local newdelsurvtouse "`del_surv_ind'" local newsurvtouse "`surv_ind'" local nsurvrows = $Npat global quick _quick } global newsurvtouse "`newsurvtouse'" qui summ _t0 if `newdelsurvtouse'==1, meanonly if `r(max)'>0 | "`survmodel'"=="fpm" { display in green "note: delayed entry models are being fitted" global del_entry 1 global del_survindlab "`del_surv_ind'" } /******************************************************************************************************************************************************************************************/ /* Create time variables */ /* Indicator matrix to denote random FP's */ mat rand_ind = J(1,$npows,0) /* Matrix to store FP powers */ mat fp_pows = J(1,$npows,.) /* Generate timevars */ local j = 1 local tassoc_ind = 1 local tfi_ind = 1 foreach i of numlist `fps' { mat fp_pows[1,`j'] = `i' /* Store powers in matrix for Mata */ /* Generate timevars for dataset and display text*/ /* Generate timevars at survival times for d0, including d/dt for hazard function */ tempvar time_surv_`j' if (`i'!=0) { qui gen double _time_`j' = (`basetime')^(`i') if `touse'==1 qui gen double `time_surv_`j'' = (`stime')^(`i') if `touse'==1 /* first derivative of time variables d/dt*/ if "`smodel'"=="fpm" | "`derivassociation'"!="" { tempvar diff_time_`j' diff_time_surv_`j' qui gen double `diff_time_`j'' = `i'*(`basetime')^(`=`i'-1') if `touse'==1 qui gen double `diff_time_surv_`j'' = `i'*(`stime')^(`=`i'-1') if `touse'==1 local diff_fp_timevar_names "`diff_fp_timevar_names' `diff_time_`j''" local diff_fp_timevar_names_surv "`diff_fp_timevar_names_surv' `diff_time_surv_`j''" } /* second derivative of time variables d2/dt2*/ if "`smodel'"=="fpm" & "`derivassociation'"!="" { tempvar 2_diff_time_`j' 2_diff_time_surv_`j' if `i'!=1 { qui gen double `2_diff_time_`j'' = (`=`i'-1')*(`i')*(`basetime')^(`=`i'-2') if `touse'==1 qui gen double `2_diff_time_surv_`j'' = (`=`i'-1')*(`i')*(`stime')^(`=`i'-2') if `touse'==1 } else { qui gen double `2_diff_time_`j'' = 0 if `touse'==1 qui gen double `2_diff_time_surv_`j'' = 0 if `touse'==1 } local 2_diff_fp_timevar_names "`2_diff_fp_timevar_names' `2_diff_time_`j''" local 2_diff_fp_timevar_names_surv "`2_diff_fp_timevar_names_surv' `2_diff_time_surv_`j''" } n di in green "-> gen double _time_`j' = X^(`i')" label variable _time_`j' "_time_`j' = X^(`i') `xtxt'" } else { qui gen double _time_`j' = log(`basetime') if `touse'==1 qui gen double `time_surv_`j'' = log(`stime') if `touse'==1 if "`smodel'"=="fpm" | "`derivassociation'"!="" { tempvar diff_time_`j' diff_time_surv_`j' qui gen double `diff_time_`j'' = 1/(`basetime') if `touse'==1 qui gen double `diff_time_surv_`j'' = 1/(`stime') if `touse'==1 local diff_fp_timevar_names "`diff_fp_timevar_names' `diff_time_`j''" local diff_fp_timevar_names_surv "`diff_fp_timevar_names_surv' `diff_time_surv_`j''" } if "`smodel'"=="fpm" & "`derivassociation'"!="" { tempvar 2_diff_time_`j' 2_diff_time_surv_`j' qui gen double `2_diff_time_`j'' = -1/((`basetime')^2) if `touse'==1 qui gen double `2_diff_time_surv_`j'' = -1/((`stime')^2) if `touse'==1 local 2_diff_fp_timevar_names "`2_diff_fp_timevar_names' `2_diff_time_`j''" local 2_diff_fp_timevar_names_surv "`2_diff_fp_timevar_names_surv' `2_diff_time_surv_`j''" } n di in green "-> gen double _time_`j' = log(X)" label variable _time_`j' "_time_`j' = log(X) `xtxt'" } local fp_timevar_names "`fp_timevar_names' _time_`j'" /* Timevar variable names for Mata */ local fp_timevar_names_surv "`fp_timevar_names_surv' `time_surv_`j''" /* Variable names to read into Mata */ if "`rfracpoly'"!=""{ foreach re of numlist `rfracpoly' { if `re'==`i' { mat rand_ind[1,`j'] = 1 /* Ref matrix for mata to identify which ones are random */ local re_timevars "`re_timevars' _time_`j'" /* Time variable names of random time variables for xtmixed call and for predictions */ local re_timevars_surv "`re_timevars_surv' `time_surv_`j''" if "`smodel'"=="fpm" | "`derivassociation'"!="" { local diff_re_timevars "`diff_re_timevars' `diff_time_`j''" local diff_re_timevars_surv "`diff_re_timevars_surv' `diff_time_surv_`j''" } if "`smodel'"=="fpm" & "`derivassociation'"!="" { local 2_diff_re_timevars "`2_diff_re_timevars' `2_diff_time_`j''" local 2_diff_re_timevars_surv "`2_diff_re_timevars_surv' `2_diff_time_surv_`j''" } } } } if "`association'"!="" { local dumtest = 0 foreach ass in `association' { if `i'==`ass' { mat timeassoc_fixed_ind[`tfi_ind',1] = `tassoc_ind' local `++tfi_ind' } } local `++tassoc_ind' } /****************************************************************************************************************************************/ /* time and covariate interactions */ if "`timeinteraction'"!="" { foreach covtime of varlist `timeinteraction' { tempvar interac_t0_`j'_`covtime' interac_t_`j'_`covtime' qui gen double _time_`j'_`covtime' = `covtime' * _time_`j' if `touse'==1 qui gen double `interac_t_`j'_`covtime'' = `covtime' * `time_surv_`j'' if `touse'==1 local covinterlist1 "`covinterlist1' _time_`j'_`covtime'" local covinterlist2 "`covinterlist2' `interac_t_`j'_`covtime''" n di in green "-> gen double _time_`j'_`covtime' = `covtime' * _time_`j'" label variable _time_`j'_`covtime' "_time_`j'_`covtime' = `covtime' * _time_`j'" local `++tassoc_ind' } if "`smodel'"=="fpm" | "`derivassociation'"!="" { foreach covtime of varlist `timeinteraction' { tempvar deriv_interac_t_`j'_`covtime' qui gen double `deriv_interac_t_`j'_`covtime'' = `covtime' * `diff_time_surv_`j'' if `touse'==1 local deriv_covinterlist_surv "`deriv_covinterlist_surv' `deriv_interac_t_`j'_`covtime''" if "`smodel'"=="fpm"{ tempvar deriv_interac_t0_`j'_`covtime' qui gen double `deriv_interac_t0_`j'_`covtime'' = `covtime' * `diff_time_`j'' if `touse'==1 local deriv_covinterlist_long "`deriv_covinterlist_long' `deriv_interac_t0_`j'_`covtime''" } } } if "`smodel'"=="fpm" & "`derivassociation'"!="" { foreach covtime of varlist `timeinteraction' { tempvar deriv2_interac_t_`j'_`covtime' qui gen double `deriv2_interac_t_`j'_`covtime'' = `covtime' * `2_diff_time_surv_`j'' if `touse'==1 local deriv2_covinterlist_surv "`deriv2_covinterlist_surv' `deriv2_interac_t_`j'_`covtime''" } } } local `++j' } global ninterac : word count `timeinteraction' scalar ntimecovinterac = $ninterac mat rand_ind_gk = J(1,$n_re,`=$npows+1+$ninterac+`n_lcovs'') local nj=1 forvalues i=1/$npows { if rand_ind[1,`i']==1 { mat rand_ind_gk[1,`nj']=`i' local `++nj' } } mata: rand_ind_gk = st_matrix("rand_ind_gk") if `shift'==0 { n di in green "(where X = _t0)" } else { n di in green "(where X = _t0 + `shift')" } /* Variance ml equation names */ if "`cov'"=="ind" | "`cov'"=="unstr" { forvalues i=1/$n_re { local var_re_eqn_names "`var_re_eqn_names' /lns_`i'" } } else { local var_re_eqn_names "/lns_1" } local fp_eqn_names "(Longitudinal: `lhs'= `fp_timevar_names' `covinterlist1' `rhs')" /* Longitudinal ml equation */ global retimelabelnames2 "`re_timevars' _cons" /* For results table */ /******************************************************************************************************************************************************************************************/ /* Pass design matrices of timevars to Mata */ /* Fixed effect design matrices at exit times */ local longparams_surv "`fp_timevar_names_surv' `covinterlist2' `rhs'" mata: X_dm_surv = st_data(.,tokens(st_local("longparams_surv")),st_local("newsurvtouse")),J(`nsurvrows',1,1) if "`rfracpoly'"!="" { mata: Z_dm = st_data(.,tokens(st_local("re_timevars")),st_local("touse")),J($nmeasures,1,1) mata: Z_dm_surv = st_data(.,tokens(st_local("re_timevars_surv")),st_local("newsurvtouse")),J(`nsurvrows',1,1) } else { mata: Z_dm = J($nmeasures,1,1) mata: Z_dm_surv = J(`nsurvrows',1,1) } if "`smodel'"=="fpm" | "`derivassociation'"!="" { local ntemp = `n_lcovs' + 1 local diff_fp_timevar_names "`diff_fp_timevar_names' `deriv_covinterlist_long'" local diff_fp_timevar_names_surv "`diff_fp_timevar_names_surv' `deriv_covinterlist_surv'" mata: diff_X_dm = st_data(.,tokens(st_local("diff_fp_timevar_names")),st_local("newdelsurvtouse")),J(`nsurvrows',`ntemp',0) mata: diff_X_dm_surv = st_data(.,tokens(st_local("diff_fp_timevar_names_surv")),st_local("newsurvtouse")),J(`nsurvrows',`ntemp',0) if "`rfracpoly'"!="" { mata: diff_Z_dm = st_data(.,tokens(st_local("diff_re_timevars")),st_local("newdelsurvtouse")),J(`nsurvrows',1,0) mata: diff_Z_dm_surv = st_data(.,tokens(st_local("diff_re_timevars_surv")),st_local("newsurvtouse")),J(`nsurvrows',1,0) } else { mata: diff_Z_dm = diff_Z_dm_surv = J(`nsurvrows',1,0) } } else { mata: diff_X_dm = diff_X_dm_surv = diff_Z_dm = diff_Z_dm_surv = J(`nsurvrows',1,0) } if "`smodel'"=="fpm" & "`derivassociation'"!="" { local 2_diff_fp_timevar_names_surv "`2_diff_fp_timevar_names_surv' `deriv2_covinterlist_surv'" mata: diff2_X_dm_surv = st_data(.,tokens(st_local("2_diff_fp_timevar_names_surv")),st_local("newsurvtouse")),J(`nsurvrows',`ntemp',0) if "`rfracpoly'"!="" { mata: diff2_Z_dm_surv = st_data(.,tokens(st_local("2_diff_re_timevars_surv")),st_local("newsurvtouse")),J(`nsurvrows',1,0) } else { mata: diff2_Z_dm_surv = J(`nsurvrows',1,0) } } else { mata: diff2_X_dm_surv = 0 mata: diff2_Z_dm_surv = 0 } /******************************************************************************************************************************************************************************************/ /* ASSOCIATION PARAMETERISATION */ global n_sepassoc : word count `association' local alpha_ith = 1 if "`nocurrent'"=="" { global current "yes" local alphaequation "`alphaequation' (alpha_`alpha_ith': `assoccovariates')" /* current association - default */ local `++alpha_ith' } else { global current "no" } if "`derivassociation'"!="" { global deriv "yes" local alphaequation "`alphaequation'(alpha_`alpha_ith': `assoccovariates')" /* association based on derivatives */ local `++alpha_ith' } else { global deriv "no" } if "`intassociation'"!="" { /* association based on random intercept */ global intassoc "yes" local alphaequation "`alphaequation'(alpha_`alpha_ith': `assoccovariates')" local `++alpha_ith' } else { global intassoc "no" } if "`association'"!="" { /* association based on random coefficient */ global timeassoc "yes" foreach assoc of numlist `association' { local alphaequation "`alphaequation'(alpha_`alpha_ith': `assoccovariates')" local `++alpha_ith' } } else { global timeassoc "no" } global n_alpha = `alpha_ith' - 1 /* Number of association parameters */ /******************************************************************************************************************************************************************************************/ /* INITIAL VALUES */ quietly{ noisily di noisily di as txt "Obtaining initial values:" noisily di tempname initmat /* Longitudinal model initial values */ `noisily' xtmixed `lhs' `fp_timevar_names' `covinterlist1' `rhs' if `touse' || `_tempid': `re_timevars', cov(`cov') `variance' matrix `initmat' = e(b) /* predict RE's and seRE's */ forvalues i=1/$n_re { tempvar blup`i' seblup`i' local blupnames "`blupnames' `blup`i''" local seblupnames "`seblupnames' `seblup`i''" } predict `blupnames' if `touse', reffects predict `seblupnames' if `touse', reses if "`nocurrent'"=="" { tempvar fitvals predict `fitvals' if `touse', fitted if "`assoccovariates'"!="" { foreach var of varlist `assoccovariates' { tempvar assocint_`var' qui gen double `assocint_`var'' = `fitvals'*`var' local associntlist1 "`associntlist1' `assocint_`var''" } } local alpha_di_txt "assoc:value" } if "`intassociation'"!="" | "`association'"!="" | "`derivassociation'"!=""{ /* predict RE's */ forvalues i=1/$n_re { tempvar sepassoc`i' local refnames "`refnames' `sepassoc`i''" } predict `refnames' if `touse', reffects if "`derivassociation'"!="" { local i = 1 foreach pow of numlist `fps' { local basis_pow`i' = `pow' local `++i' } tempvar deriv_1 qui gen `deriv_1' = 0 local stub = 1 local re_stub = 1 foreach pow of numlist `fps' { if `pow'!=0 { if rand_ind[1,`stub']==1 { local derivadd "(([`lhs'][_time_`stub'] + `sepassoc`re_stub'')*(`pow')*`basetime'^(`pow'-1))" local `++re_stub' } else { local derivadd "([`lhs'][_time_`stub']*(`pow')*`basetime'^(`pow'-1))" } } else { if rand_ind[1,`stub']==1 { local derivadd "(([`lhs'][_time_`stub'] + `sepassoc`re_stub'')/`basetime')" local `++re_stub' } else { local derivadd "([`lhs'][_time_`stub']/`basetime')" } } if "`timeinteraction'"!="" { foreach var of varlist `timeinteraction' { local derivadd2 "`derivadd2' + `derivadd'*`var' " } } replace `deriv_1' = `deriv_1' + (`derivadd') `derivadd2' local `++stub' } if "`assoccovariates'"!="" { foreach var of varlist `assoccovariates' { tempvar assocderivint_`var' qui gen double `assocderivint_`var'' = `deriv_1'*`var' local associntlist2 "`associntlist2' `assocderivint_`var''" } } local derivlist "`deriv_1'" local alpha_di_txt "`alpha_di_txt' assoc:slope" } if "`intassociation'"!="" { local sepassocnameint "`sepassoc$n_re'" if "`assoccovariates'"!="" { foreach var of varlist `assoccovariates' { tempvar associntint_`var' qui gen double `associntint_`var'' = `sepassoc$n_re'*`var' local associntlist3 "`associntlist3' `associntint_`var''" } } local alpha_di_txt "`alpha_di_txt' assoc:int" } if "`association'"!="" { //need to extract random time variables whose coefficients are specified for the association //index random time variables mat timeassoc_re_ind = J($n_time_assoc,1,.) local re = 1 local ind = 1 foreach repow of numlist `rfracpoly' { foreach ass of numlist `association' { if `repow'==`ass' { mat timeassoc_re_ind[`ind',1] = `re' local `++ind' } } local `++re' } local ind_row = 1 foreach a of numlist `association' { local ind_re = 1 foreach b of numlist `fps' { if `a'==`b' { if "`assoccovariates'"!="" { foreach var of varlist `assoccovariates' { tempvar associntsep_`var' qui gen double `associntsep_`var'' = `sepassoc`ind_row''*`var' local sepassocnames "`sepassocnames' `associntsep_`var''" } } local sepassocnames "`sepassocnames' `sepassoc`ind_row''" local sepassocpred "`sepassocpred' `ind_re'" local alpha_di_txt "`alpha_di_txt' a:_time_`ind_re'" } local `++ind_re' } local `++ind_row' } } } global alpha_di_txt `alpha_di_txt' if "`cov'"=="exch" & $n_re>1 { local corr_eqn_names "/art_1_1" local corr_eqn_names2 "art_1_1" } else if "`cov'"=="unstr" { local subind = 1 while (`subind'<$n_re) { forvalues i=`=`subind'+1'/$n_re { local corr_eqn_names "`corr_eqn_names' /art_`subind'_`i'" local corr_eqn_names2 "`corr_eqn_names2' art_`subind'_`i'" } local `++subind' } } local longequation "`fp_eqn_names' `var_re_eqn_names' `corr_eqn_names' /lns_e" local nvcvparams : word count `var_re_eqn_names' `corr_eqn_names' /*********************************/ /* Survival model initial values */ local searchopt "search(off)" tempname initmatsurv /* Flexible parametric model */ if "`smodel'"=="fpm" { if "`df'"!="" { local splines "df(`df')" } else { local splines "knots(`knots')" } `noisily' stpm2 `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `survcov' if `touse', `splines' scale(hazard) `orthog' failconvlininit /* initial values from stpm2 fit, keeping constraints */ local ln_bhknots `e(ln_bhknots)' local nalphacovs : word count `assoccovariates' local n1 = $n_alpha * (`nalphacovs' +1 ) + `n_scovs' + 2*`df' + 1 local n2 = `n1' + $n_alpha * (`nalphacovs' +1 ) + 1 tempname mat1 mat `mat1' = e(b) mat `initmatsurv' = `mat1'[1,1..`n1'] mat `initmatsurv' = `initmatsurv',`mat1'[1,`n2'..colsof(`mat1')] tempname R_bh mat `R_bh' = e(R_bh) /* rcs and drcs names */ local rcsnames "`e(rcsterms_base)'" local drcsnames "`e(drcsterms_base)'" if "`df'"=="" { local df : word count `rcsnames' } /* Constraints */ forvalues i=1/`df' { local r`i' : word `i' of `rcsnames' local dr`i' : word `i' of `drcsnames' constraint free constraint `r(free)' [xb][`r`i'']=[dxb][`dr`i''] local conslist "`conslist' `r(free)'" /* Delayed entry */ local srcsnames "`srcsnames' _s0_rcs`i'" constraint free constraint `r(free)' [xb][`r`i'']=[xb0][_s0_rcs`i'] local conslist "`conslist' `r(free)'" } local xb0_eqn "(xb0: `survcov' `srcsnames')" constraint free constraint `r(free)' [xb][_cons]=[xb0][_cons] local conslist "`conslist' `r(free)'" if "`survcov'"!="" { foreach var in `survcov' { constraint free constraint `r(free)' [xb][`var']=[xb0][`var'] local conslist "`conslist' `r(free)'" } } local dropconslist `conslist' /* If further constraints are listed stpm2 then remove this from mlopts and add to conslist */ if "`extra_constraints'" != "" { local mlopts : subinstr local mlopts "constraints(`extra_constraints')" "", word local conslist `conslist' `extra_constraints' } global constnums `conslist' local constopts "constraints($constnums)" local collinopt "collinear" /* pass collinear option as ml can drop spline variables when it shouldn't */ local survequation "(xb: `survcov' `rcsnames') (dxb: `drcsnames', nocons) `xb0_eqn'" /* rcs and drcs equations to pass to ml model */ } /* Exponential PH model */ else if "`smodel'"=="e" { `noisily' streg `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `survcov' if `touse', dist(exp) nohr /* initial values from streg fit */ mat `initmatsurv' = e(b) local survequation "(ln_lambda: `survcov')" } /* Weibull PH model */ else if "`smodel'"=="w" { `noisily' streg `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `survcov' if `touse', dist(weibull) nohr /* initial values from streg fit */ mat `initmatsurv' = e(b) local survequation "(ln_lambda: `survcov') /ln_gamma" } /* Gompertz PH model */ else if "`smodel'"=="g" { `noisily' streg `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `survcov' if `touse', dist(gompertz) nohr /* initial values from streg fit */ mat `initmatsurv' = e(b) local survequation "(ln_lambda: `survcov') /gamma" } if ("`nullassoc'"!="" & "`nocurrent'"=="") { forvalues i=1/$n_alpha { mat `initmatsurv'[1,`i']=0 } } matrix `initmat' = `initmat',`initmatsurv' /* Generate quadrature node and weight matrices */ ghquadm `gh' nodes weights } /******************************************************************************************************************************************************************************************/ /* Mata */ mata: y_ij = st_data(.,st_local("lhs"),st_local("touse")) /* Response */ mata: del_entry_time = st_data(.,st_local("basetimevar"),st_local("newdelsurvtouse")) mata: stime = st_data(.,st_local("survtimevar"),st_local("newsurvtouse")) /* Survival time */ mata: d = st_data(.,"_d",st_local("newsurvtouse")) /* Event indicator */ if "`nonadapt'"=="" { mata: weights = J($n_re,1,st_matrix("weights")) mata: nodes = J($n_re,1,st_matrix("nodes")) mata: mu_i = st_data(.,tokens(st_local("blupnames")),st_local("touse")) mata: tau_i = st_data(.,tokens(st_local("seblupnames")),st_local("touse")) mata: basisreps = cols(nodes):^$n_re /* No. of permutations for node sequences */ mata: nodesfinal = weightsfinal = basis = basis2 = J($n_re,basisreps,.) /* Basis matrix to store completed sequences of nodes; rows = no. of RE's */ /* Create nodesfinal and weightsfinal */ mata: nodes_weights($n_re,$Npat,nodes,weights,nodesfinal,weightsfinal,basis2) global first_call -1 mata: firstit = -1 mata: adaptit = `adaptit' mata: aghnodes = asarray_create("real",1) mata: aghweights = asarray_create("real",1) mata: adapt("`smodel'", aghnodes,aghweights,mu_i,tau_i,nodesfinal,weightsfinal,$n_re) } else { mata: nodes = sqrt(2):*J($n_re,1,st_matrix("nodes")) mata: weights = J($n_re,1,st_matrix("weights")):/sqrt(pi()) mata: basisreps = cols(nodes):^$n_re /* No. of permutations for node sequences */ mata: nodesfinal = weightsfinal = basis = basis2 = J($n_re,basisreps,.) /* Basis matrix to store completed sequences of nodes; rows = no. of RE's */ /* Create nodesfinal and weightsfinal */ mata: nodes_weights($n_re,$Npat,nodes,weights,nodesfinal,weightsfinal,basis2) } mata: survlike = longlike = J($Npat,basisreps,0) mata: jlnodes = J($Npat,basisreps,.) mata: id = st_data(.,st_local("_tempid"),st_local("touse")) mata: info = panelsetup(id, 1) mata: nmeas = info[.,2]:-info[.,1] :+ 1 mata: nres = $n_re mata: N = $Npat mata: Nmeas = $nmeasures if "`rhs'"!=""{ mata: covariates = st_data(.,tokens(st_local("rhs")),st_local("newsurvtouse")) } else { mata: covariates = 0 } if "`timeinteraction'"!="" { mata: timecovariates = st_data(.,tokens(st_local("timeinteraction")),st_local("newsurvtouse")) } else { mata: timecovariates = 0 } mata: newweights = J($Npat, `gh', 0) //?? /* Gauss-Kronrod nodes */ if "`smodel'"!="fpm" { gausskronrod`gk' mata: kweights = ((stime:-del_entry_time):/2):*J(`nsurvrows',1,st_matrix("kweights")) mata: knewnodes = J(`nsurvrows',1,st_matrix("knodes")):*((stime:-del_entry_time):/2) :+ ((stime:+del_entry_time):/2) mata: gknodes = asarray_create("real",2) mata: gknodes_deriv = asarray_create("real",2) if "`quick'"=="" { mata: gknodes(nodesfinal,weightsfinal,$n_re,knewnodes,gknodes,gknodes_deriv, covariates, timecovariates) } else { mata: gknodes_quick(nodesfinal,weightsfinal,$n_re,knewnodes,gknodes,gknodes_deriv, covariates, timecovariates) } mata: ngk = `gk' //reset knewnodes and stime to remove shift mata: stime = stime:-shift mata: del_entry_time = del_entry_time:-shift mata: knewnodes = J(`nsurvrows',1,st_matrix("knodes")):*((stime:-del_entry_time):/2) :+ ((stime:+del_entry_time):/2) } global rescale 0 if "`nonadapt'"!="" { local nonadapt "_na" local ghtext "Gauss-Hermite quadrature" } else { local ghtext "Adaptive Gauss-Hermite quadrature" } /******************************************************************************************************************************************************************************************/ /* MAXIMIZATION */ di as txt "Fitting full model:" if "`nonadapt'"=="" { di di in yellow "-> Conducting adaptive Gauss-Hermite quadrature" } //n di "`longequation' `alphaequation' `survequation'" //n mat list `initmat' ml model d0 stjm11_d0_`smodel'`nonadapt' /// `longequation' /// `alphaequation' /// `survequation' /// if `touse' /// , init(`initmat', copy) /// `options' /// waldtest(0) /// `searchopt' /// `collinopt' /// `constopts' /// `nolog' /// maximize /*** NEED TO CREATE MATA CLEARUP PROGRAM ***/ ereturn local predict stjm11_pred ereturn local title "Joint model estimates" ereturn local cmd stjm11 ereturn local survmodel "`smodel'" ereturn local longdepvar "`lhs'" ereturn local survdepvar "_t _d" ereturn local rcsterms_base `rcsnames' ereturn local drcsterms_base `drcsnames' ereturn local long_varlist `rhs' ereturn local surv_varlist `survcov' ereturn local panel `panel' ereturn local Npat $Npat ereturn local intmethod "`ghtext'" ereturn scalar dev = -2*e(ll) ereturn scalar AIC = -2*e(ll) + 2 * e(rank) ereturn scalar BIC = -2*e(ll) + ln(r(N)) * e(rank) /* Stuff for predictions */ ereturn local fixed_time `ffracpoly' ereturn local random_time `rfracpoly' ereturn local current $current ereturn local deriv $deriv ereturn local intassoc $intassoc ereturn local timeassoc $timeassoc ereturn local sepassoc_timevar_index `sepassocpred' ereturn local sepassoc_timevar_pows `association' ereturn local npows $npows ereturn local rand_timevars `re_timevars' ereturn local n_re $n_re ereturn local df `df' ereturn local shift `shift' ereturn local fps_list `fps' ereturn local nassoc $n_alpha ereturn local ln_bhknots `ln_bhknots' ereturn local orthog `orthog' ereturn local gh `gh' ereturn local gk `gk' ereturn local timecovvars `covinterlist1' ereturn local timeinteraction `timeinteraction' ereturn local assoccovariates `assoccovariates' ereturn local nvcvparams = `nvcvparams' ereturn matrix vcv = vcv ereturn matrix fp_pows = fp_pows ereturn matrix rand_ind = rand_ind if "`smodel'"=="fpm" { ereturn matrix rmatrix = `R_bh' } if "`association'"!="" { ereturn matrix timeassoc_re_ind = timeassoc_re_ind ereturn matrix timeassoc_fixed_ind = timeassoc_fixed_ind } if "`keepcons'" == "" { constraint drop `dropconslist' } else { ereturn local sp_constraints `dropconslist' } Replay, level(`level') smodel(`smodel') `showcons' `variance' end program Replay syntax [, Level(cilevel) Smodel(string) SHOWCons VARiance] Display, level(`level') smodel(`smodel') `showcons' `variance' end ***************ADD ABBREV TO VAR NAME DISPLAYS /******************************************************************************************************************************************************************************************/ /* DISPLAY TABLE */ program Display syntax [, Level(cilevel) Smodel(string) Panel(string) SHOWCons VARiance] tempname ests vars ses lci uci pvals zvals results mat `ests' = e(b)' mat `vars' = e(V) local nparams = colsof(`vars') mat `ses' = J(`nparams',1,0) forvalues i=1/`nparams' { mat `ses'[`i',1] = sqrt(`vars'[`i',`i']) } tempname siglev scalar `siglev' = abs(invnormal((100-`level')/200)) mat `lci' = `ests' - `siglev' * `ses' mat `uci' = `ests' + `siglev' * `ses' mat `zvals' = J(`nparams',1,0) mat `pvals' = J(`nparams',1,0) forvalues i=1/`nparams' { mat `zvals'[`i',1] = `ests'[`i',1]/`ses'[`i',1] mat `pvals'[`i',1] = (1-normal(abs(`zvals'[`i',1])))*2 } mat `results' = `ests',`ses',`zvals',`pvals',`lci',`uci' local k = length("`level'") if "`variance'"=="" { local sdtxt "sd" local corrtxt "corr" } else { local sdtxt "var" local corrtxt "cov" } di di as txt "Joint model estimates" /// as txt _col(50) "Number of obs. = " /// as res _col(`=79-length("$nmeasures")') $nmeasures di as txt "Panel variable: " as res abbrev("$panel",12) /// as txt _col(50) "Number of panels = " /// as res _col(`=79-length("$Npat")') $Npat di di as txt "Log-likelihood = " as res e(ll) di /*Show constraints if asked */ if "`showcons'"=="" { local nocnsreport nocnsreport } local labind = 1 if $n_ftime>0 { forvalues i=1/$n_ftime { local `++labind' } } if $n_rtime>0 { forvalues i=1/$n_rtime { local `++labind' } } /* time covariate interactions */ if "`e(timecovvars)'"!="" { foreach var of varlist `e(timecovvars)' { local `++labind' } } if "`e(long_varlist)'"!="" { foreach var of varlist `e(long_varlist)' { //fixed covariates in longitudinal model (rhs) local `++labind' } } ml di, neq(1) noheader showeqn nofootnote plus `nocnsreport' local `++labind' local labind = `labind' + `e(nvcvparams)' + 1 /* Association parameters */ di as res "Survival" as txt _col(14) "{c |}" forvalues i = 1/`e(nassoc)' { local lab : word `i' of $alpha_di_txt local p = 13 - length("`lab'") di as res _col(`p') "`lab'" as txt _col(14) "{c |}" if "`e(assoccovariates)'"!="" { foreach cov in `e(assoccovariates)' { forvalues j = 1/6 { local coef`j' = `results'[`labind',`j'] } local cov = abbrev("`cov'",12) Di_param, label(`cov') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6') local `++labind' } } _diparm alpha_`i', label("_cons") local `++labind' } /* Survival parameters */ if "`e(survmodel)'"=="fpm" { di as res _col(11) "xb" as txt _col(14) "{c |}" local scovs_names "`e(surv_varlist)' `e(rcsterms_base)'" foreach var of local scovs_names { //fixed covariates in survival model (survcov) forvalues i = 1/6 { local coef`i' = `results'[`labind',`i'] } local var = abbrev("`var'",12) Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6') local `++labind' } _diparm xb, label("_cons") local `++labind' } else if "`e(survmodel)'"=="e" { di as res _col(4) "ln_lambda" as txt _col(14) "{c |}" local scovs_names "`e(surv_varlist)'" foreach var of local scovs_names { //fixed covariates in survival model (survcov) forvalues i = 1/6 { local coef`i' = `results'[`labind',`i'] } local var = abbrev("`var'",12) Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6') local `++labind' } _diparm ln_lambda, label("_cons") /*ln_lambda baseline */ local `++labind' } else if "`e(survmodel)'"=="w" { di as res _col(4) "ln_lambda" as txt _col(14) "{c |}" local scovs_names "`e(surv_varlist)'" foreach var of local scovs_names { //fixed covariates in survival model (survcov) forvalues i = 1/6 { local coef`i' = `results'[`labind',`i'] } local var = abbrev("`var'",12) Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6') local `++labind' } _diparm ln_lambda, label("_cons") /*ln_lambda baseline */ local `++labind' local p = 13 - length("ln_gamma") di as res _col(`p') "ln_gamma" as txt _col(14) "{c |}" _diparm ln_gamma, label("_cons") local `++labind' } else if "`e(survmodel)'"=="g" { di as res _col(4) "ln_lambda" as txt _col(14) "{c |}" local scovs_names "`e(surv_varlist)'" foreach var of local scovs_names { //fixed covariates in survival model (survcov) forvalues i = 1/6 { local coef`i' = `results'[`labind',`i'] } local var = abbrev("`var'",12) Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6') local `++labind' } _diparm ln_lambda, label("_cons") /*ln_lambda baseline */ local `++labind' local p = 13 - length("gamma") di as res _col(`p') "gamma" as txt _col(14) "{c |}" _diparm gamma, label("_cons") local `++labind' } di as txt "{hline 13}{c BT}{hline 64} /* Random effects table title*/ di di as txt "{hline 29}{c TT}{hline 48} di as txt _col(3) "Random effects Parameters" _col(30) "{c |}" _col(34) "Estimate" _col(45) "Std. Err." _col(`=61-`k'') /// `"[`=strsubdp("`level'")'% Conf. Interval]"' di as txt "{hline 29}{c +}{hline 48} if "$n_re"!="1"{ local labtextvcv $labtextvcv } else local labtextvcv "Independent" di as res abbrev("$panel",12) as txt ": `labtextvcv'" _col(30) "{c |}" /* Std. dev./Variances of random effects */ if "`labtextvcv'"=="Independent" | "`labtextvcv'"=="Unstructured" { local test = 1 forvalues i=1/$n_re { local lab : word `test' of $retimelabelnames2 Var_display, param("lns_`i'") label("`sdtxt'(`lab')") `variance' local `++test' } } else { local name = abbrev(trim("$retimelabelnames2"),19) local n2 = length("$retimelabelnames2") if `n2'>19 { local n1 "(1)" } Var_display, param("lns_1") label("`sdtxt'(`name')`n1'") `variance' } /* Corrs/Covariances of random effects */ if "`labtextvcv'"=="Unstructured" & $n_re>1 { local firstindex = 1 local txtindex = 1 while (`firstindex'<$n_re) { local test = `firstindex' + 1 local test2 = 1 forvalues i=`test'/$n_re { local ind2 = `i'-1 local lab1 : word `txtindex' of $retimelabelnames2 local lab2 : word `=`txtindex'+`test2'' of $retimelabelnames2 if "`variance'"=="" { Covar_display, param1("art_`firstindex'_`test'") label("`corrtxt'(`lab1',`lab2')") `variance' } else { Covar_display, param1("art_`firstindex'_`test'") param2("lns_`firstindex'") param3("lns_`test'") label("`corrtxt'(`lab1',`lab2')") `variance' } local `++test' local `++test2' } local `++firstindex' local `++txtindex' } } else if "`labtextvcv'"=="Exchangeable" & $n_re>1 { local name = abbrev(trim("$retimelabelnames2"),19) local n2 = length("$retimelabelnames2") if `n2'>19 { local n1 "(1)" } if "`variance'"=="" { Covar_display, param1("art_1_1") label("`corrtxt'(`name')`n1'") `variance' } else { Covar_display, param1("art_1_1") param2("lns_1") param3("lns_1") label("`corrtxt'(`name')`n1'") `variance' } } /* Residual variance */ di as txt "{hline 29}{c +}{hline 48} Var_display, param(lns_e) label("`sdtxt'(Residual)") `variance' di as txt "{hline 29}{c BT}{hline 48} local l = length(trim("$retimelabelnames2")) if `l'>19 { di in green "(1) $retimelabelnames2" } /* Summary text */ if "`e(survmodel)'"=="w" { local smodeltxt "Weibull proportional hazards model" } else if "`e(survmodel)'"=="e" { local smodeltxt "Exponential proportional hazards model" } else if "`e(survmodel)'"=="g" { local smodeltxt "Gompertz proportional hazards model" } else { local smodeltxt "Flexible parametric model" } di "" di in green " Longitudinal submodel: Linear mixed effects model" di in green " Survival submodel: `smodeltxt'" di in green " Integration method: `e(intmethod)' using `e(gh)' nodes" if "`e(survmodel)'"!="fpm" { di in green " Cumulative hazard: Gauss-Kronrod quadrature using `e(gk)' nodes" } end program Var_display syntax, PARAM(string) LABEL(string) [VARiance] if "`variance'"=="" { _diparm `param', exp notab } else { _diparm `param', f(exp(2*@)) d(2*exp(2*@)) notab } Di_re_param, label("`label'") end program Covar_display syntax, param1(string) [PARAM2(string) PARAM3(string) LABEL(string) VARiance] if "`variance'"=="" { _diparm `param1', tanh notab } else { _diparm `param1' `param2' `param3', f(tanh(@1)*exp(@2)*exp(@3)) d((1-(tanh(@1)^2))*exp(@2+@3) tanh(@1)*exp(@2+@3) tanh(@1)*exp(@2+@3)) notab } Di_re_param, label("`label'") end program Di_re_param syntax, LABEL(string) local p = 29 - length("`label'") di as txt _col(`p') "`label'" _col(30) "{c |}" /// as res _col(33) %9.0g r(est) /// as res _col(44) %9.0g r(se) /// as res _col(58) %9.0g cond(missing(r(se)),.,r(lb)) /// as res _col(70) %9.0g cond(missing(r(se)),.,r(ub)) end program Di_param syntax, LABEL(string) COEF1(string) COEF2(string) COEF3(string) COEF4(string) COEF5(string) COEF6(string) local p = 13 - length("`label'") di as txt _col(`p') "`label'" _col(14) "{c |}" /// as res _col(17) %9.0g `coef1' /// as res _col(28) %9.0g `coef2' /// as res _col(38) %8.2f `coef3' /// as res _col(49) %4.3f `coef4' /// as res _col(58) %9.0g `coef5' /// as res _col(70) %9.0g `coef6' end program gausskronrod15 mat knodes = J(1,15,.) mat kweights = J(1,15,.) local i=1 foreach n of numlist 0.991455371120813 -0.991455371120813 0.949107912342759 -0.949107912342759 0.864864423359769 -0.864864423359769 0.741531185599394 -0.741531185599394 0.586087235467691 -0.586087235467691 0.405845151377397 -0.405845151377397 0.207784955007898 -0.207784955007898 0 { mat knodes[1,`i'] = `n' local `++i' } local i=1 foreach n of numlist 0.022935322010529 0.022935322010529 0.063092092629979 0.063092092629979 0.104790010322250 0.104790010322250 0.140653259715525 0.140653259715525 0.169004726639267 0.169004726639267 0.190350578064785 0.190350578064785 0.204432940075298 0.204432940075298 0.209482141084728 { mat kweights[1,`i'] = `n' local `++i' } end program gausskronrod7 mat knodes = J(1,7,.) mat kweights = J(1,7,.) local i=1 foreach n of numlist 0.949107912342759 -0.949107912342759 0.741531185599394 -0.741531185599394 0.405845151377397 -0.405845151377397 0 { mat knodes[1,`i'] = `n' local `++i' } local i=1 foreach n of numlist 0.129484966168870 0.129484966168870 0.279705391489277 0.279705391489277 0.381830050505119 0.381830050505119 0.417959183673469 { mat kweights[1,`i'] = `n' local `++i' } end /* Mata program to calculate nodes and weights matrices */ mata: mata set matastrict off void nodes_weights( /// real scalar nres, /// numeric scalar N, /// numeric matrix nodes, /// numeric matrix weights, /// numeric matrix nodesfinal, /// numeric matrix weightsfinal, /// numeric matrix basis2) { nres1 = nres:-1 repind = 1 /* Index for multiplying node sequences */ /* Node and weight sequences for random effects */ if (nres>1) { for (i=1; i<=nres1; i++) { reps = (cols(nodes):^(nres:-i)) /* no. of times to repeat each node */ noderepeat = J(reps,1,nodes[i,(1::cols(nodes))])' /* replicate each ith row of nodes, "reps" times, so now have "reps" rows -> then transpose */ weightrepeat = J(reps,1,weights[i,(1::cols(nodes))])' rep1 = noderepeat[1,.] rep2 = weightrepeat[1,.] for (j=2; j<=cols(nodes); j++) { rep1=rep1,noderepeat[j,.] rep2=rep2,weightrepeat[j,.] } nodesfinal[i,.] = J(1,repind,rep1) basis2[i,.] = J(1,repind,rep2) repind = repind:*cols(nodes) } } nodesfinal[nres,.] = J(1,repind,nodes[nres,.]) /* final nodes sequences */ basis2[nres,.] = J(1,repind,weights[nres,.]) /* final weights sequences */ if (nres>1){ weightsfinal = J(1,1,basis2[1,.]) for (i=2; i<=nres; i++) { weightsfinal = weightsfinal:*J(1,1,basis2[i,.]) } } else { weightsfinal = J(1,1,basis2[1,.]) } } end mata: mata set matastrict off void adapt(string scalar smodel, transmorphic aghnodes, transmorphic aghweights,numeric matrix mu_i,numeric matrix tau_i,numeric matrix nodesfinal, /// numeric matrix weightsfinal,real scalar nres) { decomp_i = J(nres,nres,0) //cholesky(st_matrix("vcv")) id = st_data(.,st_local("_tempid"),st_local("touse")) info = panelsetup(id, 1) nmeas = info[.,2]:-info[.,1] :+ 1 fp_pows = st_matrix("fp_pows") nres1 = nres:+1 npows = cols(fp_pows) npows1 = npows :+1 for (i=1; i<=rows(info); i++) { /* adapt GH nodes and weights */ shift = panelsubmatrix(mu_i,i,info)[1,.]' scale = panelsubmatrix(tau_i,i,info)[1,.] for(j=1;j<=nres;j++){ decomp_i[j,j] = scale[1,j] } nodes_i = shift :+ decomp_i * (sqrt(2):*nodesfinal) newweights = (2):^(nres:/2):*sqrt(det(decomp_i*(decomp_i'))):*exp(quadcolsum(nodesfinal:^2)) :* weightsfinal asarray(aghnodes,i,nodes_i) asarray(aghweights,i,newweights) } } end mata: mata set matastrict off void gknodes(numeric matrix nodesfinal, /// numeric matrix weightsfinal,real scalar nres,| /// numeric matrix knewnodes, transmorphic gknodes, /// transmorphic gknodes_deriv, numeric matrix covariates, numeric matrix timecovariates) { id = st_data(.,st_local("_tempid"),st_local("touse")) info = panelsetup(id, 1) nmeas = info[.,2]:-info[.,1] :+ 1 fp_pows = st_matrix("fp_pows") nres1 = nres:+1 npows = cols(fp_pows) npows1 = npows :+1 for (i=1; i<=rows(info); i++) { knewnodes_i = panelsubmatrix(knewnodes,i,info) if (st_global("timeinterac")=="yes") { timecovs_i = panelsubmatrix(timecovariates,i,info) } if (rows(covariates)>1) { cov_i = panelsubmatrix(covariates,i,info) } for (j=1; j<=nmeas[i,1];j++) { if (st_global("current")=="yes" | st_global("intassoc")=="yes" | st_global("timeassoc")=="yes") { dm_knewnodes = J(npows,cols(knewnodes),.) for(k=1;k<=npows;k++){ if (fp_pows[1,k]!=0) { dm_knewnodes[k,.] = knewnodes_i[j,]:^fp_pows[1,k] } else { dm_knewnodes[k,.] = log(knewnodes_i[j,]) } } /* time covariate interactions */ if (st_global("timeinterac")=="yes") { temp = dm_knewnodes ntimecovinterac = st_numscalar("ntimecovinterac") for(f=1;f<=ntimecovinterac;f++){ interac = timecovs_i[j,f]:*temp dm_knewnodes = dm_knewnodes\interac } } /* covariates */ if (rows(covariates)>1) { for(d=1;d<=cols(covariates);d++){ dm_knewnodes = dm_knewnodes\J(1,cols(knewnodes),cov_i[j,d]) } } dm_knewnodes = dm_knewnodes\J(1,cols(knewnodes),1) asarray(gknodes,(i,j),dm_knewnodes') } if (st_global("deriv")=="yes") { dm_knewnodes_deriv = J(npows,cols(knewnodes),0) for(k=1;k<=npows;k++){ if (fp_pows[1,k]!=0) { dm_knewnodes_deriv[k,.] = fp_pows[1,k] :* knewnodes_i[j,.]:^(fp_pows[1,k] :-1) } else { dm_knewnodes_deriv[k,.] = 1:/knewnodes_i[j,.] } } /* time covariate interactions */ if (st_global("timeinterac")=="yes") { temp = dm_knewnodes_deriv ntimecovinterac = st_numscalar("ntimecovinterac") for(c=1;c<=ntimecovinterac;c++){ test = temp :* timecovs_i[j,c] dm_knewnodes_deriv = dm_knewnodes_deriv\test } } if (rows(covariates)>1) { for(d=1;d<=cols(covariates);d++){ dm_knewnodes_deriv = dm_knewnodes_deriv\J(1,cols(knewnodes),0) } } dm_knewnodes_deriv = dm_knewnodes_deriv\J(1,cols(knewnodes),0) asarray(gknodes_deriv,(i,j),dm_knewnodes_deriv') } } } } end mata: mata set matastrict off void gknodes_quick(numeric matrix nodesfinal, /// numeric matrix weightsfinal,real scalar nres,| /// numeric matrix knewnodes, transmorphic gknodes, /// transmorphic gknodes_deriv, numeric matrix covariates, numeric matrix timecovariates,string scalar quick) { id = st_data(.,st_local("_tempid"),st_local("newsurvtouse")) npat = rows(id) fp_pows = st_matrix("fp_pows") nres1 = nres:+1 npows = cols(fp_pows) npows1 = npows :+1 for (i=1; i<=npat; i++) { if (st_global("current")=="yes" | st_global("intassoc")=="yes" | st_global("timeassoc")=="yes") { dm_knewnodes = J(npows,cols(knewnodes),.) for(k=1;k<=npows;k++){ if (fp_pows[1,k]!=0) { dm_knewnodes[k,.] = knewnodes[i,.]:^fp_pows[1,k] } else { dm_knewnodes[k,.] = log(knewnodes[i,]) } } /* time covariate interactions */ if (st_global("timeinterac")=="yes") { temp = dm_knewnodes ntimecovinterac = st_numscalar("ntimecovinterac") for(f=1;f<=ntimecovinterac;f++){ interac = timecovariates[i,f]:*temp dm_knewnodes = dm_knewnodes\interac } } /* covariates */ if (rows(covariates)>1) { for(d=1;d<=cols(covariates);d++){ dm_knewnodes = dm_knewnodes\J(1,cols(knewnodes),covariates[i,d]) } } dm_knewnodes = dm_knewnodes\J(1,cols(knewnodes),1) asarray(gknodes,(i,1),dm_knewnodes') } if (st_global("deriv")=="yes") { dm_knewnodes_deriv = J(npows,cols(knewnodes),0) for(k=1;k<=npows;k++){ if (fp_pows[1,k]!=0) { dm_knewnodes_deriv[k,.] = fp_pows[1,k] :* knewnodes[i,.]:^(fp_pows[1,k] :-1) } else { dm_knewnodes_deriv[k,.] = 1:/knewnodes[i,.] } } /* time covariate interactions */ if (st_global("timeinterac")=="yes") { temp = dm_knewnodes_deriv ntimecovinterac = st_numscalar("ntimecovinterac") for(c=1;c<=ntimecovinterac;c++){ test = temp :* timecovariates[i,c] dm_knewnodes_deriv = dm_knewnodes_deriv\test } } if (rows(covariates)>1) { for(d=1;d<=cols(covariates);d++){ dm_knewnodes_deriv = dm_knewnodes_deriv\J(1,cols(knewnodes),0) } } dm_knewnodes_deriv = dm_knewnodes_deriv\J(1,cols(knewnodes),0) asarray(gknodes_deriv,(i,1),dm_knewnodes_deriv') } } } end /* Thanks to G. R. Frechette for permission to include ghquadm (taken from rfprobit update)*/ program define ghquadm * stolen from gllamm6 who stole it from rfprobit (Bill Sribney) version 4.0 parse "`*'", parse(" ") local n = `1' if `n' + 2 > _N { di in red /* */ "`n' + 2 observations needed to compute quadrature points" exit 2001 } tempname x w xx ww a b local i 1 local m = int((`n' + 1)/2) matrix x = J(1,`m',0) matrix w = x while `i' <= `m' { if `i' == 1 { scalar `xx' = sqrt(2*`n'+1)-1.85575*(2*`n'+1)^(-1/6) } else if `i' == 2 { scalar `xx' = `xx'-1.14*`n'^0.426/`xx' } else if `i' == 3 { scalar `xx' = 1.86*`xx'-0.86*x[1,1] } else if `i' == 4 { scalar `xx' = 1.91*`xx'-0.91*x[1,2] } else { local im2 = `i' -2 scalar `xx' = 2*`xx'-x[1,`im2'] } hermite `n' `xx' `ww' matrix x[1,`i'] = `xx' matrix w[1,`i'] = `ww' local i = `i' + 1 } if mod(`n', 2) == 1 { matrix x[1,`m'] = 0} /* start in tails */ matrix `b' = (1,1) matrix w = w#`b' matrix w = w[1,1..`n'] matrix `b' = (1,-1) matrix x = x#`b' matrix x = x[1,1..`n'] /* other alternative (left to right) */ /* above: matrix x = J(1,`n',0) while ( `i'<=`n'){ matrix x[1, `i'] = -x[1, `n'+1-`i'] matrix w[1, `i'] = w[1, `n'+1-`i'] local i = `i' + 1 } */ matrix `2' = x matrix `3' = w end program define hermite /* integer n, scalar x, scalar w */ * stolen from gllamm6 who stole it from rfprobit (Bill Sribney) version 4.0 local n "`1'" local x "`2'" local w "`3'" local last = `n' + 2 tempname i p matrix `p' = J(1,`last',0) scalar `i' = 1 while `i' <= 10 { matrix `p'[1,1]=0 matrix `p'[1,2] = _pi^(-0.25) local k = 3 while `k'<=`last'{ matrix `p'[1,`k'] = `x'*sqrt(2/(`k'-2))*`p'[1,`k'-1] /* */ - sqrt((`k'-3)/(`k'-2))*`p'[1,`k'-2] local k = `k' + 1 } scalar `w' = sqrt(2*`n')*`p'[1,`last'-1] scalar `x' = `x' - `p'[1,`last']/`w' if abs(`p'[1,`last']/`w') < 3e-14 { scalar `w' = 2/(`w'*`w') exit } scalar `i' = `i' + 1 } di in red "hermite did not converge" exit 499 end