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;

