### Site Tools

lab:projects:17robust_sem:robust_sem_with_missing_data_sas_codes
* Input raw data (with missing values -99) from an external file;
data raw;
filename data 'Z:\zzy\research\Robust SEM\Missing data with Ke-Hai\mardiaMV25.dat.txt'; *need to be modified;
*filename data 'd:\missingdata-robustSEM\mardiaMV25_contaminated.dat'; *need to be modified;
infile data;
input v1 v2 v3 v4 v5;  *need to be modified;
run;
*-----------------------------------------------------------------------*;
*-----------------------------------------------------------------------*;
** Missing data are on the last variable;
** The first stage is Huber-weight using an extended EM-algorithm;
** The second stage analysis is to minimizing the normal-distribution-based
discrepancy function F_ML;
** Rescaled or adjusted statistics is used for inference;
*the asymptotic cov is given by sandwich type matrix;
** as well as the inverse of the information matrix;
options ls=150;
*options nodate nonumber;
title;
proc iml;
reset noname;
*-----------------------------------------------------------------------*;
*misinfo=j(m,p+2,0), m is the number of missing patterns;
*misinfo[i,1]=number of cases in pattern i;
*misinfo[i,2]=number of observed variables in pattern i;
*misinfo[i,3:p+2] contains a permutation of {1,2,3,...,p},
the first part corresponding to observed variables,
the remaining corresponding to missing variables in pattern i;

start pattern(n,p,x,misinfo);
*-------------------------------------------------------------------------;
*use 2^j to order missing data patterns by SAS sort subroutine;
misorder=j(n,1,0);
do i=1 to n;
misorderj=0;
do j=1 to p;
xij=x[i,j];
if xij=-99 then do;
misorderj=misorderj+2**(j-1);*this gives each missing pattern a unique number;
end;
end;
misorder[i]=misorderj;
end;
x=x||misorder;
call sort( x, p+1);*sort the rows of x according to the (p+1)th column from small to large;
*-------------------------------------------------------------------------;
print x;
misn=x[,p+1];
x=x[,1:p];
*--------------------------------------------------------------------------;
*identifying the subscripts of missing variables and put them in misinfo;
mi=0; nmi=0; oi=0; noi=0;
do j=1 to p;
if x[1,j]=-99 then do;
mi=mi||j; *recording the missing variable subscript in the first case;
nmi=nmi+1; *number of missing values in the first case;
end;
else do;
oi=oi||j;*recording the observed variable subscript in the first case;
noi=noi+1;
end;
end;
oi=(oi[2:noi+1]);
if nmi=0 then do;
misinfo_0=noi||oi;
end;
else do;
mi=(mi[2:nmi+1]);
misinfo_0=noi||oi||mi; *recording the # observed variables, locations;
end;
*--------------------------------------------------------------------------;
patnobs=0; *# of observed cases in a pattern;
totpat=1; ncount=1;
t1=misn[1];
do i=2 to n;
if 	misn[i]=t1 then do;
ncount=ncount+1;
end;
else do;
patnobs=patnobs//ncount;
t1=misn[i];
ncount=1;
totpat=totpat+1;

mi=0; nmi=0; oi=0; noi=0;
do j=1 to p;
if x[i,j]=-99 then do;
mi=mi||j;
nmi=nmi+1;
end;
else do;
oi=oi||j;
noi=noi+1;
end;
end;
oi=(oi[2:noi+1]);
mi=(mi[2:nmi+1]);
misinfo_0=misinfo_0//(noi||oi||mi);
end;

end;
patnobs=patnobs//ncount;
patnobs=patnobs[2:totpat+1];
misinfo=patnobs||misinfo_0;
print misinfo;
finish;

*-----------------------------------------------------------------------*;
** EM algorithm for unstructured (mu,sigma) starts here;
start emmusig(x,misinfo,varphi,err,mu1,sig1);
ep=.000000000001;
n=nrow(x); p=ncol(x);
mu0=j(p,1,0);*starting value;
sig0=i(p);*starting value;
n_it=0; **control iterations within 200;
err=0;
dt=1;
prob=1-varphi;
chip=cinv(prob,p);
ck=sqrt(chip);
cbeta=( p*probchi(chip,p+2)+ chip*(1-prob) )/p;
print cbeta;
do until (dt<ep);
sumx=j(p,1,0); sumxx=j(p,p,0); sumw1=0; sumw2=0;

