Appendix V: the SAS Macro Bismm

Total Page:16

File Type:pdf, Size:1020Kb

Appendix V: the SAS Macro Bismm

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

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] +(1-r)#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[,(j- ncol(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#(1- mrpred)#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;

Recommended publications