Program: t_14_2_x_pfs_summary_saffl.sas
Population: Safety Analysis Set (SAFFL='Y')
Author: Alpha Traore
Create the PFS summary table per SAP, including (as applicable):
PARAMCD='PFS' or per SAP)ADSL
USUBJIDTRT01A / TRT01ANSAFFLADTTE
USUBJIDPARAMCDAVAL (time)CNSR (censoring indicator)TIME AVAL*CNSR(1);STRATA TRT01AN;CNSR=0 → eventCNSR=1 → censored (per SAP)QuartilesProductLimitEstimates using TIMELIST=...SAFFL='Y' and PARAMCD='PFS'.options mprint mlogic symbolgen;
options validvarname=upcase;
Read the ADaM Datasets Required for Table Generation: ADSL and ADTTE
libname aa "/export/viya/homes/alpha@alphatraore.com/toydata";
/* proc datasets lib=aa; quit;*/
proc sort data=aa.adsl out = adsl ; by usubjid; run;
proc sort data=aa.adtte out = adtte ; by usubjid; run;
data subj;
set adsl;
where saffl="Y";
trt=trt01an;
run;
data tte;
set adtte;
trt=trtan;
run;
proc sort data=subj; by usubjid; run;
proc sort data=tte; by usubjid; run;
data temp1 (where=(TRT in (1,2)) );
merge subj tte;
by usubjid;
run;
proc print data=temp1(obs=5); run;
| Obs | USUBJID | TRT01AN | SAFFL | TRT | TRTAN | PARAM | PARAMCD | AVAL | CNSR | PARAMN |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 01-701-1015 | 1 | Y | 1 | 1 | Progression Free Survival | PFS | 2 | 0 | 1 |
| 2 | 01-701-1023 | 1 | Y | 1 | 1 | Progression Free Survival | PFS | 3 | 0 | 1 |
| 3 | 01-701-1028 | 2 | Y | 2 | 2 | Progression Free Survival | PFS | 3 | 0 | 1 |
| 4 | 01-701-1034 | 2 | Y | 2 | 2 | Progression Free Survival | PFS | 58 | 0 | 1 |
| 5 | 01-701-1047 | 1 | Y | 1 | 1 | Progression Free Survival | PFS | 46 | 1 | 1 |
Create macro variables to hold treatment totals
%let n1=0;
%let n2=0;
proc sql noprint;
select count(distinct usubjid) into :n1 from subj where trt=1;
select count(distinct usubjid) into :n2 from subj where trt=2;
quit;
%put &=n1 &=n2;
1940 ods listing close;ods html5 (id=saspy_internal) options(bitmap_mode='inline') device=svg style=HTMLBlue; ods graphics on / 1940! outputfmt=png; NOTE: Writing HTML5(SASPY_INTERNAL) Body file: sashtml95.htm 1941 1942 %let n1=0; 1943 %let n2=0; 1944 proc sql noprint; 1945 select count(distinct usubjid) into :n1 from subj where trt=1; 1946 select count(distinct usubjid) into :n2 from subj where trt=2; 1947 quit; NOTE: PROCEDURE SQL used (Total process time): real time 0.00 seconds cpu time 0.00 seconds SYMBOLGEN: Macro variable N1 resolves to 86 SYMBOLGEN: Macro variable N2 resolves to 84 1948 1949 %put &=n1 &=n2; N1= 86 N2= 84 1950 ods html5 (id=saspy_internal) close;ods listing; 1951
Outputs
proc sort data=temp1;
by trt;
run;
ods output quartiles=quar100;
ods output censoredsummary=cens100;
ods output productlimitestimates=est100;
proc lifetest data=temp1 method=km timelist=(0 to 150 by 50) conftype=linear reduceout;
time aval*cnsr(0);
strata trt;
survival out=surv100;
run;
The LIFETEST Procedure
Stratum 1: TRT = 1
| Product-Limit Survival Estimates | |||||||
|---|---|---|---|---|---|---|---|
| Timelist | AVAL | Survival | Failure | Survival Standard Error | Number Failed |
Number Left |
|
| 0.000 | 0.000 | 1.0000 | 0 | 0 | 0 | 86 | |
| 50.000 | 46.000 | 0.9080 | 0.0920 | 0.0333 | 7 | 61 | |
| 100.000 | 70.000 | 0.8318 | 0.1682 | 0.0446 | 12 | 47 | |
| 150.000 | 148.000 | 0.7233 | 0.2767 | 0.0567 | 18 | 40 | |
Summary Statistics for Time Variable AVAL
| Quartile Estimates | ||||
|---|---|---|---|---|
| Percent | Point Estimate |
95% Confidence Interval | ||
| Transform | [Lower | Upper) | ||
| 75 | 184.000 | LINEAR | 183.000 | 189.000 |
| 50 | 183.000 | LINEAR | 181.000 | 183.000 |
| 25 | 142.000 | LINEAR | 70.000 | 181.000 |
| Mean | Standard Error |
|---|---|
| 155.141 | 6.524 |
The LIFETEST Procedure
Stratum 2: TRT = 2
| Product-Limit Survival Estimates | |||||||
|---|---|---|---|---|---|---|---|
| Timelist | AVAL | Survival | Failure | Survival Standard Error | Number Failed |
Number Left |
|
| 0.000 | 0.000 | 1.0000 | 0 | 0 | 0 | 84 | |
| 50.000 | 44.000 | 0.7373 | 0.2627 | 0.0611 | 15 | 21 | |
| 100.000 | 69.000 | 0.5241 | 0.4759 | 0.1010 | 19 | 4 | |
| 150.000 | 69.000 | 0.5241 | 0.4759 | 0.1010 | 19 | 4 | |
Summary Statistics for Time Variable AVAL
| Quartile Estimates | ||||
|---|---|---|---|---|
| Percent | Point Estimate |
95% Confidence Interval | ||
| Transform | [Lower | Upper) | ||
| 75 | 188.000 | LINEAR | 167.000 | . |
| 50 | 167.000 | LINEAR | 63.000 | 188.000 |
| 25 | 44.000 | LINEAR | 22.000 | 69.000 |
| Mean | Standard Error |
|---|---|
| 113.996 | 13.519 |
| Summary of the Number of Censored and Uncensored Values | |||||
|---|---|---|---|---|---|
| Stratum | TRT | Total | Failed | Censored | Percent Censored |
| 1 | 1 | 86 | 57 | 29 | 33.72 |
| 2 | 2 | 84 | 23 | 61 | 72.62 |
| Total | 170 | 80 | 90 | 52.94 | |
The LIFETEST Procedure
Testing Homogeneity of Survival Curves for AVAL over Strata
| Rank Statistics | ||
|---|---|---|
| TRT | Log-Rank | Wilcoxon |
| 1 | -9.0694 | -974.00 |
| 2 | 9.0694 | 974.00 |
| Covariance Matrix for the Log-Rank Statistics | ||
|---|---|---|
| TRT | 1 | 2 |
| 1 | 9.13610 | -9.13610 |
| 2 | -9.13610 | 9.13610 |
| Covariance Matrix for the Wilcoxon Statistics | ||
|---|---|---|
| TRT | 1 | 2 |
| 1 | 97765.0 | -97765.0 |
| 2 | -97765.0 | 97765.0 |
| Test of Equality over Strata | |||
|---|---|---|---|
| Test | Chi-Square | DF | Pr > Chi-Square |
| Log-Rank | 9.0032 | 1 | 0.0027 |
| Wilcoxon | 9.7036 | 1 | 0.0018 |
| -2Log(LR) | 1.1005 | 1 | 0.2941 |
Purpose
57 (66.3%))data cens101;
set cens100;
where not missing(trt);
pctfail=100-pctcens;
length cp $30 label $200;
cp=put(failed,3.)||" ("||put(pctfail,5.1)||"%)";
label="Event (Progression or Death)"; group=1; order=1; output;
cp=put(censored,3.)||" ("||put(pctcens,5.1)||"%)";
label="Censored"; order=2; output;
keep group order label trt cp;
run;
proc print data = cens101; run;
| Obs | TRT | CP | LABEL | GROUP | ORDER |
|---|---|---|---|---|---|
| 1 | 1 | 57 ( 66.3%) | Event (Progression or Death) | 1 | 1 |
| 2 | 1 | 29 ( 33.7%) | Censored | 1 | 2 |
| 3 | 2 | 23 ( 27.4%) | Event (Progression or Death) | 1 | 1 |
| 4 | 2 | 61 ( 72.6%) | Censored | 1 | 2 |
Purpose
NE (Not Estimable)data quar101;
set quar100;
length cp ul ll est $30 label $200;
if not missing(estimate) then est=put(round(estimate,0.1),5.1);
else est="NE";
if not missing(lowerlimit) then ll=put(round(lowerlimit,0.01),6.2);
else ll="NE";
if not missing(upperlimit) then ul=put(round(upperlimit,0.01),6.2);
else ul="NE";
cp=strip(est)||" ("||strip(ll)||", "||strip(ul)||")";
order=percent;
if percent=25 then label="25th Percentile";
else if percent=50 then label="50th Percentile";
else if percent=75 then label="75th Percentile";
group=2;
keep group order label trt cp;
run;
proc print data =quar101; run;
| Obs | TRT | CP | LABEL | ORDER | GROUP |
|---|---|---|---|---|---|
| 1 | 1 | 184.0 (183.00, 189.00) | 75th Percentile | 75 | 2 |
| 2 | 1 | 183.0 (181.00, 183.00) | 50th Percentile | 50 | 2 |
| 3 | 1 | 142.0 (70.00, 181.00) | 25th Percentile | 25 | 2 |
| 4 | 2 | 188.0 (167.00, NE) | 75th Percentile | 75 | 2 |
| 5 | 2 | 167.0 (63.00, 188.00) | 50th Percentile | 50 | 2 |
| 6 | 2 | 44.0 (22.00, 69.00) | 25th Percentile | 25 | 2 |
data surv101;
set surv100;
length cp ul ll est $30 label $200;
if not missing(survival) then est=put(round(survival*100,0.1),6.1);
else est="NE";
if not missing(sdf_lcl) then ll=put(round(sdf_lcl*100,0.01),7.2);
else ll="NE";
if not missing(sdf_ucl) then ul=put(round(sdf_ucl*100,0.01),7.2);
else ul="NE";
if timelist=50 then label="50 (days)";
else if timelist=100 then label="100 (days)";
else if timelist=150 then label="150 (days)";
else if timelist=0 then label="0 (days)";
cp=strip(est)||" ("||strip(ll)||", "||strip(ul)||")";
group=3;
if timelist ne 0 then order=timelist;
else order=1;
keep group order label trt cp;
run;
proc print data =surv101; run;
| Obs | TRT | CP | LABEL | GROUP | ORDER |
|---|---|---|---|---|---|
| 1 | 1 | 100.0 (100.00, 100.00) | 0 (days) | 3 | 1 |
| 2 | 1 | 90.8 (84.28, 97.32) | 50 (days) | 3 | 50 |
| 3 | 1 | 83.2 (74.43, 91.93) | 100 (days) | 3 | 100 |
| 4 | 1 | 72.3 (61.22, 83.44) | 150 (days) | 3 | 150 |
| 5 | 2 | 100.0 (100.00, 100.00) | 0 (days) | 3 | 1 |
| 6 | 2 | 73.7 (61.76, 85.71) | 50 (days) | 3 | 50 |
| 7 | 2 | 52.4 (32.61, 72.21) | 100 (days) | 3 | 100 |
| 8 | 2 | 52.4 (32.61, 72.21) | 150 (days) | 3 | 150 |
PROC PHREG to estimate the treatment effect on time-to-eventParameterEstimates (ODS OUTPUT) and report the Hazard Ratio with 95% CI (Wald)ods output parameterestimates=hazard100;
proc phreg data = temp1;
class trt(ref="1");
model aval*cnsr(1)=trt/ties=efron rl=wald;
run;
proc print data=hazard100; run;
The PHREG Procedure
| Model Information | ||
|---|---|---|
| Data Set | WORK.TEMP1 | |
| Dependent Variable | AVAL | Analysis Value |
| Censoring Variable | CNSR | Censor |
| Censoring Value(s) | 1 | |
| Ties Handling | EFRON | |
|
Number of Observations Read
Number of Observations Used
|
170
170
|
|---|
| Class Level Information | ||
|---|---|---|
| Class | Value | Design Variables |
| TRT | 1 | 0 |
| 2 | 1 | |
| Summary of the Number of Event and Censored Values | |||
|---|---|---|---|
| Total | Event | Censored | Percent Censored |
| 170 | 90 | 80 | 47.06 |
| Convergence Status |
|---|
| Convergence criterion (GCONV=1E-8) satisfied. |
| Model Fit Statistics | ||
|---|---|---|
| Criterion | Without Covariates |
With Covariates |
| -2 LOG L | 835.141 | 785.925 |
| AIC | 835.141 | 787.925 |
| SBC | 835.141 | 790.425 |
| Testing Global Null Hypothesis: BETA=0 | |||
|---|---|---|---|
| Test | Chi-Square | DF | Pr > ChiSq |
| Likelihood Ratio | 49.2153 | 1 | <.0001 |
| Score | 52.4128 | 1 | <.0001 |
| Wald | 44.6925 | 1 | <.0001 |
| Type 3 Tests | |||
|---|---|---|---|
| Effect | DF | Wald Chi-Square | Pr > ChiSq |
| TRT | 1 | 44.6925 | <.0001 |
| Analysis of Maximum Likelihood Estimates | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Parameter | DF | Parameter Estimate |
Standard Error |
Chi-Square | Pr > ChiSq | Hazard Ratio |
95% Hazard Ratio Confidence Limits | Label | ||
| TRT | 2 | 1 | 1.59335 | 0.23834 | 44.6925 | <.0001 | 4.920 | 3.084 | 7.850 | TRT 2 |
| Obs | PARAMETER | CLASSVAL0 | DF | ESTIMATE | STDERR | CHISQ | PROBCHISQ | HAZARDRATIO | HRLOWERCL | HRUPPERCL | LABEL |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | TRT | 2 | 1 | 1.59335 | 0.23834 | 44.6925 | <.0001 | 4.920 | 3.084 | 7.850 | TRT 2 |
data hazard101;
set hazard100 (drop=label);
length hazard est ll ul $30 ;
if hazardratio ne . then est=put(round(hazardratio,0.1),6.1);
else est="NE";
if hrlowercl ne . then ll=put(round(hrlowercl,0.1),6.1);
else ll="NE";
if hruppercl ne . then ul=put(round(hruppercl,0.1),6.1);
else ul="NE";
group=4;
order=1;
label="Hazard Ratio - Estimate (95% CI)";
hazard=strip(est)||" ("||strip(ll)||","||strip(ul)||")";
run;
proc print data=hazard101; run;
| Obs | PARAMETER | CLASSVAL0 | DF | ESTIMATE | STDERR | CHISQ | PROBCHISQ | HAZARDRATIO | HRLOWERCL | HRUPPERCL | HAZARD | EST | LL | UL | GROUP | ORDER | LABEL |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | TRT | 2 | 1 | 1.59335 | 0.23834 | 44.6925 | <.0001 | 4.920 | 3.084 | 7.850 | 4.9 (3.1,7.8) | 4.9 | 3.1 | 7.8 | 4 | 1 | Hazard Ratio - Estimate (95% CI) |
data summary100;
set cens101 quar101 surv101;
run;
proc print data =summary100; run;
| Obs | TRT | CP | LABEL | GROUP | ORDER |
|---|---|---|---|---|---|
| 1 | 1 | 57 ( 66.3%) | Event (Progression or Death) | 1 | 1 |
| 2 | 1 | 29 ( 33.7%) | Censored | 1 | 2 |
| 3 | 2 | 23 ( 27.4%) | Event (Progression or Death) | 1 | 1 |
| 4 | 2 | 61 ( 72.6%) | Censored | 1 | 2 |
| 5 | 1 | 184.0 (183.00, 189.00) | 75th Percentile | 2 | 75 |
| 6 | 1 | 183.0 (181.00, 183.00) | 50th Percentile | 2 | 50 |
| 7 | 1 | 142.0 (70.00, 181.00) | 25th Percentile | 2 | 25 |
| 8 | 2 | 188.0 (167.00, NE) | 75th Percentile | 2 | 75 |
| 9 | 2 | 167.0 (63.00, 188.00) | 50th Percentile | 2 | 50 |
| 10 | 2 | 44.0 (22.00, 69.00) | 25th Percentile | 2 | 25 |
| 11 | 1 | 100.0 (100.00, 100.00) | 0 (days) | 3 | 1 |
| 12 | 1 | 90.8 (84.28, 97.32) | 50 (days) | 3 | 50 |
| 13 | 1 | 83.2 (74.43, 91.93) | 100 (days) | 3 | 100 |
| 14 | 1 | 72.3 (61.22, 83.44) | 150 (days) | 3 | 150 |
| 15 | 2 | 100.0 (100.00, 100.00) | 0 (days) | 3 | 1 |
| 16 | 2 | 73.7 (61.76, 85.71) | 50 (days) | 3 | 50 |
| 17 | 2 | 52.4 (32.61, 72.21) | 100 (days) | 3 | 100 |
| 18 | 2 | 52.4 (32.61, 72.21) | 150 (days) | 3 | 150 |
/========================================================= Transpose the dataset such that treatments become columns =========================================================/
proc sort data=summary100;
by group order label trt;
run;
proc transpose data=summary100 out=t_summary100 prefix=trt;
by group order label;
var cp;
id trt;
run;
proc print data=t_summary100; run;
| Obs | GROUP | ORDER | LABEL | _NAME_ | TRT1 | TRT2 |
|---|---|---|---|---|---|---|
| 1 | 1 | 1 | Event (Progression or Death) | CP | 57 ( 66.3%) | 23 ( 27.4%) |
| 2 | 1 | 2 | Censored | CP | 29 ( 33.7%) | 61 ( 72.6%) |
| 3 | 2 | 25 | 25th Percentile | CP | 142.0 (70.00, 181.00) | 44.0 (22.00, 69.00) |
| 4 | 2 | 50 | 50th Percentile | CP | 183.0 (181.00, 183.00) | 167.0 (63.00, 188.00) |
| 5 | 2 | 75 | 75th Percentile | CP | 184.0 (183.00, 189.00) | 188.0 (167.00, NE) |
| 6 | 3 | 1 | 0 (days) | CP | 100.0 (100.00, 100.00) | 100.0 (100.00, 100.00) |
| 7 | 3 | 50 | 50 (days) | CP | 90.8 (84.28, 97.32) | 73.7 (61.76, 85.71) |
| 8 | 3 | 100 | 100 (days) | CP | 83.2 (74.43, 91.93) | 52.4 (32.61, 72.21) |
| 9 | 3 | 150 | 150 (days) | CP | 72.3 (61.22, 83.44) | 52.4 (32.61, 72.21) |
data rowlabels;
length label $200;
label="Censor Summary - n (%)"; group=1; order=0; output;
label="Survival Summary - Estimate (95% CI)";group=2; order=0; output;
label="Percent Survival - Estimate (95% CI)"; group=3; order=0; output;
run;
proc print data =rowlabels ; run;
| Obs | LABEL | GROUP | ORDER |
|---|---|---|---|
| 1 | Censor Summary - n (%) | 1 | 0 |
| 2 | Survival Summary - Estimate (95% CI) | 2 | 0 |
| 3 | Percent Survival - Estimate (95% CI) | 3 | 0 |
/========================================================= Combine group labels to actual data =========================================================/
data final;
set t_summary100 rowlabels hazard101(keep=group label order hazard);
/*if order ne 0 then label="(*ESC*)\li250 "||strip(label);*/
run;
proc sort data=final;
by group order label;
run;
proc print data=final; run;
| Obs | GROUP | ORDER | LABEL | _NAME_ | TRT1 | TRT2 | HAZARD |
|---|---|---|---|---|---|---|---|
| 1 | 1 | 0 | Censor Summary - n (%) | ||||
| 2 | 1 | 1 | Event (Progression or Death) | CP | 57 ( 66.3%) | 23 ( 27.4%) | |
| 3 | 1 | 2 | Censored | CP | 29 ( 33.7%) | 61 ( 72.6%) | |
| 4 | 2 | 0 | Survival Summary - Estimate (95% CI) | ||||
| 5 | 2 | 25 | 25th Percentile | CP | 142.0 (70.00, 181.00) | 44.0 (22.00, 69.00) | |
| 6 | 2 | 50 | 50th Percentile | CP | 183.0 (181.00, 183.00) | 167.0 (63.00, 188.00) | |
| 7 | 2 | 75 | 75th Percentile | CP | 184.0 (183.00, 189.00) | 188.0 (167.00, NE) | |
| 8 | 3 | 0 | Percent Survival - Estimate (95% CI) | ||||
| 9 | 3 | 1 | 0 (days) | CP | 100.0 (100.00, 100.00) | 100.0 (100.00, 100.00) | |
| 10 | 3 | 50 | 50 (days) | CP | 90.8 (84.28, 97.32) | 73.7 (61.76, 85.71) | |
| 11 | 3 | 100 | 100 (days) | CP | 83.2 (74.43, 91.93) | 52.4 (32.61, 72.21) | |
| 12 | 3 | 150 | 150 (days) | CP | 72.3 (61.22, 83.44) | 52.4 (32.61, 72.21) | |
| 13 | 4 | 1 | Hazard Ratio - Estimate (95% CI) | 4.9 (3.1,7.8) |
ods escapechar='^';
ods _all_ close;
ods listing close;
ods html5 (id=nb) options(bitmap_mode='inline') style=htmlblue;
ods text="^S={just=l font_face=Arial font_size=18pt font_weight=bold}Overall Survival by Treatment Group";
ods text="^S={just=l font_face=Arial font_size=11pt font_style=italic}Safety Analysis Set";
ods text="^S={just=l} ";
proc report data=final nowd headline headskip missing
style(report)=[just=l outputwidth=95%] /* <-- key change: no just=center */
style(header)=[font_weight=bold];
columns group order label trt1 trt2 hazard;
define group / order noprint;
define order / order noprint;
define label / order ""
style(header)=[just=l]
style(column)=[just=l cellwidth=2.5in protectspecialchars=off];
define trt1 / "Treatment A" "(N=%cmpres(&n1))"
style(column)=[cellwidth=1.2in just=c];
define trt2 / "Treatment B" "(N=%cmpres(&n2))"
style(column)=[cellwidth=0.7in just=c];
define hazard / "Treatment Difference"
style(column)=[cellwidth=0.7in just=c];
compute after group;
line @1 " ";
endcomp;
run;
ods html5 (id=nb) close;
ods listing;
Overall Survival by Treatment Group
Safety Analysis Set
| Treatment A (N=86) |
Treatment B (N=84) |
Treatment Difference | |
|---|---|---|---|
| Censor Summary - n (%) | |||
| Event (Progression or Death) | 57 ( 66.3%) | 23 ( 27.4%) | |
| Censored | 29 ( 33.7%) | 61 ( 72.6%) | |
| Survival Summary - Estimate (95% CI) | |||
| 25th Percentile | 142.0 (70.00, 181.00) | 44.0 (22.00, 69.00) | |
| 50th Percentile | 183.0 (181.00, 183.00) | 167.0 (63.00, 188.00) | |
| 75th Percentile | 184.0 (183.00, 189.00) | 188.0 (167.00, NE) | |
| Percent Survival - Estimate (95% CI) | |||
| 0 (days) | 100.0 (100.00, 100.00) | 100.0 (100.00, 100.00) | |
| 50 (days) | 90.8 (84.28, 97.32) | 73.7 (61.76, 85.71) | |
| 100 (days) | 83.2 (74.43, 91.93) | 52.4 (32.61, 72.21) | |
| 150 (days) | 72.3 (61.22, 83.44) | 52.4 (32.61, 72.21) | |
| Hazard Ratio - Estimate (95% CI) | 4.9 (3.1,7.8) | ||