The whas500 data set is used in this chapter. We will also use a macro written to perform a score test for proportional hazards (phreg_score_test). Please download this file, read it over, convert it to a SAS program, and create a filename for it. This will allow us to use %include when we wish to invoke the macro. Then run the %include statement before continuing with the examples.
filename ph_score "C:phreg_score_test.sas"; %include ph_score;
Table 6.1 on page 180 using the whas500 data.
data whas500; set whas500; bmifp1=(bmi/10)**2; bmifp2=(bmi/10)**3; ga = gender*age; time = lenfol/365.25; run;
%phreg_score_test(lenfol, fstat, bmifp1 bmifp2 age hr diasbp gender chf ga, data=whas500);
Score test of proportional hazards assumption
Time variable: lenfol
                     Rho   Chi-Square           df      P-value
bmifp1             0.083        1.658        1.000        0.198
bmifp2            -0.072        1.242        1.000        0.265
AGE                0.083        1.407        1.000        0.236
HR                 0.019        0.081        1.000        0.777
DIASBP             0.000        0.000        1.000        0.997
GENDER             0.034        0.232        1.000        0.630
CHF               -0.044        0.441        1.000        0.507
ga                -0.030        0.179        1.000        0.672
Global test         .           3.655        8.000        0.887
%phreg_score_test(lenfol, fstat, bmifp1 bmifp2 age hr diasbp gender chf ga, 
                  data=whas500, type="logtime");
Score test of proportional hazards assumption
Time variable: LOG(lenfol)
                     Rho   Chi-Square           df      P-value
bmifp1             0.007        0.012        1.000        0.914
bmifp2             0.004        0.003        1.000        0.957
AGE                0.146        4.295        1.000        0.038
HR                 0.068        1.032        1.000        0.310
DIASBP             0.047        0.530        1.000        0.467
GENDER             0.101        2.046        1.000        0.153
CHF                0.038        0.333        1.000        0.564
ga                -0.105        2.240        1.000        0.134
Global test         .           7.470        8.000        0.487
%phreg_score_test(lenfol, fstat, bmifp1 bmifp2 age hr diasbp gender chf ga, 
                  data=whas500, type="km");
Score test of proportional hazards assumption
Time variable: KM(lenfol)
                     Rho   Chi-Square           df      P-value
bmifp1             0.038        0.350        1.000        0.554
bmifp2            -0.028        0.181        1.000        0.671
AGE                0.128        3.291        1.000        0.070
HR                 0.051        0.567        1.000        0.452
DIASBP             0.038        0.348        1.000        0.555
GENDER             0.081        1.317        1.000        0.251
CHF                0.011        0.026        1.000        0.873
ga                -0.082        1.352        1.000        0.245
Global test         .           5.102        8.000        0.747
%phreg_score_test(lenfol, fstat, bmifp1 bmifp2 age hr diasbp gender chf ga, 
                  data=whas500, type="rank");
Score test of proportional hazards assumption
Time variable: RANK(lenfol)
                     Rho   Chi-Square           df      P-value
bmifp1             0.027        0.171        1.000        0.679
bmifp2            -0.015        0.056        1.000        0.814
AGE                0.138        3.864        1.000        0.049
HR                 0.064        0.911        1.000        0.340
DIASBP             0.041        0.408        1.000        0.523
GENDER             0.091        1.646        1.000        0.199
CHF                0.020        0.088        1.000        0.767
ga                -0.093        1.725        1.000        0.189
Global test         .           6.358        8.000        0.607
Figure 6.1 on page 181 using the whas500 data.
proc sql noprint;
  select sum(fstat) into :total
  from whas500;
quit;
proc phreg data = whas500 outest=est61 covout;
model time*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga;
id id;
output out=t61 ressch = bmifp1_r bmifp2_r age_r hr_r diasbp_r gender_r chf_r ga_r;
run;
proc means data = t61;
var bmifp1_r bmifp2_r age_r hr_r diasbp_r gender_r chf_r ga_r;
run;
ods output ProductLimitEstimates=d61;
proc lifetest data = t61;
time time*fstat(0);
id bmifp1_r bmifp2_r age_r hr_r diasbp_r gender_r chf_r ga_r;
run;
data d61_a;
  set d61;
  if censor = 0;
  logtime = log(time);