npat=nrow(misinfo); *# of patterns;
p1=misinfo[1,2];*# of observed variables in pattern 1;
n1=misinfo[1,1];*# of observed cases in pattern 1;
if p1=p then do;*complete data;
sigin=inv(sig0);
do i=1 to n1;
xi=x[i,];
xi0=xi-mu0;
stdxi0=sigin*xi0;
di2=xi0*stdxi0;
di=sqrt(di2);
**Huber weight functions;
if di<=ck then do;
wi1=1.0;
wi2=1.0/cbeta;
end;
else do;
wi1=ck/di;
wi2=wi1*wi1/cbeta;
end;
sumw1=sumw1+wi1;
xxi0=xi0*xi0;
sumx=sumx+wi1*xi;
sumxx=sumxx+wi2*xxi0;
sumw2=sumw2+wi2;
end;
end;
else do;
chip1=cinv(prob,p1);
ck1=sqrt(chip1);
cbeta1=( p1*probchi(chip1,p1+2)+ chip1*(1-prob) )/p1;

o1=misinfo[1,3:(2+p1)];m1=misinfo[1,(2+p1+1):(p+2)];
mu_o=mu0[o1]; mu_m=mu0[m1];
sig_oo=sig0[o1,o1]; sig_om=sig0[o1,m1];
sig_mo=sig_om; sig_mm=sig0[m1,m1];
sigin_oo=inv(sig_oo);
beta_mo=sig_mo*sigin_oo;
Delt=j(p,p,0); Delt[m1,m1]=sig_mm-beta_mo*sig_om;
do i= 1 to n1;
xi=x[i,];
xi_o=xi[o1];
xi0_o=xi_o-mu_o;
stdxi_o=sigin_oo*xi0_o;
di2=xi0_o*stdxi_o;
di=sqrt(di2);
**Huber weight functions;
if di<=ck1 then do;
wi1=1.0;
wi2=1.0/cbeta1;
end;
else do;
wi1=ck1/di;
wi2=wi1*wi1/cbeta1;
end;
sumw1=sumw1+wi1;
xm1=mu_m+sig_mo*stdxi_o;  *change here;
xi[mi]=xm1;
xi0=xi-mu0;
xxi0=xi0*xi0;
sumx=sumx+wi1*xi;
sumxx=sumxx+wi2*xxi0+delt;
sumw2=sumw2+wi2;
end; *repeat the n1 cases;
end; *if p1=p;
*start from pattern 2;
snj=n1;
do j=2 to npat;
nj=misinfo[j,1]; pj=misinfo[j,2];
oj=misinfo[j,3:(2+pj)];mj=misinfo[j,(2+pj+1):(p+2)];
mu_o=mu0[oj]; mu_m=mu0[mj];
sig_oo=sig0[oj,oj]; sig_om=sig0[oj,mj];
sig_mo=sig_om; sig_mm=sig0[mj,mj];
sigin_oo=inv(sig_oo);
beta_mo=sig_mo*sigin_oo;
Delt=j(p,p,0); Delt[mj,mj]=sig_mm-beta_mo*sig_om;
chipj=cinv(prob,pj);
ckj=sqrt(chipj);
cbetaj=( pj*probchi(chipj,pj+2)+ chipj*(1-prob) )/pj;

do i=snj+1 to snj+nj;
xi=x[i,];
xi_o=xi[oj];
xi0_o=xi_o-mu_o;
stdxi_o=sigin_oo*xi0_o;
di2=xi0_o*stdxi_o;
di=sqrt(di2);
**Huber weight functions;
if di<=ckj then do;
wi1=1.0;
wi2=1.0/cbetaj;
end;
else do;
wi1=ckj/di;
wi2=wi1*wi1/cbetaj;
end;
sumw1=sumw1+wi1;
xmj=mu_m+sig_mo*stdxi_o; *change here;
xi[mj]=xmj;
xi0=xi-mu0;
xxi0=xi0*xi0;
sumx=sumx+wi1*xi;
sumxx=sumxx+wi2*xxi0+delt;
sumw2=sumw2+wi2;
end; *run through the cases within a pattern;
snj=snj+nj;
end; *number of patterns;
mu1=sumx/sumw1;
sig1=sumxx/n;
dt=(ssq(mu1-mu0)+ssq(sig1-sig0))/(ssq(mu0)+ssq(sig0));
mu0=mu1;
sig0=sig1;
n_it=n_it+1;
if n_it>200 then do;
err=1;
goto label2;
end;
end;
print mu1;
print sig1;
label2:
finish;
*-----------------------------------------------------------------------*;
**** The following subroutine is to perform vech(.) function;
*-----------------------------------------------------------------------*;
start vech(A,Va);
l=0;
p=nrow(A);
pstar=p*(p+1)/2;
Va=j(pstar,1,0);
do i=1 to p by 1;
do j=i to p by 1;
l=l+1;
Va(|l|)=A(|j,i|);
end;
end;
finish;
***--------------------------------------------------------------------***;
**** The following subroutine is to perform vec(.) function;
***--------------------------------------------------------------------***;
start vec(A,Veca);
l=0;
p=nrow(A);
p2=p*p;
Veca=j(p2,1,0);
do j=1 to p;
Veca[(j-1)*p+1:j*p]=A[,j];
end;
finish;
***--------------------------------------------------------------------***;
** creates duplication matrix as defined in Magnus&Neudecker;
***--------------------------------------------------------------------***;
start DP(p, dup);
Dup=j(p*p,p*(p+1)/2,0);
count=0;
do j=1 to p;
do i=j to p;
count=count+1;
if i=j then do;
Dup[(j-1)*p+j, count]=1;
end;
else do;
Dup[(j-1)*p+i, count]=1;
Dup[(i-1)*p+j, count]=1;
end;
end;
end;
finish;

