Contrasts

Multiple at options

If you have more than one at option then you can perform contrasts. For example, if you predict survival curves for more than one covariate pattern can take differences or ratios of these predictions.

This is best shown through example. I first load the Rotterdam 2 breast cancer data.

. use https://www.pclambert.net/data/rott2b, clear
(Rotterdam breast cancer data (augmented with cause of death))

. stset os, f(osi==1) scale(12) exit(time 60)

Survival-time data settings

         Failure event: osi==1
Observed time interval: (0, os]
     Exit on or before: time 60
     Time for analysis: time/12

--------------------------------------------------------------------------
      2,982  total observations
          0  exclusions
--------------------------------------------------------------------------
      2,982  observations remaining, representing
        753  failures in single-record/single-failure data
 13,038.968  total analysis time at risk and under observation
                                                At risk from t =         0
                                     Earliest observed entry t =         0
                                          Last observed exit t =         5

I will fit a simple model modelling the effect of hormon and use a natural spline for age.

. stpm3 i.hormon @ns(age, df(3)), scale(lncumhazard) df(5) 

Iteration 0:   log likelihood = -2120.3313  
Iteration 1:   log likelihood = -2120.0705  
Iteration 2:   log likelihood = -2120.0694  
Iteration 3:   log likelihood = -2120.0694  

                                                        Number of obs =  2,982
                                                        Wald chi2(4)  =  69.03
Log likelihood = -2120.0694                             Prob > chi2   = 0.0000

------------------------------------------------------------------------------
             | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-------------+----------------------------------------------------------------
xb           |
      hormon |
        yes  |   .3966145   .1041656     3.81   0.000     .1924536    .6007754
 _ns_f1_age1 |  -1.769774   1.089136    -1.62   0.104    -3.904441    .3648924
 _ns_f1_age2 |  -1.233782   .4602279    -2.68   0.007    -2.135812   -.3317519
 _ns_f1_age3 |  -1.709216   .4899396    -3.49   0.000     -2.66948   -.7489521
-------------+----------------------------------------------------------------
time         |
        _ns1 |  -22.10362   2.190797   -10.09   0.000    -26.39751   -17.80974
        _ns2 |   6.252487    1.18838     5.26   0.000     3.923304     8.58167
        _ns3 |  -1.093169   .0583025   -18.75   0.000    -1.207439   -.9788977
        _ns4 |  -.5425182   .0376756   -14.40   0.000    -.6163609   -.4686754
        _ns5 |   -.376672   .0361107   -10.43   0.000    -.4474477   -.3058964
       _cons |  -.1364105   .2354592    -0.58   0.562     -.597902     .325081
------------------------------------------------------------------------------
Extended functions
 (1) @ns(age, df(3))
Warning: This is a test version of stpm3

. estimates store stpm3_ns

I will now predict the survival function for a 70 year woman with and without hormonal treatment.

. predict S70h0 S70h1, survival ci          ///
>               at1(age 70 hormon 0)        ///
>               at2(age 70 hormon 1)        ///
>               timevar(0 5, step(0.1))     ///
>               frame(f1)
Predictions are stored in frame - f1

The predicted survival functions are plotted below.

. frame f1 {
.   twoway (line S70h0 S70h1 tt) ///
>          , xtitle("Years since surgery") ///
>          ytitle("S(t)")                  ///
>          legend(order(1 "hormon=0" 2 "hormon=1") ring(0) pos(1) cols(1))
. }

Visually we can see the difference in the lines which is over 10 percentage points at 5 years. We can calculate the difference using the contrast(difference) option. We can name the contrast variable using the contrastvar() option rather than rely on the default name.

. predict S70h0 S70h1, survival ci          ///
>               at1(age 70 hormon 0)        ///
>               at2(age 70 hormon 1)        ///
>               contrast(difference)        ///
>               contrastvar(Sdiff)          ///
>               timevar(0 5, step(0.1))     ///
>               frame(f1, replace)
Predictions are stored in frame - f1

Once the contrast is stored, it can be plotted together with a 95% confidence interval.

. frame f1 {
.   twoway (rarea Sdiff_lci Sdiff_uci tt, color(red%30)) ///
>          (line Sdiff tt, color(red))                   ///
>          , xtitle("Years since surgery")               ///
>          ytitle("Difference in S(t)")                  ///
>          ylabel(,format(%3.2f))                        ///
>          legend(off)
. }

By default at1() is the reference, so the difference is at2() - at1(). The reference level can be changed using the atreference() option.

. predict S70h0 S70h1, survival ci          ///
>               at1(age 70 hormon 0)        ///
>               at2(age 70 hormon 1)        ///
>               atreference(2)              ///
>               contrast(difference)        ///
>               contrastvar(Sdiff)          ///
>               timevar(0 5, step(0.1))     ///
>               frame(f1, replace)
Predictions are stored in frame - f1

Once the contrast is stored, it can be plotted together with a 95% confidence interval.

. frame f1 {
.   twoway (rarea Sdiff_lci Sdiff_uci tt, color(red%30)) ///
>          (line Sdiff tt, color(red))                   ///
>          , xtitle("Years since surgery")               ///
>          ytitle("Difference in S(t)")                  ///
>          ylabel(,format(%3.2f))                        ///
>          legend(off)
. }

More than 2 at options

You can have as many at options as you want. The following predicts survival at 10 year intervals between 40 and 90 years at diagnosis.

. local j 1

. foreach a of numlist  40(10)90 {
  2.   local atlist `atlist' at`j'(age `a' hormon 0)
  3.   local ++j
  4. } 

. predict S*, survival ci              ///
>             `atlist'                 ///
>             timevar(0 5, step(0.1))  ///
>             frame(f2, replace)
Predictions are stored in frame - f2

. frame f2 {
.   twoway (line S? tt, ) ///
>          , xtitle("Years since surgery")                         ///
>          ytitle("S(t)")                                          ///
>          ylabel(,format(%3.2f))                                  ///
>          legend(order(1 "40" 2 "50" 3 "60" 4 "70" 5 "80" 6 "90") ///
>                 ring(0) pos(7) cols(1))
. }

If you want to make contrasts between the different ages then we need to make one of the at options the reference. Below I make the 2nd at option the reference, which is for 50 year olds (they have the best survival).

. local atlist

. local j 1

. foreach a of numlist  40(10)90 {
  2.   local atlist `atlist' at`j'(age `a' hormon 0)
  3.   local ++j
  4. } 

. predict S*, survival ci                 ///
>             `atlist'                    ///
>             contrast(difference)        ///
>             contrastvar(Sdiff*)         ///
>             atreference(2)              ///
>             timevar(0 5, step(0.1))     ///
>             frame(f2, replace)
Predictions are stored in frame - f2

. frame f2 {
.   twoway (line Sdiff? tt, ) ///
>          , xtitle("Years since surgery")                         ///
>          ytitle("S(t)")                                          ///
>          ylabel(,format(%3.2f))                                  ///
>          title("Difference in survival compared to 50 year old") ///
>          legend(order(1 "40" 2 "60" 3 "70" 4 "80" 5 "90")        ///
>                 ring(0) pos(7) cols(1))
. }

Biostatistician