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.
906 lines
24 KiB
Plaintext
906 lines
24 KiB
Plaintext
10 months ago
|
*! version 1.1.1 PR 23sep2005.
|
||
|
*
|
||
|
* History of ice
|
||
|
* 1.1.1 23sep2005 Better error trapping for passive() and substitute() options.
|
||
|
* 1.1.0 23aug2005 Replace -draw- option with -match-. Default becomes draw.
|
||
|
* Trace option documented, now has argument for filename.
|
||
|
* Report number of rows with 0, 1, 2, ... missing values.
|
||
|
* Arrange variables in increasing order of missingness when imputing.
|
||
|
* Split ties at random when more than one observation satisfies the
|
||
|
* prediction matching criterion
|
||
|
* 1.0.4 21jul2005 Trap and report error when running uvis
|
||
|
* 1.0.3 08jun2005 Tidy up display of equations when have multiple lines (long equations)
|
||
|
* 1.0.3 03jun2005 Silence file load/save
|
||
|
* 1.0.2 20may2005 Changed files containing imputations to tempfiles (standalone mode)
|
||
|
* (Angela Wood reported problem).
|
||
|
* 1.0.1 04may2005 Added a trace to a file (undocumented in help file).
|
||
|
* 1.0.0 18apr2005 First release, based on mice.
|
||
|
*
|
||
|
* History of mice
|
||
|
* 1.0.3 13apr2005 Minor tidying up, including recode of ChkIn and deletion of strdel.
|
||
|
* Check if prediction equations have a variable on both sides.
|
||
|
* 1.0.2 17feb2005 Added code to take care of inherited missingness of passive variables robustly.
|
||
|
* 1.0.1 21jan2005 Added display of regression command in showing prediction equations.
|
||
|
* 1.0.0 20jan2005 First release, based on mvis2/_mvis2.
|
||
|
*
|
||
|
* History of mvis
|
||
|
* 1.1.0 18jan2005 categoric() option removed.
|
||
|
* New options dryrun, passive(), substitute(), eq() added.
|
||
|
* Improvements to output showing actual prediction equations.
|
||
|
* 1.0.5 19nov2004 Delete dummy variables for categoric() variables with no missing data from output file
|
||
|
* Found problem with bsample in Stata 7 with "if" clause and boot option.
|
||
|
* Revert to Stata 8 for mvis, _mvis and uvis.
|
||
|
* 1.0.4 18nov2004 Weights not working (syntax error), fixed.
|
||
|
* 1.0.3 16nov2004 Categoric() option added to deal with unordered categoric
|
||
|
* covariates, updated default handling of such variables
|
||
|
* 1.0.2 16oct2004 Saving, using etc of file safest with compound quotes, fixed.
|
||
|
*
|
||
|
program define ice, rclass
|
||
|
version 8
|
||
|
* Check for _I* variables, could be created by xi:
|
||
|
capture describe _I*
|
||
|
if _rc==0 {
|
||
|
di as err _n "Warning: _I* variables detected in the dataset - was xi: used?"
|
||
|
di as inp "Use of xi: with mvis is liable to give incorrect results."
|
||
|
di as inp "If you wish to model categoric covariates with dummy"
|
||
|
di as inp "variables, please recalculate the dummies via the passive() option"
|
||
|
di as inp "and use the substitute() option to identify the dummies as predictors." _n
|
||
|
}
|
||
|
local m `s(MI_m)'
|
||
|
if "`m'"!="" {
|
||
|
* Called by mi_impute
|
||
|
local mitools mitools
|
||
|
local mopt
|
||
|
local uopt
|
||
|
local fn0 `s(MI_tfile)'
|
||
|
local using `fn0'
|
||
|
forvalues i=1/`m' {
|
||
|
local fn`i' `s(MI_tfile`i')'
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
* standalone
|
||
|
local mitools
|
||
|
local mopt "m(int 1)"
|
||
|
local uopt [using/]
|
||
|
}
|
||
|
|
||
|
syntax varlist(min=2 numeric) [if] [in] [aweight fweight pweight iweight] `uopt', /*
|
||
|
*/ [ `mopt' REPLACE Seed(int 0) BOot MAtch DRYrun * ]
|
||
|
|
||
|
* Check if there are variables called boot and/or match
|
||
|
if "`boot'"=="boot" {
|
||
|
cap confirm var boot
|
||
|
if _rc local options `options' boot(`varlist')
|
||
|
else local options `options' boot(boot)
|
||
|
}
|
||
|
if "`match'"=="match" {
|
||
|
cap confirm var match
|
||
|
if _rc local options `options' match(`varlist')
|
||
|
else local options `options' match(match)
|
||
|
}
|
||
|
if `seed'>0 set seed `seed'
|
||
|
local first first
|
||
|
if "`dryrun'"!="" {
|
||
|
if `"`using'"'=="" {
|
||
|
tempname fn
|
||
|
local using `fn'
|
||
|
}
|
||
|
_ice `varlist' `if' `in' [`weight' `exp'] using `using', `options' first dryrun
|
||
|
di as text _n "End of dry run. No imputations were done, no files were created."
|
||
|
exit
|
||
|
}
|
||
|
preserve
|
||
|
if "`mitools'"=="" {
|
||
|
if `m'<1 {
|
||
|
di as err "number of imputations must be 1 or more"
|
||
|
exit 198
|
||
|
}
|
||
|
if `"`using'"'=="" {
|
||
|
if "`dryrun'"=="" {
|
||
|
di as err "using required"
|
||
|
exit 100
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if substr(`"`using'"',-4,.)!=".dta" {
|
||
|
local using `using'.dta
|
||
|
}
|
||
|
if "`replace'"=="" {
|
||
|
confirm new file `"`using'"'
|
||
|
}
|
||
|
}
|
||
|
forvalues i=1/`m' {
|
||
|
tempfile fn`i'
|
||
|
_ice `varlist' `if' `in' [`weight' `exp'] using `fn`i'', `options' `first'
|
||
|
di as text `i' ".." _cont
|
||
|
local first
|
||
|
}
|
||
|
* Join files of imputations vertically using code from mijoin.ado
|
||
|
quietly {
|
||
|
local J _j
|
||
|
forvalues j=1/`m' {
|
||
|
* could automate this part
|
||
|
use `"`fn`j''"', clear
|
||
|
chkrowid
|
||
|
local I `s(I)'
|
||
|
if "`I'"=="" {
|
||
|
* create row number
|
||
|
local I _i
|
||
|
cap drop `I'
|
||
|
gen long `I'=_n
|
||
|
lab var `I' "obs. number"
|
||
|
}
|
||
|
cap drop `J'
|
||
|
gen int `J'=`j'
|
||
|
lab var `J' "imputation number"
|
||
|
save `"`fn`j''"', replace
|
||
|
}
|
||
|
use `"`fn1'"', clear
|
||
|
forvalues j=2/`m' {
|
||
|
append using `"`fn`j''"'
|
||
|
}
|
||
|
char _dta[mi_id] `I'
|
||
|
}
|
||
|
save `"`using'"', `replace'
|
||
|
}
|
||
|
else {
|
||
|
* Save original data and imputations to tempfiles for mi_impute to stack
|
||
|
* fn0,...,fn`m' are local macros created by mi_impute and supplied as s() functions;
|
||
|
* they contain the actual names of tempfiles, hence the need for compound quotes.
|
||
|
local original original
|
||
|
forvalues i=0/`m' {
|
||
|
if "`replace'"!="" cap drop `"`fn`i''"' // !! bug - should be erase not cap drop?
|
||
|
_ice `varlist' `if' `in' [`weight' `exp'] using `"`fn`i''"', ///
|
||
|
`options' `first' `original' mitools
|
||
|
di as text `i' ".." _cont
|
||
|
local original
|
||
|
if `m'>0 local first
|
||
|
}
|
||
|
}
|
||
|
end
|
||
|
|
||
|
program define chkrowid, sclass
|
||
|
version 8
|
||
|
local I: char _dta[mi_id]
|
||
|
if "`I'"=="" exit
|
||
|
cap confirm var `I'
|
||
|
if _rc exit
|
||
|
sret local I `I'
|
||
|
end
|
||
|
|
||
|
*! Based on _mvis2 version 1.0.2 PR 19jan2005.
|
||
|
program define _ice, rclass
|
||
|
version 8
|
||
|
syntax varlist(min=2 numeric) [if] [in] [aw fw pw iw] using/, /*
|
||
|
*/ [ BOot(varlist) CC(varlist) CMd(string) CYcles(int 10) noCONStant MAtch(varlist) /*
|
||
|
*/ DRYrun EQ(string) first Genmiss(string) Id(string) mitools ON(varlist) original /*
|
||
|
*/ PASsive(string) noSHoweq SUBstitute(string) TRace(string) ]
|
||
|
|
||
|
if "`original'"!="" {
|
||
|
* Save original data
|
||
|
quietly save `"`using'"', replace
|
||
|
exit
|
||
|
}
|
||
|
|
||
|
local nvar: word count `varlist'
|
||
|
if "`id'"!="" {
|
||
|
confirm new var `id'
|
||
|
}
|
||
|
else local id _i
|
||
|
|
||
|
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'
|
||
|
replace `rmis'=. if `rmis'==`nvar'
|
||
|
lab var `rmis' "#missing values"
|
||
|
if "`first'"!="" & "`showeq'"=="" noi tab `rmis', missing
|
||
|
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"
|
||
|
detangle "`cmd'" cmd "`varlist'"
|
||
|
forvalues i=1/`nvar' {
|
||
|
if "${S_`i'}"!="" {
|
||
|
local cmd`i' ${S_`i'}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
* Default for all uvis operations is nomatch, meaning draw
|
||
|
if "`match'"!="" {
|
||
|
tokenize `match'
|
||
|
while "`1'"!="" {
|
||
|
ChkIn `1' "`varlist'"
|
||
|
if `s(k)'>0 {
|
||
|
local match`s(k)' match
|
||
|
}
|
||
|
mac shift
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if "`boot'"!="" {
|
||
|
tokenize `boot'
|
||
|
while "`1'"!="" {
|
||
|
ChkIn `1' "`varlist'"
|
||
|
if `s(k)'>0 {
|
||
|
local boot`s(k)' boot
|
||
|
}
|
||
|
mac shift
|
||
|
}
|
||
|
}
|
||
|
local anyerr 0
|
||
|
if `"`passive'"'!="" {
|
||
|
tempvar passmiss
|
||
|
/*
|
||
|
Defines vars that are functions or transformations of others in varlist.
|
||
|
They are (may be) "passively imputed". "\" is an expression separator.
|
||
|
Default is comma.
|
||
|
Comma may not always be appropriate (i.e. may appear in an expression).
|
||
|
*/
|
||
|
detangle "`passive'" passive "`varlist'" \
|
||
|
local haserr 0
|
||
|
forvalues i=1/`nvar' {
|
||
|
if "${S_`i'}"!="" {
|
||
|
local exp`i' ${S_`i'}
|
||
|
ParsExp `exp`i''
|
||
|
local exclude `s(result)'
|
||
|
if "`exclude'"!="" {
|
||
|
* Count missingness of this passive variable
|
||
|
egen int `passmiss'=rmiss(`exclude') if `touse'
|
||
|
count if `passmiss'>0 & `touse'==1
|
||
|
local nimp`i'=r(N)
|
||
|
if `nimp`i''==0 {
|
||
|
local v: word `i' of `varlist'
|
||
|
noi di as err "passive definition `v' = (${S_`i'}) redundant: `exclude' has no missing data."
|
||
|
local ++haserr
|
||
|
}
|
||
|
drop `passmiss'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if `haserr'>0 {
|
||
|
di as err "`haserr' error(s) found in option " as inp "passive(`passive')"
|
||
|
local anyerr 1
|
||
|
}
|
||
|
}
|
||
|
if "`substitute'"!="" {
|
||
|
* defines vars that are to be substituted in the recalc context
|
||
|
detangle "`substitute'" substitute "`varlist'"
|
||
|
local haserr 0
|
||
|
forvalues i=1/`nvar' {
|
||
|
if "${S_`i'}"!="" {
|
||
|
local sub`i' ${S_`i'}
|
||
|
local v: word `i' of `varlist'
|
||
|
count if missing(`v') & `touse'==1
|
||
|
if r(N)==0 {
|
||
|
noi di as err "substitute for variable `v' redundant: `v' has no missing data."
|
||
|
local ++haserr
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if `haserr'>0 {
|
||
|
noi di as err "`haserr' error(s) found in option " as inp "substitute(`substitute')"
|
||
|
local anyerr 1
|
||
|
}
|
||
|
}
|
||
|
if `"`eq'"'!="" {
|
||
|
* defines equations specified vars.
|
||
|
detangle "`eq'" equation "`varlist'"
|
||
|
forvalues i=1/`nvar' {
|
||
|
if "${S_`i'}"!="" {
|
||
|
local Eq`i' ${S_`i'}
|
||
|
* Check that eq vars are in mainvarlist
|
||
|
tokenize `Eq`i''
|
||
|
while "`1'"!="" {
|
||
|
ChkIn `1' "`varlist'"
|
||
|
mac shift
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if `anyerr' {
|
||
|
di as err _n "specification error(s) found."
|
||
|
exit 198
|
||
|
}
|
||
|
count if `touse'
|
||
|
local n=r(N)
|
||
|
/*
|
||
|
Count potentially imputable missing values for each variable,
|
||
|
and where necessary create an equation for each
|
||
|
*/
|
||
|
local to_imp 0 // actual number of vars with missing values to be imputed
|
||
|
local recalc 0 // number of passively imputed vars to be recalculated
|
||
|
tempvar xtmp // temporary holding area
|
||
|
local nimp // list of number of missing values for each variable
|
||
|
forvalues i=1/`nvar' {
|
||
|
local xvar: word `i' of `varlist'
|
||
|
if "`genmiss'"!="" {
|
||
|
tempvar mvar`i'
|
||
|
gen byte `mvar`i''=missing(`xvar') if `touse'==1
|
||
|
lab var `mvar`i'' "1 if `xvar' missing, 0 otherwise"
|
||
|
}
|
||
|
local x`i' `xvar'
|
||
|
count if missing(`xvar') & `touse'==1
|
||
|
* Create prediction equation for each active variable
|
||
|
if r(N)>0 & `"`exp`i''"'=="" {
|
||
|
local nimp`i'=r(N)
|
||
|
* active var: has missing obs, not passive
|
||
|
local ++to_imp
|
||
|
local main`i' 1
|
||
|
* Keep missingness of the original variable
|
||
|
tempvar miss`i'
|
||
|
gen byte `miss`i''=missing(`xvar') if `touse'==1
|
||
|
* Define equation for this variable - user definition from eq() takes precedence
|
||
|
if "`Eq`i''"!="" {
|
||
|
local eq`i' `Eq`i''
|
||
|
}
|
||
|
else {
|
||
|
* Remove variable from mainvarlist
|
||
|
local eq`i': list varlist - xvar
|
||
|
}
|
||
|
if "`cmd`i''"=="" {
|
||
|
/*
|
||
|
Assign default cmd for vars not so far accounted for.
|
||
|
cmd is relevant only for vars requiring imputation, i.e. with >=1 missing values.
|
||
|
Use logit if 2 distinct values, mlogit if 3-5, otherwise regress.
|
||
|
*/
|
||
|
inspect `xvar' if `touse'
|
||
|
local nuniq=r(N_unique)
|
||
|
if `nuniq'==1 {
|
||
|
noi di as err "only 1 distinct value of `xvar' found"
|
||
|
exit 2000
|
||
|
}
|
||
|
if `nuniq'==2 {
|
||
|
count if `xvar'==0 & `touse'==1
|
||
|
if r(N)==0 {
|
||
|
noi di as err "variable `xvar' unsuitable for imputation,"
|
||
|
noi di as err "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
|
||
|
}
|
||
|
if "`cmd`i''"=="mlogit" {
|
||
|
* With mlogit, if xvar carries a score label,
|
||
|
* drop it since it causes prediction problems
|
||
|
local xlab: value label `xvar'
|
||
|
capture label drop `xlab'
|
||
|
}
|
||
|
if "`on'"=="" {
|
||
|
* Initially fill missing obs cyclically with nonmissing obs
|
||
|
sampmis `xtmp'=`xvar'
|
||
|
replace `xvar'=cond(`touse'==0, ., `xtmp')
|
||
|
drop `xtmp'
|
||
|
}
|
||
|
else replace `xvar'=. if `touse'==0
|
||
|
local lab`i' `xvar' imput.`suffix' (`nimp`i'' values)
|
||
|
}
|
||
|
else {
|
||
|
local main`i' 0
|
||
|
if "`nimp`i''"=="" { // may have been set earlier by consideration of ParsExp
|
||
|
local nimp`i'=r(N)
|
||
|
}
|
||
|
if `"`exp`i''"'!="" {
|
||
|
if "`Eq`i''"!="" {
|
||
|
noi di as err "equation" as input " `xvar':`Eq`i'' " ///
|
||
|
as err "invalid, `xvar' is passively imputed"
|
||
|
exit 198
|
||
|
}
|
||
|
local ++recalc
|
||
|
}
|
||
|
}
|
||
|
local nimp `nimp' `nimp`i''
|
||
|
}
|
||
|
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
|
||
|
}
|
||
|
* Remove passivevars from equations as necessary
|
||
|
forvalues i=1/`nvar' {
|
||
|
if `"`exp`i''"'!="" {
|
||
|
ParsExp `exp`i''
|
||
|
local exclude `s(result)'
|
||
|
* remove current passivevar from each relevant equation
|
||
|
local passive `x`i''
|
||
|
tokenize `exclude'
|
||
|
while "`1'"!="" {
|
||
|
* identify which variable in mainvarlist we are looking at
|
||
|
ChkIn `1' "`varlist'"
|
||
|
local index `s(k)'
|
||
|
* Remove `passive' from equation of variable
|
||
|
* whose index in mainvarlist is `index'
|
||
|
* (only allowed to be done if there is no
|
||
|
* user equation Eq`' for var #`index')
|
||
|
if "`eq`index''"!="" & "`Eq`index''"=="" {
|
||
|
local eq`index': list eq`index' - passive
|
||
|
}
|
||
|
mac shift
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if "`substitute'"!="" {
|
||
|
forvalues i=1/`nvar' {
|
||
|
if `main`i'' & "`sub`i''"!="" {
|
||
|
* substitute for this variable in all equations where it is a covariate
|
||
|
forvalues j=1/`nvar' {
|
||
|
if `main`j'' & (`j'!=`i') & "`Eq`j''"=="" {
|
||
|
local res: list eq`j' - x`i'
|
||
|
* substitute sub`i' if necessary i.e. if not already there
|
||
|
tokenize `sub`i''
|
||
|
while "`1'"!="" {
|
||
|
cap ChkIn `1' "`res'"
|
||
|
if "`s(k)'"=="0" {
|
||
|
local res `res' `1'
|
||
|
}
|
||
|
mac shift
|
||
|
}
|
||
|
local eq`j' `res'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
* Show prediction equations at first imputation
|
||
|
if "`first'"!="" {
|
||
|
local errs 0
|
||
|
local longstring 55 // max display length of variables in equation
|
||
|
local off 13 // blanks to col 13 on continuation lines
|
||
|
if "`showeq'"=="" {
|
||
|
noi di as text _n " Variable {c |} Command {c |} Prediction equation" _n ///
|
||
|
"{hline 12}{c +}{hline 9}{c +}{hline `longstring'}"
|
||
|
}
|
||
|
forvalues i=1/`nvar' {
|
||
|
if "`exp`i''"!="" & `nimp`i''>0 {
|
||
|
local eq "[Passively imputed from `exp`i'']"
|
||
|
local formatoutput 0
|
||
|
}
|
||
|
else if "`eq`i''"=="" {
|
||
|
local eq "[No missing data in estimation sample]"
|
||
|
local formatoutput 0
|
||
|
}
|
||
|
else {
|
||
|
local eq `eq`i''
|
||
|
local formatoutput 1
|
||
|
}
|
||
|
if "`showeq'"=="" {
|
||
|
if `formatoutput' {
|
||
|
formatline, n(`eq') maxlen(`longstring')
|
||
|
local nlines=r(lines)
|
||
|
forvalues j=1/`nlines' {
|
||
|
if `j'==1 noi di as text %11s abbrev("`x`i''",11) ///
|
||
|
" {c |} " %-8s "`cmd`i''" "{c |} `r(line`j')'"
|
||
|
else noi di as text _col(`off') ///
|
||
|
"{c |}" _col(23) "{c |} `r(line`j')'"
|
||
|
}
|
||
|
}
|
||
|
else noi di as text %11s abbrev("`x`i''",11) ///
|
||
|
" {c |} " %-8s "`cmd`i''" "{c |} `eq'"
|
||
|
}
|
||
|
// Check for invalid equation - xvar on both sides
|
||
|
if "`eq`i''"!="" {
|
||
|
if `: list x`i' in eq`i'' {
|
||
|
noi di as err "Error!" as inp " `x`i''" ///
|
||
|
as err " found on both sides of prediction equation"
|
||
|
local ++errs
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if `errs' {
|
||
|
di as err _n `errs' " error(s) found. Consider using the passive() option to fix the problem"
|
||
|
exit 198
|
||
|
}
|
||
|
if "`dryrun'"!="" {
|
||
|
exit
|
||
|
}
|
||
|
noi di as text _n "Imputing " _cont
|
||
|
}
|
||
|
if `to_imp'==1 | "`on'"!="" {
|
||
|
local cycles 1
|
||
|
}
|
||
|
* Update recalculated variables
|
||
|
if `"`passive'"'!="" & `recalc'>0 {
|
||
|
forvalues i=1/`nvar' {
|
||
|
if "`exp`i''"!="" {
|
||
|
replace `x`i''=`exp`i''
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
* Impute sequentially `cycles' times by regression switching (van Buuren et al)
|
||
|
tempvar y imputed
|
||
|
* Sort variables on number of missing values, from low to high numbers.
|
||
|
* Of benefit to the mice algorithm since less missings get imputed first.
|
||
|
listsort "`nimp'"
|
||
|
forvalues i=1/`nvar' {
|
||
|
local r`i' `s(index`i')'
|
||
|
}
|
||
|
if `"`trace'"'!="" {
|
||
|
tempname tmp
|
||
|
* create names
|
||
|
local postvl cycle
|
||
|
forvalues r=1/`nvar' {
|
||
|
local i `r`r'' // antirank: vars with small #missing come first
|
||
|
if `main`i'' local postvl `postvl' `x`i''_mean
|
||
|
}
|
||
|
postfile `tmp' `postvl' using `"`trace'"', replace
|
||
|
}
|
||
|
forvalues j=1/`cycles' {
|
||
|
if `"`trace'"'!="" local posts (`j')
|
||
|
forvalues r=1/`nvar' {
|
||
|
local i `r`r'' // antirank, ensuring vars with small #missing come first
|
||
|
if `main`i'' {
|
||
|
* Each var is reimputed based on imputed values of other vars
|
||
|
local type: type `x`i''
|
||
|
gen `type' `y'=`x`i'' if `miss`i''==0 & `touse'==1
|
||
|
if "`on'"=="" {
|
||
|
local vars `eq`i''
|
||
|
}
|
||
|
else local vars `on'
|
||
|
* uvis is derived from uvisamp4.ado
|
||
|
cap uvis `cmd`i'' `y' `vars' `wgt' if `touse', ///
|
||
|
gen(`imputed') `boot`i'' `match`i'' `constant'
|
||
|
if _rc {
|
||
|
noi di as err _n(2) "Error running -uvis-"
|
||
|
noi di as err "I detected a problem with running uvis with command `cmd`i'' on response `x`i''"
|
||
|
noi di as err "and covariates `vars'."
|
||
|
if "`cmd`i''"=="mlogit" {
|
||
|
noi di as inp "The troublesome regression command is mlogit."
|
||
|
noi di as inp "Try reducing the number of categories of `x`i'' or using ologit if appropriate"
|
||
|
}
|
||
|
exit 198
|
||
|
}
|
||
|
if `"`trace'"'!="" {
|
||
|
summarize `imputed' if missing(`y') & `touse'==1
|
||
|
local mean=r(mean)
|
||
|
local posts `posts' (`mean')
|
||
|
/*
|
||
|
noi di as text %11s abbrev("`x`i''",10) %7.0g `mean' _cont
|
||
|
foreach v of var `vars' {
|
||
|
if "`v'"=="`x`i''" {
|
||
|
noi di as result " ." _cont
|
||
|
}
|
||
|
else noi di as result _skip(1) %7.0g _b[`v'] _cont
|
||
|
}
|
||
|
noi di
|
||
|
*/
|
||
|
}
|
||
|
replace `x`i''=`imputed'
|
||
|
drop `y' `imputed'
|
||
|
}
|
||
|
}
|
||
|
if `"`trace'"'!="" post `tmp' `posts'
|
||
|
if `recalc'>0 { // update covariates needing recalculation
|
||
|
forvalues i=1/`nvar' {
|
||
|
if "`exp`i''"!="" & `nimp`i''>0 {
|
||
|
replace `x`i''=`exp`i''
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if `to_imp'==1 & "`first'"!="" {
|
||
|
noi di as text _n "[Only 1 variable to be imputed, therefore no cycling needed.]"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if `"`trace'"'!="" postclose `tmp'
|
||
|
* Save to file with cases in original order
|
||
|
quietly {
|
||
|
local impvl /* list of newvars containing imputations */
|
||
|
sort `order'
|
||
|
forvalues i=1/`nvar' {
|
||
|
return scalar ni`i'=`nimp`i''
|
||
|
if "`genmiss'"!="" {
|
||
|
cap drop `genmiss'`x`i''
|
||
|
rename `mvar`i'' `genmiss'`x`i''
|
||
|
}
|
||
|
if `main`i'' {
|
||
|
local impvl `impvl' `x`i''
|
||
|
lab var `x`i'' "`lab`i''"
|
||
|
cap drop `miss`i''
|
||
|
}
|
||
|
}
|
||
|
drop `touse'
|
||
|
if "`mitools'"=="" {
|
||
|
* 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'
|
||
|
return local impvl `impvl'
|
||
|
return scalar imputed=`to_imp'
|
||
|
}
|
||
|
else drop `order'
|
||
|
save `"`using'"', replace
|
||
|
}
|
||
|
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
|
||
|
|
||
|
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
|
||
|
local k: list posof "`v'" in varlist
|
||
|
sret local k `k'
|
||
|
if `s(k)'==0 {
|
||
|
di as err "`v' is not a valid covariate"
|
||
|
exit 198
|
||
|
}
|
||
|
end
|
||
|
|
||
|
*! version 1.0.0 PR 20dec2004.
|
||
|
program define ParsExp, sclass
|
||
|
version 8
|
||
|
tokenize `*', parse(" +-/^()[]{}.*=<>!$%&|~`'")
|
||
|
local vl
|
||
|
while "`1'"!="" {
|
||
|
cap confirm var `1'
|
||
|
if _rc==0 {
|
||
|
if index("`vl'", "`1'")==0 {
|
||
|
local vl `vl' `1'
|
||
|
}
|
||
|
}
|
||
|
mac shift
|
||
|
}
|
||
|
sreturn local result `vl'
|
||
|
end
|
||
|
|
||
|
program define detangle
|
||
|
version 8
|
||
|
/*
|
||
|
Disentangle varlist:string clusters---e.g. for DF.
|
||
|
Returns values in $S_*.
|
||
|
If `4' is null, `3' is assumed to contain rhs
|
||
|
and lowest and highest value checking is disabled.
|
||
|
Heavily based on frac_dis.ado, but "=" disallowed as separator
|
||
|
and "\" allowed (for use by passive()).
|
||
|
*/
|
||
|
args target tname rhs separator
|
||
|
if "`separator'"=="" {
|
||
|
local separator ","
|
||
|
}
|
||
|
unab rhs:`rhs'
|
||
|
local nx: word count `rhs'
|
||
|
forvalues j=1/`nx' {
|
||
|
local n`j': word `j' of `rhs'
|
||
|
}
|
||
|
tokenize "`target'", parse("`separator'")
|
||
|
local ncl 0 /* # of separator-delimited clusters */
|
||
|
while "`1'"!="" {
|
||
|
if "`1'"=="`separator'" {
|
||
|
mac shift
|
||
|
}
|
||
|
local ncl=`ncl'+1
|
||
|
local clust`ncl' "`1'"
|
||
|
mac shift
|
||
|
}
|
||
|
if "`clust`ncl''"=="" {
|
||
|
local --ncl
|
||
|
}
|
||
|
if `ncl'>`nx' {
|
||
|
di as err "too many `tname'() values specified"
|
||
|
exit 198
|
||
|
}
|
||
|
/*
|
||
|
Disentangle each varlist:string cluster
|
||
|
*/
|
||
|
forvalues i=1/`ncl' {
|
||
|
tokenize "`clust`i''", parse(":")
|
||
|
if "`2'"!=":" {
|
||
|
if `i'>1 {
|
||
|
noi di as err "invalid `clust`i'' in `tname'() (syntax error)"
|
||
|
exit 198
|
||
|
}
|
||
|
local 2 ":"
|
||
|
local 3 `1'
|
||
|
local 1
|
||
|
forvalues j=1/`nx' {
|
||
|
local 1 `1' `n`j''
|
||
|
}
|
||
|
}
|
||
|
local arg3 `3'
|
||
|
unab arg1:`1'
|
||
|
tokenize `arg1'
|
||
|
while "`1'"!="" {
|
||
|
ChkIn `1' "`rhs'"
|
||
|
local v`s(k)' `arg3'
|
||
|
mac shift
|
||
|
}
|
||
|
}
|
||
|
forvalues j=1/`nx' {
|
||
|
if "`v`j''"!="" {
|
||
|
global S_`j' `v`j''
|
||
|
}
|
||
|
else global S_`j'
|
||
|
}
|
||
|
end
|
||
|
|
||
|
*! Based on artformatnos.ado v 1.0.0 PR 26Feb2004
|
||
|
program define formatline, rclass
|
||
|
version 8
|
||
|
syntax, N(string) Maxlen(int) [ Format(string) Leading(int 1) Separator(string) ]
|
||
|
|
||
|
if `leading'<0 {
|
||
|
di as err "invalid leading()"
|
||
|
exit 198
|
||
|
}
|
||
|
|
||
|
if "`separator'"!="" {
|
||
|
tokenize "`n'", parse("`separator'")
|
||
|
}
|
||
|
else tokenize "`n'"
|
||
|
|
||
|
local n 0
|
||
|
while "`1'"!="" {
|
||
|
if "`1'"!="`separator'" {
|
||
|
local ++n
|
||
|
local n`n' `1'
|
||
|
}
|
||
|
macro shift
|
||
|
}
|
||
|
local j 0
|
||
|
local length 0
|
||
|
forvalues i=1/`n' {
|
||
|
*noi di in red "format=`format' i=`i' item=`n`i''"
|
||
|
if "`format'"!="" {
|
||
|
capture local out: display `format' `n`i''
|
||
|
if _rc {
|
||
|
di as err "invalid format attempted for: " `"`n`i''"'
|
||
|
exit 198
|
||
|
}
|
||
|
}
|
||
|
else local out `n`i''
|
||
|
if `leading'>0 {
|
||
|
local out " `out'"
|
||
|
}
|
||
|
local l1=length("`out'")
|
||
|
local l2=`length'+`l1'
|
||
|
if `l2'>`maxlen' {
|
||
|
local ++j
|
||
|
return local line`j'="`line'"
|
||
|
local line "`out'"
|
||
|
local length `l1'
|
||
|
}
|
||
|
else {
|
||
|
local length `l2'
|
||
|
local line "`line'`out'"
|
||
|
}
|
||
|
}
|
||
|
local ++j
|
||
|
return local line`j'="`line'"
|
||
|
return scalar lines=`j'
|
||
|
end
|
||
|
*! version 1.1.0 PR 02aug2005.
|
||
|
program define listsort, sclass
|
||
|
version 6
|
||
|
gettoken p 0 : 0, parse(" ,")
|
||
|
if `"`p'"'=="" {
|
||
|
exit
|
||
|
}
|
||
|
sret clear
|
||
|
syntax , [ Reverse Lexicographic ]
|
||
|
local lex="`lexicog'"!=""
|
||
|
if "`reverse'"!="" { local comp < }
|
||
|
else local comp >
|
||
|
local np: word count `p'
|
||
|
local i 1
|
||
|
while `i'<=`np' {
|
||
|
local p`i': word `i' of `p'
|
||
|
local index`i' `i'
|
||
|
if !`lex' { confirm number `p`i'' }
|
||
|
local i=`i'+1
|
||
|
}
|
||
|
* Apply shell sort (Kernighan & Ritchie p 58)
|
||
|
local gap=int(`np'/2)
|
||
|
while `gap'>0 {
|
||
|
local i `gap'
|
||
|
while `i'<`np' {
|
||
|
local j=`i'-`gap'
|
||
|
while `j'>=0 {
|
||
|
local j1=`j'+1
|
||
|
local j2=`j'+`gap'+1
|
||
|
if `lex' { local swap=(`"`p`j1''"' `comp' `"`p`j2''"') }
|
||
|
else local swap=(`p`j1'' `comp' `p`j2'')
|
||
|
if `swap' {
|
||
|
local temp `p`j1''
|
||
|
local p`j1' `p`j2''
|
||
|
local p`j2' `temp'
|
||
|
* swap indexes
|
||
|
local temp `index`j1''
|
||
|
local index`j1' `index`j2''
|
||
|
local index`j2' `temp'
|
||
|
}
|
||
|
local j=`j'-`gap'
|
||
|
}
|
||
|
local i=`i'+1
|
||
|
}
|
||
|
local gap=int(`gap'/2)
|
||
|
}
|
||
|
local p
|
||
|
local index
|
||
|
local i 1
|
||
|
while `i'<=`np' {
|
||
|
sret local i`i' `p`i''
|
||
|
sret local index`i' `index`i''
|
||
|
local p `p' `p`i''
|
||
|
local index `index' `index`i''
|
||
|
local i=`i'+1
|
||
|
}
|
||
|
/* Find antirank of each obs
|
||
|
forvalues i=1/`np' {
|
||
|
forvalues j=1/`np' {
|
||
|
if
|
||
|
*/
|
||
|
sret local list `p'
|
||
|
sret local index `index'
|
||
|
end
|
||
|
exit
|
||
|
|
||
|
sort `c'
|
||
|
local i 0
|
||
|
while `i'<`nx' {
|
||
|
local i=`i'+1
|
||
|
/*
|
||
|
Store positions of sorted predictors in user's list
|
||
|
*/
|
||
|
local j 0
|
||
|
while `j'<`nx' {
|
||
|
local j=`j'+1
|
||
|
if `i'==`n'[`j'] {
|
||
|
local r`j' `i'
|
||
|
local j `nx'
|
||
|
}
|
||
|
}
|
||
|
}
|