run;
proc iml;
  use d61_a;
  read all variables {bmifp1_r bmifp2_r age_r hr_r diasbp_r gender_r chf_r ga_r} into L;
  read all variables {time logtime survival censor } into X;
  use est61;
  read all  var {bmifp1 bmifp2 age hr diasbp gender chf ga} into V
      where (_type_ = "COV");
  ssr =  (&total)*L*V;
  W = X || ssr;
  create fig61_b var {time logtime survival censor  sbmifp1_r sbmifp2_r sage_r shr_r sdiasbp_r sgender_r schf_r sga_r};
  append from W;
quit;
***EMPTY GRAPHICS CATALOG;
proc greplay nofs igout=gseg;
delete _all_;
run;
quit;
* figure 6.1 (a);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.1 to .15 by .05) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(-6 to 2 by 2) label=('Log Time') minor=none;
title 'Figure 6.1a';
proc gplot data = fig61_b;
plot shr_r*logtime / vaxis = axis1 haxis = axis2 name = "fig61a" noframe;
run;
quit;
* figure 6.1 (b);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.1 to .15 by .05) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 8 by 2) label=('Time') minor=none;
title 'Figure 6.1b';
proc gplot data = fig61_b;
plot shr_r*time / vaxis = axis1 haxis = axis2 name = "fig61b" noframe;
run;
quit;
* figure 6.1 (c);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.1 to .15 by .05) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 1 by .2) label=('Kaplan-Meier Estimate') minor=none;
title 'Figure 6.1c';
proc gplot data = fig61_b;
plot shr_r*survival / vaxis = axis1 haxis = axis2 name = "fig61c" noframe;
run;
quit;
* figure 6.1 (d);
proc rank data = fig61_b out=fig61_b_ranked;
var time;
run;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.1 to .15 by .05) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 250 by 50) label=('Rank of Time') minor=none;
title 'Figure 6.1d';
proc gplot data = fig61_b_ranked;
plot shr_r*time / vaxis = axis1 haxis = axis2 name = "fig61d" noframe;
run;
quit;
title;
goptions reset=all;
proc greplay igout=work.gseg tc=sashelp.templt template=l2r2 nofs;
treplay 1:fig61a 2:fig61c 3:fig61b 4:fig61d;
run;
quit;

Figure 6.2 on page 182 using the whas500 data modified in the previous example.
***EMPTY GRAPHICS CATALOG;
proc greplay nofs igout=gseg;
delete _all_;
run;
quit;
* figure 6.2 (a);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-4 to 6 by 2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(-6 to 2 by 2) label=('Log Time') minor=none;
title 'Figure 6.2a';
proc gplot data = fig61_b;
plot schf_r*logtime / vaxis = axis1 haxis = axis2 name = "fig62a" noframe;
run;
quit;
* figure 6.2 (b) htext = 2 htitle = 3;
goptions reset=all; 
symbol v = dot;
axis1 order=(-4 to 6 by 2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 8 by 2) label=('Time') minor=none;
title 'Figure 6.2b';
proc gplot data = fig61_b;
plot schf_r*time / vaxis = axis1 haxis = axis2 name = "fig62b" noframe;
run;
quit;
* figure 6.2 (c) htext = 2 htitle = 3;
goptions reset=all; 
symbol v = dot;
axis1 order=(-4 to 6 by 2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 1 by .2) label=('Kaplan-Meier Estimate') minor=none;
title 'Figure 6.2c';
proc gplot data = fig61_b;
plot schf_r*survival / vaxis = axis1 haxis = axis2 name = "fig62c" noframe;
run;
quit;
* figure 6.2 (d);
proc rank data = fig61_b out=fig61_b_ranked;
var time;
run;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-4 to 6 by 2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 250 by 50) label=('Rank of Time') minor=none;
title 'Figure 6.2d';
proc gplot data = fig61_b_ranked;
plot schf_r*time / vaxis = axis1 haxis = axis2 name = "fig62d" noframe;
run;
quit;
title;
goptions reset=all;
proc greplay igout=work.gseg tc=sashelp.templt template=l2r2 nofs;
treplay 1:fig62a 2:fig62c 3:fig62b 4:fig62d;
run;
quit;