*-----------------------------------------------------------------------*;
*-----------------------------------------------------------------------*;
**creating index for vec(Sigma_j) corresponding to the observed cases;
*-----------------------------------------------------------------------*;
start index(p,oj,indexj);
index=j(p,p,0);
count=0;
do i=1 to p;
do j=1 to p;
count=count+1;
index[j,i]=count;
end;
end;
indexoj=index[oj,oj];
nj=nrow(indexoj);
vecj=0;
do i=1 to nj;
vecj=vecj//indexoj[,i];
end;
indexj=vecj[2:nj*nj+1];
finish;

*-----------------------------------------------------------------------*;
**computing the estimator of the asymptotic covariance of
\hat\Omega_{\hat\beta};
*-----------------------------------------------------------------------*;
start Ascov(varphi,mu0,sig0,x,misinfo, Abeta, Bbeta, Gamma);
n=nrow(x); p=ncol(x);
ps=p*(p+1)/2; pps=p+ps;
run dp(p,dup); dupt=dup;
i_p=i(p);

B11=j(p,p,0); B12=j(p,ps,0); B22=j(ps,ps,0);
ddl11=j(p,p,0); ddl12=j(p,ps,0); ddl21=j(ps,p,0); ddl22=j(ps,ps,0);
prob=1-varphi;

chip=cinv(prob,p);
ck=sqrt(chip);
cbeta=( p*probchi(chip,p+2)+ chip*(1-prob) )/p;

dl=j(pps,1,0);

