*! Version 1.1.0 2025-04-11 *! Author: Dejin Xie (Nanchang University, China) ** Version 1.1.0 2025-04-11, option "ascending" and "descending" added ** Version 1.0.0 2025-03-28, the initial version ****** Report Missing Observations of Individual and Time variables Panel Data ****** program define xtmiss , rclass sortpreserve version 13 syntax [if] [in] , Id(varlist) Time(varlist) [ Both Punct(string) Join(string) /// Exist Keep Ascending Descending Nolist * ] marksample touse, strok if "`nolist'"!="" & "`keep'"=="" { dis as res "Since ption {it:{ul:k}eep} is not set, option {it:{ul:n}olist} is ignored automatically." local nolist "" } if "`ascending'"!="" & "`descending'"!="" { dis as err "option {it:{ul:a}scending} or {it:{ul:d}escending} should be set at most one." exit } if "`join'"=="" { local join ";" } quietly { capture assert `touse'==1 local TouSe=!_rc if `TouSe'==0 { tempvar XtMissiD gen `XtMissiD'=_n local XtNum=`c(N)' preserve keep if `touse' tempfile XtMissFile } capture drop Id_Var egen Id_Var = concat(`id') , punct(`punct') capture Time_Var egen Time_Var = concat(`time') , punct(`punct') return local Idvars `id' return local Timevars `time' return scalar exist_num=`c(N)' if "`exist'"!="" { capture drop Id_Exist bysort Time_Var : gen Id_Exist=_N capture drop Time_Exist bysort Id_Var : gen Time_Exist=_N } capture drop _fillin fillin Id_Var Time_Var return scalar balance_num=`c(N)' count if _fillin==1 return scalar missing_num=`r(N)' if `r(N)'==0 { noisily dis as res "There is no missing observations in the data (i.e. fully balanced)." capture drop Id_Var Time_Var Id_Exist Time_Exist _fillin exit } capture drop Id_Total bysort Time_Var : gen Id_Total=_N capture drop Id_Miss bysort Time_Var : egen Id_Miss=total(_fillin==1) capture drop Id_MProp gen Id_MProp = Id_Miss/Id_Total sort Id_Var Time_Var stvarag Id_Var if _fillin==1 , by(Time_Var) parse(`join') generate(Id_MissElm) if "`both'"!="" { capture drop Time_Total bysort Id_Var : gen Time_Total=_N capture drop Time_Miss bysort Id_Var : egen Time_Miss=total(_fillin==1) capture drop Time_MProp gen Time_MProp = Time_Miss/Time_Total sort Id_Var Time_Var stvarag Time_Var if _fillin==1 , by(Id_Var) parse(`join') generate(Time_MissElm) } if `TouSe'==0 { sort `XtMissiD' count if _fillin==0 replace `XtMissiD'=`XtNum'+_n-`r(N)' if _fillin==1 save `XtMissFile', replace restore merge 1:1 `XtMissiD' using `XtMissFile', nogen } if "`Nolist'"=="" { preserve keep if `touse' & _fillin==1 bysort Time_Var (_fillin) : keep if _n==_N if "`ascending'"!="" { sort Id_Miss Time_Var } if "`descending'"!="" { gsort -Id_Miss Time_Var } noisily dis _dup(90) "{bf:{res:~}}" noisily dis as txt "The missing situations of individual variable " as res "`id'" as txt " (" as res "n=`=Id_Total[1]'" as txt") are as follows :" noisily list Time_Var Id_Miss Id_MProp Id_MissElm , noobs abbr(30) `options' restore if "`both'"!="" { preserve keep if `touse' & _fillin==1 bysort Id_Var (_fillin) : keep if _n==_N if "`ascending'"!="" { sort Time_Miss Id_Var } if "`descending'"!="" { gsort -Time_Miss Id_Var } noisily dis _dup(90) "{bf:{res:~}}" noisily dis as txt "The missing situations of time variable " as res "`time'" as txt " (" as res "T=`=Time_Total[1]'" as txt") are as follows :" noisily list Id_Var Time_Miss Time_MProp Time_MissElm , noobs abbr(30) `options' restore } } if "`keep'"!="" { bysort Time_Var (_fillin) : replace Id_MissElm = Id_MissElm[_N] if `touse' lab var Id_MissElm "Missing elements in (`id')" bysort Time_Var (_fillin) : replace Id_Miss = Id_Miss[_N] if `touse' lab var Id_Miss "Number of missing obs in (`id')" bysort Time_Var (_fillin) : replace Id_Total = Id_Total[_N] if `touse' lab var Id_Total "Total number of obs in (`id')" bysort Time_Var (_fillin) : replace Id_MProp = Id_MProp[_N] if `touse' lab var Id_MProp "Proportion of missing obs in (`id')" if "`exist'"!="" { lab var Id_Exist "Number of existing obs in (`id')" } if "`both'"!="" { bysort Id_Var (_fillin) : replace Time_MissElm = Time_MissElm[_N] if `touse' lab var Time_MissElm "Missing elements in (`time')" bysort Id_Var (_fillin) : replace Time_Miss = Time_Miss[_N] if `touse' lab var Time_Miss "Number of missing obs in (`time')" bysort Id_Var (_fillin) : replace Time_Total = Time_Total[_N] if `touse' lab var Time_Total "Total number of obs in (`time')" bysort Id_Var (_fillin) : replace Time_MProp = Time_MProp[_N] if `touse' lab var Time_MProp "Proportion of missing obs in (`time')" if "`exist'"!="" { lab var Time_Exist "Number of existing obs in (`time')" order Time_Exist, before(Time_Total) } } } else { capture drop Id_Miss Id_Total Id_MProp Id_MissElm `XtMissiD' if "`exist'"!="" { capture drop Id_Exist Time_Exist } if "`both'"!="" { capture drop Time_Miss Time_Total Time_MProp Time_MissElm } } capture drop Id_Var Time_Var capture drop if _fillin==1 capture drop _fillin } /* Close brace of quietly */ end