*! version 1.0.0 PR 30sep2004. program define _mvis7, rclass version 7 syntax varlist(min=2 numeric) [if] [in] [aw fw pw iw] using/, /* */ [ BOot(varlist) CC(varlist) CMd(string) CYcles(int 10) noCONStant DRaw(varlist) /* */ First(int 0) Genmiss(string) Id(string) ON(varlist) REcycle(varlist) TRace ] * Remove duplicate var names (_rmdups is essentially _mi_unique.ado) _rmdups "`varlist'" local varlist `r(unique)' local nvar: word count `varlist' if `first'<0 | `first'>`nvar' { di in red "invalid `first'" exit 198 } if "`id'"!="" { confirm new var `id' } else local id _i if "`trace'"!="" { local noi noisily } preserve tempvar touse order quietly { marksample touse, novarlist if "`cc'`on'"!="" { markout `touse' `cc' `on' } * Record sort order gen long `order'=_n lab var `order' "obs. number" * For standard operation (no `on' list), disregard any completely missing rows in varlist, among marked obs if "`on'"=="" { tempvar rmis egen int `rmis'=rmiss(`varlist') if `touse'==1 count if `rmis'==0 replace `touse'=0 if `rmis'==`nvar' drop `rmis' } * Deal with weights frac_wgt `"`exp'"' `touse' `"`weight'"' local wgt `r(wgt)' * Sort out cmds (not checking if each cmd is valid - any garbage may be entered) if "`cmd'"!="" { * local cmds "regress logistic logit ologit mlogit" frac_dis "`cmd'" cmd "`varlist'" forvalues i=1/`nvar' { if "${S_`i'}"!="" { local cmd`i' ${S_`i'} } } } * Default for all uvis operations is nodraw, equivalent to match if "`draw'"!="" { tokenize `draw' while "`1'"!="" { ChkIn `1' "`varlist'" if `s(k)'>0 { local draw`s(k)' draw } mac shift } } if "`boot'"!="" { tokenize `boot' while "`1'"!="" { ChkIn `1' "`varlist'" if `s(k)'>0 { local boot`s(k)' boot } mac shift } } * Copy relevant members of varlist to new vars which will contain imputations count if `touse' local n=r(N) if `first'==0 { local first `nvar' } local ivars1 /* list of first `first' vars */ local ivars2 /* list of remaining vars */ local to_imp 0 /* actual number of vars with missing values imputed */ forvalues i=1/`nvar' { local xvar: word `i' of `varlist' if "`cmd`i''"=="" { /* Assign default cmd for vars not so far accounted for. Use logit if 2 distinct values, mlogit if 3-5, otherwise regress. */ quietly inspect `xvar' if `touse' local nuniq=r(N_unique) if `nuniq'==1 { noi di in red "only 1 distinct value of `xvar' found" exit 2000 } if `nuniq'==2 { count if `xvar'==0 & `touse'==1 if r(N)==0 { noi di in red "variable `xvar' unsuitable for imputation," noi di in red "binary variables must include at least one 0 and one non-missing value" exit 198 } local cmd`i' logit } else if `nuniq'<=5 { local cmd`i' mlogit } else local cmd`i' regress } count if `xvar'==. & `touse'==1 local nimp`i'=r(N) if `nimp`i''>0 { local to_imp=`to_imp'+1 if "`recycle'"=="" { * Create temporary variable with imputed variable tempvar ivar`i' if "`on'"=="" { * Initially fill missing obs cyclically with nonmissing obs sampmis `ivar`i''=`xvar' replace `ivar`i''=. if `touse'==0 } else gen `ivar`i''=`xvar' if `touse' lab var `ivar`i'' "`xvar' imput.`suffix' (`nimp`i'' values)" } else /* recycle */ local ivar`i': word `to_imp' of `recycle' if `to_imp'==1 & "`fivar'"=="" { * record first imputed var for counting purposes later local fivar `ivar`i'' } if "`genmiss'"!="" { tempvar mvar`i' gen byte `mvar`i''=missing(`xvar') if `touse'==1 lab var `mvar`i'' "1 if `xvar' missing, 0 otherwise" } } else local ivar`i' `xvar' if `i'<=`first' { local ivars1 `ivars1' `ivar`i'' } else local ivars2 `ivars2' `ivar`i'' } local ivars `ivars1' `ivars2' if `to_imp'==0 { noi di as err _n "All relevant cases are complete, no imputation required." return scalar N=`n' return scalar imputed=0 exit 2000 } if `to_imp'==1 | "`on'"!="" { local cycles 1 } * Impute sequentially `cycles' times by regression switching (van Buuren et al) tempvar imputed forvalues j=1/`cycles' { if "`trace'"!="" { noi di as text _n "Cycle `j'" } forvalues i=1/`nvar' { if `nimp`i''>0 { * Each var is reimputed based on imputed * values of other vars local y: word `i' of `varlist' if "`on'"=="" { strdel `ivar`i'' `ivars' local vars $S_1 } else local vars `on' * uvis is derived from uvisamp4.ado uvis7 `cmd`i'' `y' `vars' `wgt' if `touse', /* */ gen(`imputed') `boot`i'' `draw`i'' `constant' if "`trace'"!="" { sum `imputed' if missing(`y') & `touse'==1 noi di as text %11s "`y'" %7.0g r(mean) _cont foreach v of var `ivars' { if "`v'"=="`ivar`i''" { noi di as result " ." _cont } else noi di as result _skip(1) %7.0g _b[`v'] _cont } noi di } replace `ivar`i''=`imputed' drop `imputed' } } if `to_imp'==1 { noi di as text "[Only 1 variable to be imputed, therefore no cycling needed.]" _cont } if `to_imp'>1 & "`trace'"=="" { noi di as text "." _cont } } } forvalues i=1/`nvar' { return scalar ni`i'=`nimp`i'' } * Save to file with cases in original order quietly { local impvl /* list of newvars containing imputations */ sort `order' forvalues i=1/`nvar' { if `nimp`i''>0 { local x: word `i' of `varlist' replace `x'=`ivar`i'' if `touse' local impvl `impvl' `x' local lab: var label `ivar`i'' lab var `x' "`lab'" drop `ivar`i'' if "`genmiss'"!="" { cap drop `genmiss'`x' rename `mvar`i'' `genmiss'`x' } } } drop `touse' * Save list of imputed variables with imputations to char _dta[mi_ivar] char _dta[mi_ivar] `impvl' char _dta[mi_id] `id' rename `order' `id' save `"`using'"', replace noi di as text _n "File " as result `"`using'"' as text " created." } return local impvl `impvl' return scalar imputed=`to_imp' end *! v 1.0.0 PR 01Jun2001. program define sampmis version 7 * Duplicates nonmissing obs of `exp' into missing ones, in random order. * This routine always reproduces the same sort order among the missings. * Note technique to avoid Stata creating arbitrary sort order for missing * observations of `exp'; affects entire reproducibility of mvi sampling. syntax newvarname =/exp quietly { tempvar u * Sort non-missing data at random, sort missing data systematically gen double `u'=cond(missing(`exp'), _n, uniform()) sort `u' count if !missing(`exp') local nonmis=r(N) drop `u' local type: type `exp' gen `type' `varlist'=`exp' local blocks=int((_N-1)/`nonmis') forvalues i=1/`blocks' { local j=`nonmis'*`i' local j1=`j'+1 local j2=min(`j'+`nonmis',_N) replace `varlist'=`exp'[_n-`j'] in `j1'/`j2' } } end *! v 1.2.0 PR 30Dec98. program define strdel version 5.0 if "`*'"=="" { error 198 } local target "`1'" mac shift local rest "`*'" local t: word count `target' local i 1 while `i'<=`t' { local w: word `i' of `target' local lw=length("`w'") local wild=(substr("`w'",`lw',.)=="*") if `wild' { local w=substr("`w'",1,`lw'-1) } local new parse "`rest'", parse(" ") while "`1'"!="" { if `wild' { if substr("`1'",1,`lw'-1)!="`w'" { local new `new' `1 } } else { if "`1'"!="`w'" { local new `new' `1' } } mac shift } local rest `new' local i=`i'+1 } global S_1 `rest' end program define _rmdups, rclass * based on Carlin's _mi_unique.ado version 7 local res abc local keep tokenize `0' local 0 while "`1'"!=""{ local 0 `0' `1' mac shift } while "`res'"~="" { local res gettoken first rest: 0 tokenize `rest' while "`1'"!="" { cap assert "`first'"=="`1'" if _rc { local res `res' `1' } mac shift } local keep `keep' `first' local 0 `res' } local N: word count `keep' return local unique `keep' return scalar N=`N' end program define ChkIn, sclass version 7 * Returns s(k) = index # of target variable v in varlist, or 0 if not found. args v varlist sret clear sret local k 0 tokenize `varlist' local j 1 while "``j''"!="" { if "`v'"=="``j''" { sret local k `j' continue, break } local j=`j'+1 } if `s(k)'==0 { di as err "`v' is not a valid covariate" exit 198 } end