Figure 6.3 on page 183 using the whas500 data modified in a previous example.
***EMPTY GRAPHICS CATALOG;
proc greplay nofs igout=gseg;
delete _all_;
run;
quit;
* figure 6.3 (a);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.6 to .4 by .2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(-6 to 2 by 2) label=('Log Time') minor=none;
title 'Figure 6.3a';
proc gplot data = fig61_b;
plot sage_r*logtime / vaxis = axis1 haxis = axis2 name = "fig63a" noframe;
run;
quit;
* figure 6.3 (b);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.4 to .4 by .2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 8 by 2) label=('Time') minor=none;
title 'Figure 6.3b';
proc gplot data = fig61_b;
plot sage_r*time / vaxis = axis1 haxis = axis2 name = "fig63b" noframe;
run;
quit;
* figure 6.3 (c);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.4 to .4 by .2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 1 by .2) label=('Kaplan-Meier Estimate') minor=none;
title 'Figure 6.3c';
proc gplot data = fig61_b;
plot sage_r*survival / vaxis = axis1 haxis = axis2 name = "fig63c" noframe;
run;
quit;
* figure 6.3 (d);
proc rank data = fig61_b out=fig61_b_ranked;
var time;
run;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.4 to .4 by .2) label=(a=90 'Scaled Schonefeld Residuals') minor=none;
axis2 order=(0 to 250 by 50) label=('Rank of Time') minor=none;
title 'Figure 6.3d';
proc gplot data = fig61_b_ranked;
plot sage_r*time / vaxis = axis1 haxis = axis2 name = "fig63d" noframe;
run;
quit;
title;
goptions reset=all;
proc greplay igout=work.gseg tc=sashelp.templt template=l2r2 nofs;
treplay 1:fig63a 2:fig63c 3:fig63b 4:fig63d;
run;
quit;

Figure 6.4 on page 186 using the whas500 data.
proc phreg data = whas500 ;
model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga;
id id;
output out=f64 ressco = bmifp1_r bmifp2_r age_r hr_r diasbp_r gender_r chf_r ga_r;
run;
proc sort data = whas500;
by id;
run;
proc sort data = f64;
by id;
run;
data f64m;
merge whas500 f64;
by id;
run;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-10 to 20 by 5) label=(a=90 'Score Residuals') minor=none;
axis2 order=(10 to 50 by 10) label=('Body Mass Index (kg/m^2)') minor=none;
title 'Figure 6.4a';
proc gplot data = f64m;
plot bmifp1_r*bmi / vaxis = axis1 haxis = axis2 name = "f64a" noframe;
run;
quit;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-40 to 60 by 20) label=(a=90 'Score Residuals') minor=none;
axis2 order=(10 to 50 by 10) label=('Body Mass Index (kg/m^2)') minor=none;
title 'Figure 6.4b';
proc gplot data = f64m;
plot bmifp2_r*bmi / vaxis = axis1 haxis = axis2 name = "f64b" noframe;
run;
quit;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-100 to 150 by 50) label=(a=90 'Score Residuals') minor=none;
axis2 order=(0 to 200 by 50) label=('Heart Rate (Beats/Min)') minor=none;
title 'Figure 6.4c';
proc gplot data = f64;
plot hr_r*hr / vaxis = axis1 haxis = axis2 name = "f64c" noframe;
run;
quit;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-100 to 150 by 50) label=(a=90 'Score Residuals') minor=none;
axis2 order=(0 to 200 by 50) label=('Diastolic Blood Pressure (mmHg)') minor=none;
title 'Figure 6.4d';
proc gplot data = f64;
plot diasbp_r*diasbp / vaxis = axis1 haxis = axis2 name = "f64d" noframe;
run;
quit;
goptions reset=all;
proc greplay igout=work.gseg tc=sashelp.templt template=l2r2 nofs;
treplay 1:f64a 2:f64c 3:f64b 4:f64d;
run;
quit;

