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

Use FDA Suggestions on Missing Data and Sensitivity Analyses

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

Not Estimable: Why the Median Time-to-Event Is Sometimes Out of Reach ?