MMRM in SAS: Step-by-Step

 /*-----------------------------*

 | 0) Housekeeping (optional)  |

 *-----------------------------*/

ods trace on;

options nolabel;


/*-----------------------------*

 | 1) Fit the MMRM             |

 *-----------------------------*/

proc mixed data=xxx(where=(0<vsn<=96)) order=data;

  class usubjid trtc vsn genotype;


  /* Fixed effects */

  model chg =

        trtc|vsn              /* trtc, vsn, and trtc*vsn */

        base*vsn

        b_age*vsn

        genotype*vsn

        / solution ddfm=kr;


  /* Repeated measures (UN covariance) */

  repeated vsn / subject=usubjid type=un;


  /* Precision/analytic weights (e.g., ATT) */

  weight _attwgt_;


  /* LSMEANS with visit-wise EC – Internal study differences */

  lsmeans trtc*vsn / diff cl slice=vsn;


  /* Overall (average over visits) treatment difference */

  estimate 'EC vs Internal study (average over VSN)' trtc 1 -1;


  /* Visit-specific EC – Internal study contrasts

     Ensure the CLASS order for VSN matches 24,48,72,96.

  */

  contrast 'EC – Internal study @ 24w'

           trtc 1 -1

           trtc*vsn   1 0 0 0    -1 0 0 0;


  contrast 'EC – Internal study @ 48w'

           trtc 1 -1

           trtc*vsn   0 1 0 0     0 -1 0 0;


  contrast 'EC – Internal study @ 72w'

           trtc 1 -1

           trtc*vsn   0 0 1 0     0  0 -1 0;


  contrast 'EC – Internal study @ 96w'

           trtc 1 -1

           trtc*vsn   0 0 0 1     0  0  0 -1;


  /* Global joint test across visits (multi-df Wald) */

  contrast 'Global treatment difference across visits'

           trtc 1 -1  trtc*vsn  1 0 0 0  -1 0 0 0,

           trtc 1 -1  trtc*vsn  0 1 0 0   0 -1 0 0,

           trtc 1 -1  trtc*vsn  0 0 1 0   0  0 -1 0,

           trtc 1 -1  trtc*vsn  0 0 0 1   0  0  0 -1;


  /* Capture outputs for TLFs/QC */

  ods output

    lsmeans   = lsm_vsn_trt

    diffs     = dif_vsn_trt

    covparms  = cov_un

    estimates = est_tests;

run;


ods trace off;

What each step does (and how to read it)

  1. PROC MIXED & CLASS
    Declares the repeated-measures factors. order=data ensures your visit order (e.g., 24, 48, 72, 96) is used when constructing contrasts and LSMeans.

  2. MODEL statement

    • trtc|vsn fits treatment, visit, and their interaction, so the treatment effect can differ by visit (core of MMRM).

    • base*vsn, b_age*vsn, genotype*vsn allow covariate effects to vary by visit (common in SAPs for longitudinal change).

    • ddfm=kr uses Kenward–Roger degrees of freedom (better small-sample properties).

    • solution prints estimates for all fixed effects (useful for QC, usually not reported directly).

  3. REPEATED with TYPE=UN
    Sets an unstructured covariance for within-subject residuals—maximally flexible (variance and correlation free to vary by visit pair). Appropriate when N allows, and convergence is stable.

  4. WEIGHT attwgt
    Applies precision (analytic) weights (e.g., ATT weights from propensity modeling). Larger weights imply smaller residual variance and more influence.
    Tips: ensure weights are positive; consider trimming/stabilizing extreme weights; rerun as sensitivity with trimmed weights.

  5. LSMEANS trtc*vsn / diff cl slice=vsn
    Produces visit-specific EC–Mission differences with CIs and p-values without hand-coding coefficients. This is the easiest, least error-prone way to get per-visit effects.

  6. ESTIMATE 'EC vs Mission'
    Gives an average treatment difference across visits under the model; often de-emphasized when the interaction is present (interpret with care).

  7. CONTRAST (per visit)
    Explicitly reconstructs EC–Mission at a given visit using the cell-means coding for trtc and trtc*vsn. Functionally matches the SLICE=VSN results; useful for an auditable, fixed set of inferential statements.

  8. Global joint test (multi-df)
    The comma-separated CONTRAST forms a Wald test that all visit-specific EC–Mission differences are zero simultaneously. Report the F/χ², df, and p-value as your global longitudinal treatment test.

  9. ODS OUTPUT

    • lsm_vsn_trt: LSMeans for each (trtc, vsn) cell (good for figures).

    • dif_vsn_trt: Per-visit differences with SE, t, CI, p (table/forest).

    • cov_un: the estimated UN covariance (check plausibility, convergence).

    • est_tests: rows for ESTIMATE/CONTRAST (per-visit and global tests).


Interpretation + QC checklist

  • Primary readouts: table from dif_vsn_trt (EC–Mission at 24/48/72/96 weeks) and the Global test from est_tests.

  • Convergence & fit: in the PROC MIXED log and cov_un; if UN struggles, consider CSH or ARH(1) as sensitivity.

  • Missing data: MMRM assumes MAR given included covariates. If dropout is meaningful, plan MI/tipping-point sensitivity.

  • Level order safety: Ensure VSN levels are in the intended order (use order=data and pre-sort your dataset).

  • Weights: Inspect distribution; consider stabilized ATT, trimming (e.g., 1st–99th percentile).

  • Multiplicity: Report both per-visit results and the global joint test to support the overall claim.

Comments

Popular posts from this blog

Analysis of Repeated Measures Data using SAS (1)

Understanding Binding vs. Non-Binding Futility Analysis in Clinical Trials

Medical information for Melanoma, Merkel cell carcinoma and tumor mutation burden