Figure 6.5 on page 186 using the whas500 data as modified in the previous example.
***EMPTY GRAPHICS CATALOG;
proc greplay nofs igout=gseg;
delete _all_;
run;
quit;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-80 to 20 by 20) label=(a=90 'Score Residuals') minor=none;
axis2 order=(20 to 100 by 20) label=('Age (Years)') minor=none;
title 'Figure 6.5a';
proc gplot data = f64;
plot age_r*age / vaxis = axis1 haxis = axis2 name = "f65a" noframe;
run;
quit;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-200 to 200 by 100) label=(a=90 'Score Residuals') minor=none;
axis2 order=(20 to 100 by 20) label=('Age (Years)') minor=none;
title 'Figure 6.5b';
proc gplot data = f64;
plot ga_r*age / vaxis = axis1 haxis = axis2 name = "f65b" noframe;
run;
quit;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-3 to 2 by 1) label=(a=90 'Score Residuals') minor=none;
axis2 offset=(4 cm, 4 cm) value=('No' 'Yes') order=(0 1) label=('Congestive Heart Complications') minor=none;
title 'Figure 6.5c';
proc gplot data = f64;
plot chf_r*chf / vaxis = axis1 haxis = axis2 name = "f65c" noframe;
run;
quit;
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-2 to 2 by 1) label=(a=90 'Score Residuals') minor=none;
axis2 offset=(4 cm, 4 cm) value=('Male' 'Female') order=(0 1) label=('Gender') minor=none;
title 'Figure 6.5d';
proc gplot data = f64;
plot gender_r*gender / vaxis = axis1 haxis = axis2 name = "f65d" noframe;
run;
quit;
goptions reset=all;
proc greplay igout=work.gseg tc=sashelp.templt template=l2r2 nofs;
treplay 1:f65a 2:f65c 3:f65b 4:f65d;
run;
quit;

Figure 6.6 on page 187 using the whas500 data.
* requires scaled score residuals which you can get from SAS with the dfbeta option on the output statement;
proc phreg data = whas500;
model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga;
id id;
output out=fig66 resmart = mgale dfbeta = ssbmifp1_r ssbmifp2_r ssage_r sshr_r ssdiasbp_r ssgender_r sschf_r ssga_r;
run;
***EMPTY GRAPHICS CATALOG;
proc greplay nofs igout=gseg;
delete _all_;
run;
quit;
goptions reset = all htext = 2 htitle = 3;
data bmi;
set fig66;
bmi = sqrt(bmifp1)*10;
run;
* f6.6(a);
goptions reset=all; 
symbol v = dot;
axis1 order=(-.1 to .1 by .05) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 order=(10 to 50 by 10) label=('Body Mass Index (kg/m^2)') minor=none;
title 'Figure 6.6a';
proc gplot data = bmi;
plot ssbmifp1_r*bmi / vaxis = axis1 haxis = axis2 name = "f66a" noframe;
run;
quit;
* f6.6(b);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.02 to .02 by .01) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 order=(10 to 50 by 10) label=('Body Mass Index (kg/m^2)') minor=none;
title 'Figure 6.6b';
proc gplot data = bmi;
plot ssbmifp2_r*bmi / vaxis = axis1 haxis = axis2 name = "f66b" noframe;
run;
quit;
* f6.6(c);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.0008 to .0006 by .0002) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 order=(0 to 200 by 50) label=('Heart Rate (Beats/Min)') minor=none;
title 'Figure 6.6c';
proc gplot data = bmi;
plot sshr_r*hr / vaxis = axis1 haxis = axis2 name = "f66c" noframe;
run;
quit;
* f6.6(d);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.001 to .0015 by .0005) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 order=(0 to 200 by 50) label=('Diastolic Blood Pressure (mmHg)') minor=none;
title 'Figure 6.6d';
proc gplot data = bmi;
plot ssdiasbp_r*diasbp / vaxis = axis1 haxis = axis2 name = "f66d" noframe;
run;
quit;
title;
goptions reset=all;
proc greplay igout=work.gseg tc=sashelp.templt template=l2r2 nofs;
treplay 1:f66a 2:f66c 3:f66b 4:f66d;
run;
quit;