npat=nrow(misinfo);
n1=misinfo[1,1]; p1=misinfo[1,2];
if p1=p then do;*complete data;
sigin=inv(sig0);
run vec(sig0,vecsig);
Wmat=0.5*(sigin@sigin);
do i=1 to n1;
xi=x[i,];
xi0=xi-mu0;
stdxi=sigin*xi0;
stdxit=stdxi;
di2=xi0*stdxi;
di=sqrt(di2);
**Huber weight functions;
if di<=ck then do;
wi1=1.0;
wi2=1.0/cbeta;
dwi1=0;
dwi2=0;
end;
else do;
wi1=ck/di;
wi2=wi1*wi1/cbeta;
dwi1=wi1/di2;
dwi2=wi2/di2;
end;
*for computing B_{\beta};
dlimu=wi1*stdxi;
xixi0=xi0*xi0;
run vec(xixi0,vecyi);
wvecyi=wi2*vecyi;
dlisig=dupt*Wmat*(wvecyi-vecsig);
B11=B11+dlimu*dlimu;
B12=B12+dlimu*dlisig;
B22=B22+dlisig*dlisig;
dl_i=dlimu//dlisig;
dl=dl+dl_i;
*for computing A_{\beta};
Hi=stdxi*stdxit;
tti=wi1*sigin;
uui=wi2*sigin;
ddl11=ddl11+(-tti+dwi1*Hi);
ddl22=ddl22+dupt*(Wmat-( Hi@(uui-.5*dwi2*Hi) ) )*dup;
ddl12=ddl12+((-tti+.5*dwi1*Hi)@stdxit )*dup;
ddl21=ddl21+dupt*((-uui+dwi2*Hi)@stdxi );
end; *repeat the n1 cases;
end; *if p1=p;
else do;
chip1=cinv(prob,p1);
ck1=sqrt(chip1);
cbeta1=( p1*probchi(chip1,p1+2)+ chip1*(1-prob) )/p1;
o1=misinfo[1,3:(2+p1)];
mu_o=mu0[o1];
sig_oo=sig0[o1,o1];
run vec(sig_oo,vecsig_oo);
sigin_oo=inv(sig_oo);
E1=i_p[o1,]; Et1=E1;
F1=(E1@E1)*dup; Ft1=F1;
Wmat1=0.5*(sigin_oo@sigin_oo);
do i= 1 to n1;
xi=x[i,];
xi_o=xi[o1];
xi0_o=xi_o-mu_o;
xi0_ot=xi0_o;
stdxi_o=sigin_oo*xi0_o;
stdxit_o=stdxi_o;
di2=xi0_ot*stdxi_o;
di=sqrt(di2);
**Huber weight functions;
if di<=ck1 then do;
wi1=1.0;
wi2=1.0/cbeta1;
dwi1=0;
dwi2=0;
end;
else do;
wi1=ck1/di;
wi2=wi1*wi1/cbeta1;
dwi1=wi1/di2;
dwi2=wi2/di2;
end;
*for computing B_{\beta};
dlimu=wi1*Et1*stdxi_o;
xixi0_o=xi0_o*xi0_ot;
run vec(xixi0_o,vecyi);
wvecyi=wi2*vecyi;
dlisig=Ft1*Wmat1*(wvecyi-vecsig_oo);
B11=B11+dlimu*dlimu;
B12=B12+dlimu*dlisig;
B22=B22+dlisig*dlisig;
dl_i=dlimu//dlisig;
dl=dl+dl_i;
*for computing A_{\beta};
Hi=stdxi_o*stdxit_o;
*tti=wi1*sigooin;
tti=wi1*sigin_oo;
*uui=wi2*sigooin;
uui=wi2*sigin_oo;
ddl11=ddl11+Et1*(-tti+dwi1*Hi)*E1;
ddl22=ddl22+Ft1*(Wmat1-( Hi@(uui-.5*dwi2*Hi) ) )*F1; *Wmati to Wmat1;
ddl12=ddl12+Et1*((-tti+.5*dwi1*Hi)@stdxit_o )*F1;
ddl21=ddl21+Ft1*((-uui+dwi2*Hi)@stdxi_o )*E1;
end; *1 to n1;
end; *elsedo;
*start from pattern 2;
snj=n1;
do j=2 to npat;
nj=misinfo[j,1]; pj=misinfo[j,2];
chipj=cinv(prob,pj);
ckj=sqrt(chipj);
cbetaj=( pj*probchi(chipj,pj+2)+ chipj*(1-prob) )/pj;
oj=misinfo[j,3:(2+pj)];
mu_o=mu0[oj];
sig_oo=sig0[oj,oj];
sigin_oo=inv(sig_oo);
run vec(sig_oo,vecsig_oo);
sigin_oo=inv(sig_oo);
Ej=i_p[oj,]; Etj=Ej;
Fj=(Ej@Ej)*dup; Ftj=Fj;
Wmati=0.5*(sigin_oo@sigin_oo);
do i=snj+1 to snj+nj;
xi=x[i,];
xi_o=xi[oj];
xi0_o=xi_o-mu_o;
xi0_ot=xi0_o;
stdxi_o=sigin_oo*xi0_o;
stdxit_o=stdxi_o;
di2=xi0_ot*stdxi_o;
di=sqrt(di2);
**Huber weight functions;
if di<=ckj then do;
wi1=1.0;
wi2=1.0/cbetaj;
dwi1=0;
dwi2=0;
end;
else do;
wi1=ckj/di;
wi2=wi1*wi1/cbetaj;
dwi1=wi1/di2;
dwi2=wi2/di2;
end;
*for computing B_{\beta};
dlimu=wi1*Etj*stdxi_o;
xixi0_o=xi0_o*xi0_ot;
run vec(xixi0_o,vecyi);
wvecyi=wi2*vecyi;
dlisig=Ftj*Wmati*(wvecyi-vecsig_oo);
B11=B11+dlimu*dlimu;
B12=B12+dlimu*dlisig;
B22=B22+dlisig*dlisig;
dl_i=dlimu//dlisig;
dl=dl+dl_i;

*for computing A_{\beta};
Hi=stdxi_o*stdxit_o;
tti=wi1*sigin_oo;
uui=wi2*sigin_oo;

ddl11=ddl11+Etj*(-tti+dwi1*Hi)*Ej;
ddl22=ddl22+Ftj*(Wmati-( Hi@(uui-.5*dwi2*Hi) ) )*Fj;
ddl12=ddl12+Etj*(( (-tti+0.5*dwi1*Hi)@stdxit_o ) )*Fj;
ddl21=ddl21+Ftj*((-uui+dwi2*Hi)@stdxi_o )*Ej;
end; *repeat cases within jth pattern;
snj=snj+nj;
end; *repeat pattern;

