SAS macro

advertisement
Appendix V: The SAS Macro bismm
/*BISMM function by using Interactive Matrix Language (IML) */
/*Converted from R by Bing Cai*/
/*Modified, 01/30/2011, by Daohang Sha */
/*Last modified: go through TTH comments, 02/14/2011, by Daohang Sha */
/*08/31/2011, cleaned up from bismm_no_excl_restrict1.sas by Daohang Sha*/
/*09/02/2011, added notes for multiple baseline covariates, Daohang Sha*/
/*#############################################################################/*
/*# Bing Cai */
/*# Modify the R program from Vansteelandt and Goetghebeur*/
/*# to fit the situation that the placebo group patients have access to the treatment*/
/*#*/
/*# 1. Have two association model separately for R=1 and R=0.*/
/*# 2. Modify the H(r)*/
/*# 3. Iteration method for the selection of d and q*/
/*# 4. Modify the program for variance estimate accordingly*/
/*#
/*##################################################################################*
/
/*################################################################################*/
/*#y: outcome variable;*/
/*#z1: covariate(compliance) in structural model;
*/
/*#z2: covariate(compliance) in associational model;
make sure that z1 is included lastly !!! */
/*#x: baseline covariates;*/
/*#w: weight to adjust for lost to followup;*/
/*#r: randomization indicator (1: active, 0: experimental);*/
/*#family: select error distribution and link function, eg. family=binomial(link=probit);*/
/*#psi: starting value for structural parameter, eg psi <- rep(0, ncol(Compliance));*/
/*#print:
if TRUE structural parameter value in every iteration is printed;*/
/*#tol: tolerance for convergence criterion;*/
/*#robust: if TRUE robust weights are used;*/
/*#prest: estimate probability of being randomized to experimental arm (F: set this probability equal to
0.5);*/
/*#D: weight functions for structural equations (if NULL, optimal weights are estimated);*/
/*#maxiter:
maximum number of allowed iterations;*/
/*#########################################################################*/
/*Before invoking %bismm(), %pre_bismm(data) must be invoked first. */
/*This step prepares the data sets being used in %bismm()*/
/*Input data must include the following variables: yobs r x z */
/*For the meanings of these variables please see notes above by Bing Cai*/
/*Output data of macro %bismm() is "out1"*/
/*02/01/2011, Daohang Sha*/
/*########################################################################*/
/*For multiple baseline covariates if they are labeled as x1, x2, x3, ...*/
/*Two things need to do,*/
/* 1) replace variable x in all proc genmod within %macro pre_bismm() with x1 x2 x3 ... */
/* 2) combine all covariates together by adding x=x1||x2||x3; right after */
/* ... */
/*
use arg; */
/*
read all var _all_; */
/* within proc iml in %macro bismm() */
/*09/02/2011, DS*/
%macro pre_bismm(indat);
/*add id variable to the data set*/
data data;
set &indat.;
id=_N_;
/*
drop var1;*/
keep yobs x z r id;
run;
data R1;
set data;
if R=0 then yobs=.;
run;
data R0;
set data;
if R=1 then yobs=.;
run;
/* # Build association model 1: [R=1]*/
proc genmod data=R1 descending;
ods output Genmod.ParameterEstimates=m2t_coef(keep=Parameter Estimate);
class z(ref=first)/param=ref;
model yobs = x z /dist=binomial link=logit;
output out=m2t PREDICTED=pyR1 RESRAW =helput;
ods exclude
ModelInfo
NObs
ResponseProfile
ClassLevels
ModelFit
ConvergenceStatus
ParameterEstimates
;
run;
/*set residual as 0 when R=0*/
data m2t;
set m2t;
if r=0 then helput = 0;
run;
/*get coefficient of model 1*/
data m2t_coef;
set m2t_coef;
if Parameter ne "Scale";
rename Estimate=m2t_coef;
drop Parameter;
run;
/* # Build association model 2 [R=0]*/
proc genmod data=R0 descending;
ods output Genmod.ParameterEstimates=m2p_coef(keep=Parameter Estimate);
class z(ref=first)/param=ref;
model yobs = x z /dist=binomial link=logit;
output out=m2p PREDICTED=pyR0 RESRAW =helpup;
ods exclude
ModelInfo
NObs
ResponseProfile
ClassLevels
ModelFit
ConvergenceStatus
ParameterEstimates
;
run;
/*set residual as 0 when R=1*/
data m2p;
set m2p;
if r=1 then helpup = 0;
run;
/*get coefficient of model 2*/
data m2p_coef;
set m2p_coef;
if Parameter ne "Scale";
rename Estimate=m2p_coef;
drop Parameter;
run;
/* # A model to predict treatment group*/
proc genmod data=data descending;
model r = x/dist=binomial link=logit;
output out=mr PREDICTED=mrpred resraw=r_res;
ods exclude
ModelInfo
NObs
ResponseProfile
ClassLevels
ModelFit
ConvergenceStatus
ParameterEstimates
;
run;
/*put model 1 and 2 together*/
data m2tp;
update m2t m2p;
by id;
run;
data m2tpr;
merge m2tp mr(keep=id mrpred r_res);
by id;
run;
proc datasets;
delete data m2p m2t m2tp mr r0 r1 pZR1 pZR0;
quit;
%mend;
%macro bismm(indat=ds, w=1, psi=., print="F", tol=1e-10, robust="F",prest="T", D="", maxiter=600);
/*prepare the data for estimation*/
%pre_bismm(&indat.)
/*save arguments to a data set so IML can read in*/
data arg;
w=&w.;
psi=&psi.; *one parameter;
print=&print.;
tol=&tol.;
robust=&robust.;
prest=&prest.;
D=&D.;
maxiter=&maxiter.;
run;
/*start BISMM iteration estimation */
proc iml;
/*get initial arguments*/
use arg;
read all var _all_;
/*for multiple baseline covariates labeled as x1, x2, and x3, DS, 09/02/2011*/
/*
x=x1||x2||x3; */
/*read data set*/
use m2tpr;
read all var _all_;
y=yobs;
z1=z; * one parameter;
z2=x||z;
use m2t_coef;
read all var {m2t_coef};
use m2p_coef;
read all var {m2p_coef};
/*
# Function used for estimation with robust weights*/
/*
### add in intercept for z2 and x*/
ones=repeat(1,nrow(y),1);
z2=ones||z2;
x=ones||x;
/*one parameter*/
if psi=. then psi=repeat(0,ncol(z1),1);
psiold=psi;
/*
/*
/*
/*
/*
######################### */
# Estimation*/
#########################*/
###initiate q */
q=0;
# Fit structural model*/
do i=1 to maxiter by 1;
temp1 = z2*m2t_coef - z1*psi;
temp2 = z2*m2p_coef - z1*psi;
YP=r/(1+exp(-temp1)) + (1-r)/(1+exp(-temp2));
dYPdPSI = - r#exp(temp1)/((1+exp(temp1))#(1+exp(temp1)))#z1
+ (1-r)#exp(temp2)/((1+exp(temp2))#(1+exp(temp2)))#z1;
YPNew = YP - dYPdPSI*psi;
/*
# Calculating weight matrix */
b=inv(x`*x)*x`*dYPdPSI;
zpred=x*b;
q= x*inv(x`*x)*x`*YP;
if prest="T" then do;
g = ((-1)##r) # zpred/(r#mrpred+(1-r)#(1-mrpred));
end;
else do;
g = ((-1)##r) # zpred;
end;
if (D ^= "") then
do;
g = D;
end;
gw = g # w;
gzinv= inv(t(gw)*dYPdPSI);
psi = gzinv*t(gw)*(q - YPNew);
/*
/*
if (print="T") then */
print psi,psiold;*/
/*
if (robust)
*/
/*
{*/
/*
if (ncol(z2)==ncol(g)) */
/*
m2$coef<-nlm(f=glmrob, p=coef(m2), y=y, z2=z2, d=rbind(t(g)), r=r)$estimate */
/*
else */
/*
m2$coef<-nlm(f=glmrob, p=coef(m2), y=y, z2=z2,
d=rbind(t(z2[,(1+ncol((g))):ncol(z2)]),t(g)), r=r)$estimate*/
/*
}*/
YP=r/(1+exp(-temp1)) + (1-r)/(1+exp(-temp2));
dYPdPSI=-r#exp(temp1)/((1+exp(temp1))#(1+exp(temp1)))#z1
+(1-r)#exp(temp2)/((1+exp(temp2))#(1+exp(temp2)))#z1;
YPNew = YP - dYPdPSI*psi;
q= x*inv(x`*x)*x`*YP;
b=inv(x`*x)*x`*dYPdPSI;
zpred=x*b;
if prest="T" then do;
g = ((-1)##r) # zpred/(r#mrpred+(1-r)#(1-mrpred));
end;
else do;
g = ((-1)##r) # zpred;
end;
if (D ^= "") then
do;
g = D;
end;
gw = g # w ;
gzinv= inv(t(gw)*dYPdPSI);
psi = (psi + gzinv*t(gw)*(q - YPNew))/2;
/*print iteration infomation*/
if (print="T") then do;
iter_val=i||psi`;
iter_char=char(iter_val,15,10); * convert matrix numerical element to char;
col={"Iteration(i)" "psi"};
iterinfo=col//iter_char;
print iterinfo;
end;
tol1=t(psi-psiold)*(psi-psiold);
if tol1<tol then stop;
else psiold =psi;
end; *end of i do loop;
create psi var {i,psi};
append;
close psi;
/*
print final estamation infomation*/
if (i>=maxiter+1) then do;
i=i-1;
print "WARNNING: Parameter values did not converge!";
print "iteration=" i "; Total tolerance =" tol1 ">=" tol;
print "Try to increase the number of max iteration: maxiter";
end;
else print "Parameter values converged." "iteration=" i "; Total tolerance =" tol1 "<" tol;
/* ### End OF Estimation ### */
/*
/*
/*
############################ */
# CALCULATING THE VARIANCE # */
############################ */
/*
#Estimated psi*/
/*
#ds (INCORPORATE WEIGHT TO ADJUST FOR LOST TO FOLLOWUP)*/
d=t(g);
dw=t(g*w);
/*
# Build association model*/
if (robust^="T") then drob=z2;
else do;
if (ncol(z2)=nrow(d)) then drob=t(d);
else drob=z2[,(1+ncol(t(d))):ncol(z2)]||t(d);
end;
/*
# Build treatment assignment model*/
u=shape(.,nrow(y),ncol(z1)+2*ncol(z2)+ncol(x));
du=shape(.,ncol(z1)+2*ncol(z2)+ncol(x),ncol(z1)+2*ncol(z2)+ncol(x));
h = r#(exp(temp1)/(1+exp(temp1))) + (1-r)#(exp(temp2)/(1+exp(temp2)));
/*
### U matrix*/
do i=1 to ncol(z1) by 1;
do j=1 to nrow(z1);
u[j,i]=dw[i,j]#(h[j]-q[j]);
end;
end;
do i=(ncol(z1)+1) to (ncol(z1)+ncol(z2));
do j=1 to nrow(z1);
u[j,i]=helput[j]#drob[j,(i-ncol(z1))];
end;
end;
/*
### Placebo group association part */
do i=(ncol(z1)+ncol(z2)+1) to (ncol(z1)+2*ncol(z2));
do j=1 to nrow(z1);
u[j,i]=helpup[j]#drob[j,(i-ncol(z1)-ncol(z2))];
end;
end;
/*
# treatment assignment part */
do i=(ncol(z1)+2*ncol(z2)+1) to (ncol(z1)+2*ncol(z2)+ncol(x));
do j=1 to nrow(z1);
u[j,i]=r_res[j]#x[j,(i-ncol(z1)-2*ncol(z2))];
end;
end;
/*
/*
### dU matrix*/
# structual part (INCORPORATE WEIGHT TO ADJUST FOR LOST TO FOLLOWUP) */
do i=1 to ncol(z1);
do j=1 to ncol(z1);
du[i,j]=-sum(r#exp(temp1)/((1+exp(temp1))#(1+exp(temp1)))#dw[i,]`#z1[,j]
+(1r)#exp(temp2)/((1+exp(temp2))#(1+exp(temp2)))#dw[i,]`#z1[,j])/nrow(y);
end;
do j=(ncol(z1)+1) to (ncol(z1)+ncol(z2));
du[i,j]=sum(r#exp(temp1)/((1+exp(temp1))#(1+exp(temp1)))#dw[i,]`#z2[,(jncol(z1))])/nrow(y);
end;
do j=(ncol(z1)+ncol(z2)+1) to (ncol(z1)+2*ncol(z2));
du[i,j]=sum((1-r)#exp(temp2)/((1+exp(temp2))#(1+exp(temp2)))#dw[i,]`#z2[,(j-ncol(z1)ncol(z2))])/nrow(y);
end;
do j=(ncol(z1)+2*ncol(z2)+1) to (ncol(z1)+2*ncol(z2)+ncol(x));
du[i,j]=-sum((dw[i,]`/(r#(1-mrpred)+(1-r)#mrpred)##2)#(h-q)#(2*r-1)#mrpred#(1mrpred)#x[,(j-ncol(z1)-2*ncol(z2))])/nrow(y);
end;
end;
/*
# association part */
do i=(1+ncol(z1)) to (ncol(z1)+ncol(z2));
do j=1 to ncol(z1);
du[i,j]=0;
end;
do j=(1+ncol(z1)) to (ncol(z1)+ncol(z2));
du[i,j]=-sum(pyR1#(1-pyR1)#r#drob[,(i-ncol(z1))]#z2[,(j-ncol(z1))])/nrow(y)*2;
end;
do j=(1+ncol(z1)+ncol(z2)) to (ncol(z1)+2*ncol(z2));
du[i,j]=0;
end;
do j=(1+ncol(z1)+2*ncol(z2)) to (ncol(z1)+2*ncol(z2)+ncol(x));
du[i,j]=0;
end;
end;
do i=(1+ncol(z1)+ncol(z2)) to (ncol(z1)+2*ncol(z2));
do j=1 to (ncol(z1)+ncol(z2));
du[i,j]=0;
end;
do j=(1+ncol(z1)+ncol(z2)) to (ncol(z1)+2*ncol(z2));
du[i,j]=-sum(pyR0#(1-pyR0)#r#drob[,(i-ncol(z1)-ncol(z2))]#z2[,(j-ncol(z1)-ncol(z2))])/nrow(y)*2;
end;
do j=(1+ncol(z1)+2*ncol(z2)) to (ncol(z1)+2*ncol(z2)+ncol(x));
du[i,j]=0;
end;
end;
/*
# treatment assignment part */
do i=(1+ncol(z1)+2*ncol(z2)) to (ncol(z1)+2*ncol(z2)+ncol(x));
do j=1 to ncol(z1);
du[i,j]=0;
end;
do j=(1+ncol(z1)) to (ncol(z1)+2*ncol(z2));
du[i,j]=0;
end;
do j=(1+ncol(z1)+2*ncol(z2)) to (ncol(z1)+2*ncol(z2)+ncol(x));
du[i,j]=-sum(mrpred#(1-mrpred)#x[,(j-ncol(z1)-2*ncol(z2))]#x[,(i-ncol(z1)-2*ncol(z2))])/nrow(y);
end;
end;
if prest="T" then
do;
idu=inv(du);
end;
else do;
idu=inv(du[1:(ncol(z1)+ncol(z2)),1:(ncol(z1)+ncol(z2))]);
u=u[,1:(ncol(z1)+ncol(z2))];
end;
/*
# variance matrix*/
vari=idu*(u`*u)*idu`/nrow(y)**2;
if (print="T") then do;
print "rvariance:", vari;
end;
/*print model m2t outputs*/
/*
/*
/*
# Print association model1*/
# cat("\n Association model1: \n\n")*/
# Print structural model*/
covmat=
vari[1:nrow(psi),1:nrow(psi)];
var_cf=diag(covmat);
/* TTH: need to account for two element vectors psi, s_err, zvalue, pvalue, lowlimit, uplimit */
ones=repeat(1,ncol(var_cf),1);
var=var_cf*ones;
s_err=sqrt(var);
zvalue=psi/s_err;
pvalue=2*(1-cdf("normal",abs(zvalue)));
lowlimit=psi-1.96*s_err;
uplimit=psi+1.96*s_err;
/*prepare for print out */
if (print="T") then do;
val=psi||var||s_err||lowlimit||uplimit||pvalue; print val;
cha=char(val,8,5); * convert matrix numerical element to char;
col={"psi" "var" "SE" "LowerCI" "UpperCI" "p value"};
paraEstimate=col//cha;
print paraEstimate;
end;
create out1 var {psi, var, lowlimit, uplimit};
append;
/*
show contents;*/
close out1;
quit;
%mend;
Download