Figure 6.7 on page 188 using the whas500 data as modified in the previous example.
***EMPTY GRAPHICS CATALOG;
proc greplay nofs igout=gseg;
delete _all_;
run;
quit;
* f6.7(a);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.003 to .001 by .001) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 order=(20 to 120 by 20) label=('Age (Years)') minor=none;
title 'Figure 6.7a';
proc gplot data = bmi;
plot ssage_r*age / vaxis = axis1 haxis = axis2 name = "f67a" noframe;
run;
quit;
* f6.7(b);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.004 to .004 by .002) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 order=(20 to 120 by 20) label=('Age (Years)') minor=none;
title 'Figure 6.7b';
proc gplot data = bmi;
plot ssga_r*age / vaxis = axis1 haxis = axis2 name = "f67b" noframe;
run;
quit;
* f6.7(c);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.04 to .04 by .02) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 offset=(4 cm, 4 cm) value=('No' 'Yes') order=(0 1) label=('Congestive Heart Complications') minor=none;
title 'Figure 6.7c';
proc gplot data = bmi;
plot sschf_r*chf / vaxis = axis1 haxis = axis2 name = "f67c" noframe;
run;
quit;
* f6.7(d);
goptions reset=all htext = 2 htitle = 3; 
symbol v = dot;
axis1 order=(-.2 to .3 by .1) label=(a=90 'Scaled Score Residuals') minor=none;
axis2 offset=(4 cm, 4 cm) value=('Male' 'Female') order=(0 1) label=('Gender') minor=none;
title 'Figure 6.7d';
proc gplot data = bmi;
plot ssgender_r*gender / vaxis = axis1 haxis = axis2 name = "f67d" noframe;
run;
quit;
goptions reset=all;
proc greplay igout=work.gseg tc=sashelp.templt template=l2r2 nofs;
treplay 1:f67a 2:f67c 3:f67b 4:f67d;
run;
quit;

Figure 6.8 on page 190 using the whas500 dataset. We are presenting this example before Table 6.2 on the previous page because the results of this graph are used in selecting the observations of interest in the table.
proc phreg data = whas500;
model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga;
output out=f68 resmart = martres ld = ld;
run;
goptions reset=all; 
symbol v = dot;
axis1 order=(0 to .8 by .2) label=(a=90 'Likelihood Dispacement') minor=none;
axis2 order=(-4 to 1 by 1) label=('Martingale Residuals') minor=none;
proc gplot data = f68;
plot ld*martres / vaxis = axis1 haxis = axis2;
run;
quit;

Table 6.2 on page 189 using the modified versions of whas500 used in creating Figures 6.4-6.8. To determine which IDs to include in the table, we will identify those observations highlighted as outliers in Figures 6.4-6.8.
* Listing of subjects identified in Figure 6.4 and 6.5;
data t62a; set f64m;
keep id;  
if (bmi < 20 & bmifp1_r>8) or 
 (bmi < 20 & bmifp2_r>20) or
 (hr_r>90) or
 (diasbp_r>100) or 
 (age>80 & age_r<-50) or 
 (age>80 & ga_r<-150) or 
 (chf=0 & chf_r>1.5) or
 (chf=1 & chf_r<-1.5) or
 (gender=0 & gender_r>1.5) or 
 (gender=1 & gender_r<-1.5);
run;
* Listing of subjects identified in Figure 6.6 and 6.7; 
data t62b; set bmi;
keep id;  
if (bmi < 20 & ssbmifp1_r >0.05) or 
 (bmi < 20 & ssbmifp2_r <-0.01) or
 (bmi > 41 & ssbmifp2_r >0.01) or
 (hr > 170) or 
 (diasbp > 190) or
 (age > 85 & ssage_r <-0.002) or
 (age < 40 & ssga_r <-.002) or
 (age > 70 & ssga_r >0.002) or
 (chf=1 & sschf_r<-0.03) or
 (gender=0 & ssgender_r<-.15);
run;
* Listing of subjects identified in Figure 6.8; 
data t62c; set f68;
keep id;  
if (martres<-3 & ld>.2);
run;
data ids; set t62a t62b t62c; 
run;
proc sort data = ids; 
by id; 
run;
data ids62; set ids;
by id;
if first.id;
run;
proc print data = ids62 noobs; 
run;
 ID
 51
 89
112
115
153
194
251
256
416
472
proc format;
value genderfmt
0 = "Male"
1 = "Female";
value chffmt
0 = "No"
1 = "Yes";
run;
proc print data = whas500 label noobs;
var id bmi age hr diasbp gender chf;
where id in(51 89 112 115 153 194 251 256 416 472);
label id =  "Study ID" bmi = "Body Mass Index" age = "Age" hr = "Heart Rate" diasbp = "Diastolic Blood Pressure"
gender = "Gender" chf = "CHF";
format bmi f8.2 gender genderfmt. chf chffmt.;
run;
             Body                    Diastolic