Bbeta=(B11||B12)//(B12||B22);

Abeta=(ddl11||ddl12)//(ddl21||ddl22);

Abin=inv(Abeta);
Omega=n*Abin*Bbeta*(Abin);
*Gamma=Omega[p+1:pps,p+1:pps];
gamma=Omega;
finish;
*-----------------------------------------------------------------------*;
*-----------------------------------------------------------------------*;
**creating index for vech(Sigma) corresponding to the selected variables;
*p=#all variables;
*ps=# selected variables;
*V_forana contains the selected subscripts;
start indexv(p,V_forana,index_s);
pv=nrow(V_forana);
pvs=pv*(pv+1)/2;
index_s=j(pvs,1,0);
count=p;
countv=0;
do i=1 to p;
do j=i to p;
count=count+1;

do iv=1 to pv;
do jv=iv to pv;

if i=V_forana[iv] then do;
if j=V_forana[jv] then do;
countv=countv+1;
index_s[countv]=count;
end;
end;
end;
end;
end;
end;
index_s=V_forana//index_s;
finish;

*-----------------------------------------------------------------------*;
*-----------------------------------------------------------------------*;
**creating index for vech(Sigma) corresponding to the selected variables;
*p=#all variables;
*ps=# selected variables;
*V_forana contains the selected subscripts;
start indexvc(p,V_forana,index_s);
pv=nrow(V_forana);
pvs=pv*(pv+1)/2;
index_s=j(pvs,1,0);
count=0;
countv=0;
do i=1 to p;
do j=i to p;
count=count+1;

do iv=1 to pv;
do jv=iv to pv;

if i=V_forana[iv] then do;
if j=V_forana[jv] then do;
countv=countv+1;
index_s[countv]=count;
end;
end;
end;
end;
end;
end;
index_s=index_s+j(pvs,1,p) ;
finish;

*-----------------------------------------------------------------------*;
**generating a permutation matrix from the order of vech(A) to the
vecs(A) as used by EQS;
***--------------------------------------------------------------------***;
start switch(p, permuc, permu);

ps=p*(p+1)/2;
bmat=j(p,p,0);
nb=0;
do i=1 to p;
do j=1 to i;
nb=nb+1;
bmat[i,j]=nb;
end;
end;
run vech(bmat,vb);

Imatc=i(ps);
permuc=Imatc[,vb];

Imat=i(p+ps);
vp=1:p;
vs=vp//( vb+j(ps,1,p) );
permu=imat[,vs];
permu=permu[(p+1):(p+ps),]//permu[1:p,]; *EQS puts the covariance first;

finish;

*-----------------------------------------------------------------------*;
*** The following is the main program;
use raw;
read all var _num_ into x;
close raw;
n=nrow(x); print "n=" n;
p=ncol(x);
V_forana={1, 2, 4, 5}; *need to be specified;
*V_forana={1, 2,3, 4, 5,6,7,8,9}; *need to be specified;
varphi=0.10; *need to be specified;
print "varphi=" varphi;
p_v=nrow(V_forana);
print p_v;
pvs=p_v+p_v*(p_v+1)/2;
run pattern(n,p,x,misinfo);
print x;
totpat=nrow(misinfo);

print "#total observed patterns="  totpat;
print "cases--#observed V--observed V--missing V=";
print misinfo;
run emmusig(x,misinfo,varphi,err,hmu1,hsigma1);
hmu=hmu1[V_forana];
hsigma=hsigma1[V_forana,V_forana];
print "hat\mu=";
print hmu;
print "hat\Sigma=";
print hsigma;
run Ascov(varphi,hmu1,hsigma1,x,misinfo, Abeta, Bbeta, hupsilon);

run indexv(p,V_forana,index_beta); *index for both means and covariances;
run indexvc(p,V_forana,index_sig); *index for only the covariances;
run switch(p_v, permu_sig, permu_beta); *generating permutation matrices;
print index_beta;

hgamma_sig=hupsilon[index_sig,index_sig];
hgamma_sig=permu_sig*hgamma_sig*permu_sig;*needed for the 2nd stage ML in EQS;
print "\hat\Gamma_sig=";
print hgamma_sig;

hgamma_beta=hupsilon[index_beta,index_beta];
hgamma_beta=( permu_beta*hgamma_beta*permu_beta||j(pvs,1,0) )//(j(1,pvs,0)||1);*needed for the 2nd stage ML in EQS;
print "hat\Gamma_beta=";
print hgamma_beta;
`