You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

438 lines
13 KiB
Plaintext

7 months ago
*! version 1.1.1 PR 28nov2005
/*
History
1.1.1 28nov2005 eform and eform() option styles now allowed.
nowarning option to suppress warning message about supported regression cmds.
1.1.0 30sep2005 Generalization of supported commands (cmdchk.ado also modified).
Version <=7 no longer supported.
1.0.9 18apr2005 Default rowid variable becomes _i.
If not found, take from char _dta[MI_obsid] then char _dta[mi_id].
Default impid variable is _j. If not found, take from _dta[MI_impid].
These changes are for future compatibility with MItools.
1.0.8 04mar2005 Fixed problem with eform on redisplay
1.0.7 28jan2005 Fixed problem with null model estimation
Fixed bug with noconstant option
1.0.6 25jan2005 e(sample) now correct for all imputations, via ereturn post.
Add d.f. quantities from Barnard & Rubin (1999) Biometrika 86:948-955 eq (3)-(5).
Minor additions to ereturn quantities for compatibility with misw.
Allow null model and model only with constant for benefit of misw.
1.0.5 16nov2004 Update calculations of quantities stored for Li et al (1991) F test.
1.0.4 13oct2004 Change e(cmd) to `cmd', make e(cmd2)="micombine" (for use after mfx).
Implementation of mean log likelihood and chisquare statistic saved
(note undocumented -noclear- but v. useful option to ereturn post/estimates post).
*/
program define micombine, eclass
if _caller()<=7 {
di as error "version 7 and earlier not supported"
exit 9
}
if replay() {
if `"`e(cmd2)'"'!="micombine" {
error 301
}
syntax[, EForm EForm2(string)]
if "`eform2'"!="" {
if "`eform'"!="" di as err "[eform ignored]"
local eform eform(`eform2')
}
else if "`eform'"!="" local eform eform("exp(b)")
di as text _n "Multiple imputation parameter estimates (" as res e(m) as text " imputations)"
capture ereturn display, `eform'
local rc=_rc
if `rc'>0 {
* Null model, or model with cc() only
if `"`e(cmd)'"'!="stcox" {
`e(cmd)' `0'
}
else di as text "[Null model - no estimates]"
}
else ereturn display, `eform'
di as result e(N) as text " observations."
exit
}
gettoken cmd 0 : 0
if "`cmd'"=="stpm" {
local dist 7
local bad 0
}
else {
cmdchk `cmd'
local cmdnotknown `s(bad)'
/*
dist=0 (normal), 1 (binomial), 2 (poisson), 3 (cox), 4 (glm),
5 (xtgee), 6(ereg/weibull).
*/
local dist `s(dist)'
}
syntax [anything] [if] [in] [aw fw pw iw] , [ IMPid(string) BR CC(varlist) noCONStant ///
DEAD(varname) DETail EForm EForm2(string) GENxb(string) LRR noWARning OBSid(string) * ]
if `cmdnotknown' & "`warning'"!="nowarning" {
di as err _n "Warning: " as inp "`cmd'" as err " is not a certified regression command for micombine."
di as err "micombine will continue mechanically, but correct results are not guaranteed."
di as err "You must take responsibility that Rubin's rules are appropriate here." _n
}
if "`eform2'"!="" {
if "`eform'"!="" di as err "[eform ignored]"
local eform eform(`eform2')
}
else if "`eform'"!="" local eform eform("exp(b)")
* Check for possible impid characteristic. If it does not exist use default _j
if "`impid'"=="" {
local impid: char _dta[MI_impid]
if "`impid'"=="" local impid _j
}
cap confirm var `impid'
if _rc {
di as err "imputation identifier `impid' not found"
exit 601
}
* Check for possible obsid chars. If none exist use default _i
if "`obsid'"=="" {
local I: char _dta[MI_obsid]
if "`I'"=="" local I: char _dta[mi_id]
if "`I'"=="" local I _i
}
else local I `obsid'
cap confirm var `I'
if _rc {
di as err "observation identifier `I' not found"
exit 601
}
if "`detail'"!="" {
local detail noisily
}
else local detail
*Change here 11/15/05, commenting out the line below !! PR DELETED XIAO CHEN'S EDIT, NOV 05
frac_cox "`dead'" `dist'
if "`constant'"=="noconstant" {
if "`cmd'"=="fit" | "`cmd'"=="stcox" | "`cmd'"=="cox" {
di as error "noconstant invalid with `cmd'"
exit 198
}
}
*Change here 11/15/05, `dist' could be null.... !! PR DELETED XIAO CHEN'S EDIT, NOV 05
*if "`dist'" =="7" { /* stcox, streg, stpm */
if `dist'==7 {
local y
local yname _t
local xvars `anything'
}
else {
gettoken y xvars : anything
gettoken xvars left: xvars, parse("(")
local yname `y'
}
tempvar touse
quietly {
marksample touse
markout `touse' `varlist' `dead' `cc'
if "`dead'"!="" {
local dead "dead(`dead')"
}
* Deal with weights.
frac_wgt `"`exp'"' `touse' `"`weight'"'
local wgt `r(wgt)'
tempvar J
* Important (compatibility with mitools): ignore rows for which impid=0
egen int `J'=group(`impid') if `touse'==1 & `impid'>0 & !missing(`impid')
sum `J', meanonly
local m=r(max)
if `m'<2 {
di as error "there must be at least 2 imputations"
exit 198
}
local nxvar: word count `xvars'
/*
if `nxvar'<1 {
di as err "there must be at least one covariate"
exit 198
}
*/
local ncc: word count `cc' /* could legitimately be zero */
local nvar=`nxvar'+`ncc' /* number of covariates in model */
count if `touse'==1 & `J'==1
local nobs=r(N)
* Null Cox model (or model with only ccvars): fit on final imputation only, and quit
if "`xvars'"=="" & ("`cmd'"=="cox" | "`cmd'"=="stcox") {
if "`cmd'"=="stcox" & "`cc'"=="" {
local options `options' estimate
}
`detail' `cmd' `y' `cc' if `touse'==1 & `J'==`m' `wgt', `options' `dead' `constant'
noi `cmd'
di as result `nobs' as text " observations."
ereturn scalar m=`m'
ereturn local impid `impid'
ereturn local cmd `cmd'
ereturn local cmd2 micombine
exit
}
* Compute model over m imputations
tempname W Q B T QQ
if "`genxb'"!="" {
tempvar xb xbtmp
gen `xb'=.
}
* Estimate mean LR chisquare statistic (where possible)
tempname chi2 ell ell0 nucom
scalar `chi2'=0
scalar `ell'=0
scalar `ell0'=0
forvalues i=1/`m' {
tempname Q`i'
`detail' `cmd' `y' `xvars' `cc' `left' if `touse'==1 & `J'==`i' `wgt', ///
`options' `dead' `constant'
scalar `nucom'=e(df_r) // complete-data residual degrees of freedom
if `nucom'==. {
scalar `nucom'=100000
}
scalar `ell'=`ell'+e(ll)
scalar `ell0'=`ell0'+e(ll_0)
scalar `chi2'=`chi2'-2*(e(ll_0)-e(ll))
if "`genxb'"!="" {
predict `xbtmp' if `touse'==1 & `J'==`i', xb
replace `xb'=`xbtmp' if `touse'==1 & `J'==`i'
drop `xbtmp'
}
matrix `Q`i''=e(b)
if `i'==1 {
matrix `Q'=e(b)
matrix `W'=e(V)
}
else {
matrix `Q'=`Q'+e(b)
matrix `W'=`W'+e(V)
}
}
if "`genxb'"!="" {
sort `touse' `I' `J'
by `touse' `I': gen `genxb'=sum(`xb')/`m' if `touse'==1
by `touse' `I': replace `genxb'=`genxb'[_N] if _n<_N
lab var `genxb' "Mean Linear Predictor (`m' imputations)"
}
matrix `Q'=`Q'/`m' /* MI param estimates */
matrix `W'=`W'/`m'
scalar `chi2'=`chi2'/`m'
scalar `ell'=`ell'/`m'
scalar `ell0'=`ell0'/`m'
local k=colsof(`Q')
matrix `B'=J(`k',`k',0)
forvalues i=1/`m' {
matrix `QQ'=`Q`i''-`Q'
if `i'==1 {
matrix `B'=`QQ''*`QQ'
}
else matrix `B'=`B'+`QQ''*`QQ'
}
matrix `B'=`B'/(`m'-1)
matrix `T'=`W'+(1+1/`m')*`B' /* estimated VCE matrix */
/*
Relative increase in variance due to missing information (r) for
each variable, and df and lambda, the fraction of missing information.
All measures are unstable for low m. See Schafer (1997) p. 110.
Note that BIF = sqrt(T/W) = sqrt(1 + (B/W)*(1+1/m)) = sqrt(1+r)
is the between-imputation imprecision factor, i.e. the ratio
of the SE derived from T to the SE derived from W,
ignoring between-imputation variation in parameter estimates.
*/
tempname r t lambda nu BIF
matrix `r'=J(1,`k',0)
matrix `lambda'=J(1,`k',0)
matrix `nu'=J(1,`k',0)
matrix `BIF'=J(1,`k',0)
scalar `t'=`m'-1
* Next few lines assign quantities for tests of individual (1 df) components of Q (=beta)
forvalues j=1/`k' {
matrix `r'[1,`j']=(1+1/`m')*`B'[`j',`j']/`W'[`j',`j']
matrix `nu'[1,`j']=cond(`t'>4, 4+(`t'-4)*(1+(1-2/`t')/`r'[1,`j'])^2, `t'*(1+1/`r'[1,`j'])^2)
matrix `lambda'[1,`j']=(`r'[1,`j']+2/(`nu'[1,`j']+3))/(`r'[1,`j']+1)
matrix `BIF'[1,`j']=sqrt(1+`r'[1,`j']) /* = sqrt(`T'[`j',`j']/`W'[`j',`j']) */
}
* Next few lines assign quantities for d.f. from Barnard & Rubin 1999 B'ka 86(4): 948-955.
tempname nutilde num nuobs gamma
matrix `nutilde'=J(1,`k',0)
matrix `num'=J(1,`k',0)
matrix `nuobs'=J(1,`k',0)
matrix `gamma'=J(1,`k',0)
forvalues j=1/`k' {
matrix `gamma'[1,`j']=(1+1/`m')*`B'[`j',`j']/`T'[`j',`j']
matrix `nuobs'[1,`j']=((`nucom'+1)/(`nucom'+3))*`nucom'*(1-`gamma'[1,`j'])
matrix `num'[1,`j']=(`m'-1)*`gamma'[1,`j']^-2
matrix `nutilde'[1,`j']=1/((1/`num'[1,`j']+1/`nuobs'[1,`j']))
}
* use all varnames
local names: colnames(`Q1')
matrix colnames `r'=`names'
matrix colnames `nu'=`names'
matrix colnames `lambda'=`names'
matrix colnames `BIF'=`names'
matrix colnames `gamma'=`names'
matrix colnames `nuobs'=`names'
matrix colnames `num'=`names'
matrix colnames `nutilde'=`names'
* Li, Raghunathan & Rubin (1991) estimates of T and nu1
* for F test of Q=0 on k,nu1 degrees of freedom
tempname r1 t1 BW TLRR
matrix `BW'=`B'*syminv(`W')
scalar `r1'=trace(`BW')*(1+1/`m')/`k'
matrix `TLRR'=`W'*(1+`r1')
scalar `t1'=`k'*(`m'-1)
matrix colnames `Q'=`names'
matrix rownames `T'=`names'
matrix colnames `T'=`names'
matrix rownames `B'=`names'
matrix colnames `B'=`names'
matrix rownames `TLRR'=`names'
matrix colnames `TLRR'=`names'
}
di as text _n "Multiple imputation parameter estimates (`m' imputations)"
if "`lrr'"!="" {
di as text "[Using Li-Raghunathan-Rubin (LRR) estimate of VCE matrix]"
ereturn post `Q' `TLRR', depname(`yname') obs(`nobs') esample(`touse') noclear
ereturn matrix T `T'
}
else {
ereturn post `Q' `T', depname(`yname') obs(`nobs') esample(`touse') noclear
ereturn matrix TLRR `TLRR'
}
if "`br'"=="" {
ereturn display, `eform'
di as result `nobs' as text " observations."
}
ereturn matrix B `B'
ereturn matrix W `W'
ereturn matrix r `r'
ereturn matrix nu `nu'
ereturn matrix lambda `lambda'
ereturn matrix BIF `BIF'
* Quantities for calculating df `nutilde' according to Barnard & Rubin (1999)
ereturn matrix gamma `gamma'
ereturn matrix nuobs `nuobs'
ereturn matrix num `num'
ereturn matrix nutilde `nutilde'
ereturn scalar r1=`r1'
ereturn scalar nu1=cond(`t1'>4, 4+(`t1'-4)*(1+(1-2/`t1')/`r1')^2, 0.5*`t1'*(1+1/`k')*(1+1/`r1')^2)
ereturn scalar m=`m'
ereturn scalar chi2=`chi2'
ereturn scalar ll=`ell'
ereturn scalar ll_0=`ell0'
ereturn local eform `eform'
ereturn local impid `impid'
ereturn local cmd `cmd'
ereturn local cmd2 micombine
if "`br'"!="" {
display_t
di as result `nobs' as text " observations."
}
end
program define display_t
* Display results with t-statistics estimated according to Barnard & Rubin (1999)
tempname V Q nu
matrix `V'=e(V)
matrix `Q'=e(b)
matrix `nu'=e(nutilde)
local yname `e(depvar)'
local xs: colnames `Q'
local k=colsof(`Q')
di as text _n "Intervals and inference based on d.f. from Barnard & Rubin (1999)"
di as txt "{hline 13}{c TT}{hline 64}"
local t0 = abbrev("`yname'",12)
if `"`e(eform)'"'!="" {
local tt "Odds Ratio"
}
else {
local tt " Coef."
}
#delimit ;
di as text
%12s "`t0'" _col(14)"{c |}`tt' Std. Err. t P>|t| [$S_level% Conf. Intvl] MI.df"
_n "{hline 13}{c +}{hline 64}" ;
#delimit cr
tempname df mn se t p invt l u
forvalues i=1/`k' {
local x: word `i' of `xs'
if "`x'"!="_cons" {
local fmt : format `x'
if substr("`fmt'",-1,1)=="f" {
local fmt="%8."+substr("`fmt'",-2,2)
}
else if substr("`fmt'",-2,2)=="fc" {
local fmt="%8."+substr("`fmt'",-3,3)
}
else local fmt "%8.0g"
local fmt`i' `fmt'
}
else local fmt "%8.0g"
scalar `df' =`nu'[1,`i']
scalar `mn' = `Q'[1,`i']
scalar `se' = sqrt(`V'[`i',`i'])
scalar `t' = `mn'/`se'
scalar `p' = 2* ttail(`df', abs(`t'))
scalar `invt' = invttail(`df', (1-$S_level/100)/2)
scalar `l' = `mn' - `invt'*`se'
scalar `u' = `mn' + `invt'*`se'
if `"`e(eform)'"'!="" {
scalar `mn' = exp(`mn')
scalar `se' = `mn'*`se'
scalar `l' = exp(`l')
scalar `u' = exp(`u')
}
if `df'>99999 {
local fmtdf %9.2e
}
else local fmtdf %9.2f
di as text /*
*/ %12s abbrev("`x'",12) _col(14) "{c |}" /*
*/ _col(17) as res `fmt' `mn' /*
*/ _col(27) `fmt' `se' /*
*/ _col(36) %7.2f `t' /*
*/ _col(42) %7.3f `p' /*
*/ _col(52) `fmt' `l' /*
*/ _col(61) `fmt' `u' /*
*/ _col(70) `fmtdf' `df'
}
di as text "{hline 13}{c BT}{hline 64}"
end
program define chkrowid, sclass
local I: char _dta[mi_id]
if "`I'"=="" {
di as error "no row-identifier variable found - data may have incorrect format"
exit 198
}
cap confirm var `I'
local rc=_rc
if `rc' {
di as error "row-identifier variable `I' not found"
exit `rc'
}
sret local I `I'
end