Study        Mass           Heart      Blood
  ID        Index    Age     Rate     Pressure    Gender    CHF
  51        22.45     80     105         72       Male      Yes
  89        15.93     95      62         45       Male      No
 112        14.84     87     105        104       Female    No
 115        18.90     81     118         70       Female    Yes
 153        39.94     32     102         83       Female    No
 194        24.21     43      47         90       Male      Yes
 251        22.27    102      89         60       Male      Yes
 256        44.84     53      96         99       Female    No
 416        28.55     80      64        198       Male      No
 472        25.40     72     186         84       Male      No
Table 6.3 on page 191 using the whas500 data.
ods output ParameterEstimates=out63a; proc phreg data = whas500 ; model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga; where diasbp ne 198; run; data out63; set out63a; z = estimate /stderr; lb = estimate-1.96*stderr; ub = estimate+1.96*stderr; run; proc print data = out63 noobs; var variable estimate stderr z probchisq lb ub; format z f8.2; format estimate probchisq lb ub f8.3; format stderr f8.4; run;
ProbChi Variable Estimate StdErr z Sq lb ub bmifp1 -0.685 0.1741 -3.94 0.000 -1.026 -0.344 bmifp2 0.145 0.0395 3.66 0.000 0.067 0.222 AGE 0.060 0.0083 7.15 0.000 0.043 0.076 HR 0.012 0.0029 4.13 0.000 0.006 0.018 DIASBP -0.012 0.0035 -3.48 0.000 -0.019 -0.005 GENDER 1.838 0.9579 1.92 0.055 -0.040 3.715 CHF 0.830 0.1469 5.65 0.000 0.542 1.118 ga -0.027 0.0121 -2.28 0.023 -0.051 -0.004
Table 6.4 on page 194 using the whas500 data.
proc phreg data = whas500 ;
model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga;
where diasbp ne 198;
output out = t64 xbeta = xb resmart = martres;
run;
proc sort data = t64 (where=(diasbp ne 198)) out=t64s;
by xb;
run;
data t64a;
set t64s;
if _n_ <= 100 then quin = 1;
if 101 <= _n_ <= 200 then quin = 2;
if 201 <= _n_ <= 300 then quin = 3;
if 301 <= _n_ <= 400 then quin = 4;
if _n_ >= 401 then quin = 5;
run;
proc sql;
  create table t64b as
  select quin, max(xb) as cut_point, count(quin) as count, 
         sum(fstat) as observed, sum(fstat-martres) as expected
  from t64a
  group by quin;
quit;
data t64c;
  set t64b;
  z = (observed-expected)/sqrt(expected);
  p = 2*(1-PROBNORM(abs(z)));
run;
proc print data = t64c noobs label;
label quin = "Quintile" cut_point = "Cut Point" count = "Count" observed = "Observed" expected = "Expected";
format cut_point expected z f8.2 p f8.3;
run;
                 Cut
Quintile       Point    Count    Observed    Expected           z           p
    1           1.37     100         6           8.17       -0.76       0.448
    2           2.17     100        15          22.47       -1.58       0.115
    3           2.80     100        41          37.55        0.56       0.574
    4           3.52     100        66          53.39        1.73       0.084
    5           5.66      99        86          92.41       -0.67       0.505
Table 6.5 on page 196 using the whas500 data.
ods output ParameterEstimates=out65a; proc phreg data = whas500 ; model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga; where diasbp ne 198; run; data out65; set out65a; z = estimate /stderr; lb = estimate-1.96*stderr; ub = estimate+1.96*stderr; run; proc print data = out65 noobs; var variable estimate stderr z probchisq lb ub; format z f8.2; format estimate probchisq lb ub f8.3; format stderr f8.4; run;
ProbChi Variable Estimate StdErr z Sq lb ub bmifp1 -0.685 0.1741 -3.94 0.000 -1.026 -0.344 bmifp2 0.145 0.0395 3.66 0.000 0.067 0.222 AGE 0.060 0.0083 7.15 0.000 0.043 0.076 HR 0.012 0.0029 4.13 0.000 0.006 0.018 DIASBP -0.012 0.0035 -3.48 0.000 -0.019 -0.005 GENDER 1.838 0.9579 1.92 0.055 -0.040 3.715 CHF 0.830 0.1469 5.65 0.000 0.542 1.118 ga -0.027 0.0121 -2.28 0.023 -0.051 -0.004
Table 6.6 on page 198 using the whas500 data.
proc phreg data = whas500 ; model lenfol*fstat(0) = bmifp1 bmifp2 age hr10 diasbp10 gender chf ga / risklimits; where diasbp ne 198; hr10 = hr/10; diasbp10 = diasbp/10; run;
The PHREG Procedure
               Analysis of Maximum Likelihood Estimates
                   Parameter      Standard
Variable    DF      Estimate         Error    Chi-Square    Pr > ChiSq
bmifp1       1      -0.68510       0.17408       15.4891        <.0001
bmifp2       1       0.14480       0.03954       13.4100        0.0003
AGE          1       0.05957       0.00833       51.1641        <.0001
hr10         1       0.12170       0.02945       17.0712        <.0001
diasbp10     1      -0.12237       0.03513       12.1357        0.0005
GENDER       1       1.83776       0.95793        3.6805        0.0551
CHF          1       0.83029       0.14693       31.9321        <.0001
ga           1      -0.02742       0.01205        5.1767        0.0229
  Analysis of Maximum Likelihood Estimates
              Hazard      95% Hazard Ratio
Variable       Ratio      Confidence Limits
bmifp1         0.504       0.358       0.709
bmifp2         1.156       1.070       1.249
AGE            1.061       1.044       1.079
hr10           1.129       1.066       1.197
diasbp10       0.885       0.826       0.948
GENDER         6.282       0.961      41.070
CHF            2.294       1.720       3.060
ga             0.973       0.950       0.996
Table 6.7 on page 198 using the whas500 data. Our confidence intervals are slightly different from those in the book.
ods output covb = covb;
proc phreg data = whas500;
model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga / covb;
ga = gender*age;
run;
data _null_;
  set covb;
  if upcase(rowname) = "GENDER" then 
    call symput('vgender', gender);
  if upcase(rowname) = "GA" then do;
    call symput('vga', ga);
    call symput('covga_age', gender);
   end;
run;
* see equations on pages 197-198;
data t67; 
  do age =40 to 90 by 10;
   hz = 1.838 - 0.027*age;
   ul = hz + 1.96*sqrt(&vgender+ age**2*&vga +2*age*&covga_age);
   ll = hz - 1.96*sqrt(&vgender+ age**2*&vga +2*age*&covga_age);
   exphz=exp(hz);
   expul = exp(ul);
   expll =exp(ll);
   output;
  end;
run;
proc print data = t67 noobs label;
var age exphz expll expul;
format exphz expul expll f8.2;
label age='Age' exphz='HR' expll='Lower Limit' expul='Upper Limit';
run;
Lower Upper Age HR Limit Limit 40 2.13 0.82 5.54 50 1.63 0.78 3.38 60 1.24 0.74 2.09 70 0.95 0.67 1.34 80 0.72 0.55 0.96 90 0.55 0.38 0.81
Figure 6.9 on page 202 using the whas500 data. To achieve the desired labeling of the lines, we must create a legend using a data step.
ods output covb = f69;
ods output ParameterEstimates = pe;
proc phreg data = whas500;
model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga / covb;
where id ne 416;
ga = gender*age;
run;
data _null_;
set pe;
if Variable = "bmifp1" then 
call symput('ebmifp1', Estimate);
if Variable = "bmifp2" then 
call symput('ebmifp2', Estimate);
run;
data _null_;
  set f69;
  if rowname = "bmifp1" then 
    call symput('vbmifp1', bmifp1);
  if rowname = "bmifp2" then do;
    call symput('vbmifp2', bmifp2);
    call symput('cov1_2', bmifp1);
   end;
run;
data ch6f9;
set whas500;
a = bmifp1 - 9.9225;
b = bmifp2 - 31.25588;
ln_hr = &ebmifp1*a+&ebmifp2*b;
hr = exp(ln_hr);
se_ln_hr = sqrt(a**2*&vbmifp1+b**2*&vbmifp2+2*a*b*&cov1_2);
ln_hr_l = ln_hr-1.96*se_ln_hr;
ln_hr_u= ln_hr+1.96*se_ln_hr;
hr_l=exp(ln_hr_l);
hr_u=exp(ln_hr_u);
run;
proc print data = ch6f9 (obs = 15);
var hr;
run;
proc sort data = ch6f9;
by bmi;
run;
data annolegend;
length function style color $8 text $22;
  retain xsys ysys '1' when 'a' color 'black';
        
  function='move';          
    x=35;  y=90;  output;
  function='draw';
    x=51;  y=90;  line=14;  output;
  function='label'; 
    x=52;  y=90;  position='6';
    text='Confidence Limits';
    output;
                
  function='move';  
    x=35;  y=93;  output;
  function='draw'; 
    x=51;  y=93;  line=1;  output;
  function='label';
    x=52;  y=93;  position='6';
    text='Estimated Hazard Ratio';
    output;                
run;
goptions reset = all;
axis1 order=(0 to 8 by 2) label=(a=90 'Estimated Hazard Ratio') minor=none;
axis2 order=(10 to 50 by 10) label=('Body Mass Index (kg/m^2)') minor=none;
symbol1 i=join v=none c=black line=1;
symbol2 i=join v=none c=black line=14;
symbol3 i=join v=none c=black line=14;
goptions  ftext = swiss htitle = 5 htext = 3 gunit = pct 
          cback = white hsize = 5in vsize = 4in;
proc gplot data = ch6f9;
plot (hr hr_u hr_l)* bmi / overlay vaxis = axis1 haxis = axis2 vref=1 nolegend annotate=annolegend;
run;
quit;

Table 6.8 on page 203 continuing to use the whas500 data. We will use parameter estimates, variances, and co-variances from the model we ran to generate Figure 6.9 and the formulas on page 201.
data t68; do bmi = 15 to 40 by 5; a = (bmi/10)**2 - 9.9225; b = (bmi/10)**3 - 31.25588; ln_hr = &ebmifp1*a+&ebmifp2*b; hr = exp(ln_hr); se_ln_hr = sqrt(a**2*&vbmifp1+b**2*&vbmifp2+2*a*b*&cov1_2); ul = ln_hr + 1.96*se_ln_hr; ll = ln_hr - 1.96*se_ln_hr; expul = exp(ul); expll =exp(ll); output; end; run; proc print data = t68 noobs; var bmi hr expll expul; run; bmi hr expll expul 15 3.38472 1.89928 6.03194 20 1.99381 1.39381 2.85210 25 1.28746 1.06698 1.55350 30 1.01588 0.96612 1.06820 35 1.09186 0.92607 1.28734 40 1.78188 1.00170 3.16972
Figure 6.10 on page 204 using the whas500 data.
data c;
  array a(*) bmifp1 bmifp2 age hr diasbp gender chf ga;
  do i = 1 to dim(a);
    a(i) = 0;
  end;
  drop i;
  output;
run;
proc phreg data = whas500 outest=f610_cov covout;
model lenfol*fstat(0) = bmifp1 bmifp2 age hr diasbp gender chf ga;
ga = gender*age;
id id;
where diasbp ne 198;
output out = f610 xbeta = xb;
baseline out = f610bsurv covariates = c survival = surv /nomean;
run;
data test1;
  set f610_cov;
  if _n_ = 1 then do; 
    call symput('bgender', gender);
    call symput('bage', age);
    call symput('bga', ga);
   end;
run;
proc sort data = f610bsurv;
by lenfol;
run;
proc sort data = f610;
by lenfol;
run;
data test2;
merge f610bsurv f610;
by lenfol;
rm = xb - &bage*age - &bgender*gender - &bga*ga;
run;
proc means data = test2 median;
  var rm;
  output out=m median=median;
run;
proc sql;
  select median into :rm
  from m;
quit;
data test3;
  set test2;
s72_male = surv**(exp(&rm + &bage*72));
s72_female = surv**(exp(&rm + &bage*72 + &bgender + &bga*72));
years = lenfol/365.25;
run;
                                                                                                                                                                        
goptions reset=all; 
goptions  ftext = swiss htitle = 5 htext = 3 gunit = pct 
          cback = white hsize = 5in vsize = 4in;
axis1 order=(0 to 1 by .2) label=(a=90 'Modified Risk Score Adjusted Survival Functions') minor=none;
axis2 order=(0 to 6 by 2) label=('Follow Up Time (Years)') minor=none;
symbol1 i=stepjll v=none c=black line=1;
symbol2 i=stepjll v=none c=black line=14;
legend label=none value=('72 Year Old Males' '72 Year Old Females')
       position=(bottom left inside) mode=share down = 2; 
proc gplot data = test3;
where years <=6;
plot (s72_male s72_female) * years / overlay vaxis = axis1 haxis = axis2 legend = legend;
run;
quit;

