Treatment-by-Time Interaction: Which Coefficient Is the Treatment Effect?

Clinical Epidemiology ResearchMethodology and Research DesignUniqcret doctor knowledges
Treatment-by-Time Interaction: Which Coefficient Is the Treatment Effect?
On this page

อ่านฉบับภาษาไทย (Thai version)

Abstract

In a randomised trial with repeated visits, a regression with arm, visit and their interaction prints several coefficients, none labelled the treatment effect. This article maps each coefficient to the arm-by-visit means it compares. With two visits, the arm coefficient is the difference between arms at baseline, the visit coefficient is the change in the control arm, and the interaction is a difference in differences: the treatment-arm change minus the control-arm change. With four visits coded as categories (categorical time), the difference between arms at a later visit is the arm coefficient plus that visit's interaction coefficient. Treating time as a number gives one slope difference and assumes straight lines. A simulated trial of 300 adults shows the arithmetic, compares three uses of the baseline score and models the correlation between visits. This article concludes that the treatment effect must be named with its visit and read as a sum of coefficients, and that a baseline-adjusted version of that difference is usually more precise.


Visual summary. Simulated data.

A regression table at a trial writing meeting

A writing committee is drafting the main paper of a randomised trial. The trial enrolled 300 adults with a chronic symptom score, where a lower score means fewer symptoms. Scores were taken at weeks 0, 4, 8 and 12, with week 0 before the first dose. The treatment is fictional and the data are simulated.

The regression table has an intercept, one coefficient for arm, three for visit and three for the arm-by-visit interaction.

A treatment-by-time interaction lets the difference between arms change from visit to visit. A joint test of the three interaction coefficients (one test of whether the arm difference is the same at every visit) is clearly significant. A clinician asks which of these eight numbers is the treatment effect.

The one-sentence answer is this. The treatment effect at week 12 is the arm coefficient plus the week-12 interaction coefficient, and the paper should name week 12 as its visit.

Because the trial has a pre-treatment baseline, a baseline-adjusted version of that difference (constrained baseline or ANCOVA, both defined in 'Three ways to use the week-0 score') is usually the more precise primary estimate. The rest of this article shows why.

Two arms, two visits: four means and four coefficients

Start with a baseline visit and one follow-up visit. Let $Y_{ij}$ be the score of participant $i$ at visit $j$. Let $\mathrm{arm}_i$ be 1 for treatment and 0 for control, and $\mathrm{post}_j$ be 1 at follow-up and 0 at baseline. The mean model is

$$\mathrm{E}(Y_{ij}) = \beta_0 + \beta_1\,\mathrm{arm}_i + \beta_2\,\mathrm{post}_j + \beta_3\,\mathrm{arm}_i\,\mathrm{post}_j$$

Here $\mathrm{E}(Y_{ij})$ is the mean score for a given arm and visit, and each $\beta$ is a coefficient to estimate. Setting the two indicators to 0 or 1 gives the four cell means in the table.

The four cell means of the two-visit model

Read the bottom row: the difference between arms at follow-up is a sum of two coefficients.
ArmBaseline ($\mathrm{post}_j = 0$)Follow-up ($\mathrm{post}_j = 1$)Change, follow-up minus baseline
Control ($\mathrm{arm}_i = 0$)$\beta_0$$\beta_0 + \beta_2$$\beta_2$
Treatment ($\mathrm{arm}_i = 1$)$\beta_0 + \beta_1$$\beta_0 + \beta_1 + \beta_2 + \beta_3$$\beta_2 + \beta_3$
Treatment minus control$\beta_1$$\beta_1 + \beta_3$$\beta_3$

Reading the four cells

Each coefficient now has a plain meaning. $\beta_0$ is the control mean at baseline, and $\beta_1$ is the difference between arms at baseline. $\beta_2$ is the change in the control arm. $\beta_3$ is the change in the treatment arm minus the change in the control arm, a difference in differences.

The difference between arms at follow-up is $\beta_1 + \beta_3$, a sum, not either coefficient alone. A contrast is a sum or difference of coefficients that answers one question, such as the arm difference at week 12.

The reference level of a variable is the category the others are compared with, here the one coded 0. In a model with an interaction, each arm or visit coefficient is read with the other variable at its reference level, here baseline and control.

In a trial, baseline comes before treatment, so randomisation makes the expected baseline difference zero. The estimate of $\beta_1$ therefore reflects chance imbalance, not an effect of treatment. Coding follow-up as the reference would turn $\beta_1$ into the follow-up difference, with the fitted means unchanged.

Hand example: four true means, four coefficients

Hand example. In the simulated trial used throughout this article, the true mean score (simulated truth) is 50 in both arms at week 0. At week 12 the true mean is 44 in the control arm and 38 in the treatment arm. Take week 0 as baseline and week 12 as follow-up.

  1. Control mean at baseline

    \[ \beta_0 = 50 \]

    The intercept is the control arm at week 0.

  2. Baseline difference

    \[ \beta_1 = 50 - 50 = 0 \]

    Randomisation makes the true baseline difference zero.

  3. Change in the control arm

    \[ \beta_2 = 44 - 50 = -6 \]

    The control arm improves by 6 points without the treatment.

  4. Difference in differences

    \[ \beta_3 = (38 - 50) - (44 - 50) = -12 - (-6) = -6 \]

    The treatment arm changes by -12 points, against -6 points in the control arm.

  5. Treatment effect at week 12

    \[ \beta_1 + \beta_3 = 0 + (-6) = -6 \]

    The same number comes straight from the week-12 means: 38 minus 44 is -6.

Result: The true difference in mean score between arms at week 12 is -6 points. It equals $\beta_3$ here only because $\beta_1 = 0$.

Four visits: one interaction coefficient per visit

With visits at weeks 0, 4, 8 and 12, one approach is categorical time: one indicator per visit after baseline, with no assumed shape. Let $d_{kj}$ be 1 when visit $j$ is the $k$-th visit after baseline and 0 otherwise. So $k$ = 1, 2 and 3 stand for weeks 4, 8 and 12. The mean model becomes

$$\mathrm{E}(Y_{ij}) = \beta_0 + \beta_1\,\mathrm{arm}_i + \sum_{k=1}^{3} \beta_{2,k}\,d_{kj} + \sum_{k=1}^{3} \beta_{3,k}\,\mathrm{arm}_i\,d_{kj}$$

Each later visit has its own control change, $\beta_{2,k}$, and its own interaction coefficient, $\beta_{3,k}$. The difference between arms at visit $k$ is $\beta_1 + \beta_{3,k}$, the same sum, one visit at a time. With eight coefficients for eight cell means, the model is saturated. With no missing visits, it reproduces the observed cell means exactly.

The joint test of the three interaction coefficients asks whether the difference between arms is the same at every visit. A reader usually needs a different answer: how large the difference is at week 12.

A straight line instead: one slope difference

The second approach treats time as a number, called linear time. With $t_j$ the week of visit $j$, a linear-time model is

$$\mathrm{E}(Y_{ij}) = \gamma_0 + \gamma_1\,\mathrm{arm}_i + \gamma_2\,t_j + \gamma_3\,\mathrm{arm}_i\,t_j$$

Here $\gamma_0$ and $\gamma_1$ play the roles of $\beta_0$ and $\beta_1$. $\gamma_2$ is the control slope in points per week, and $\gamma_3$ is the slope difference between arms. The difference between arms at week $t$ is $\gamma_1 + \gamma_3 t$, so one coefficient carries the whole time course. The price is an assumption that each arm follows a straight line.

In the simulated trial the true differences between arms are -2, -4 and -6 points at weeks 4, 8 and 12. They lie on a straight line, so both codings target the same values. When a trajectory bends, for example an early response that levels off, a linear model can misstate the final-visit difference. Categorical time makes no shape assumption and suits trials with a few fixed visits [1].

Categorical time versus linear time

The two codings of time side by side. The last row is the trade-off to weigh in the analysis plan.
FeatureCategorical timeLinear time
Time variableOne indicator per visit after baselineWeek as a number
Interaction termsOne per later visit, $\beta_{3,k}$One slope difference, $\gamma_3$
Difference between arms at a visit$\beta_1 + \beta_{3,k}$$\gamma_1 + \gamma_3 t$
Shape assumedNoneA straight line in each arm
Main riskMore coefficients, wider intervals when visits are manyBias at the final visit when the trajectory bends
Drag any visit mean of either arm. The panel shows the categorical-time coefficients, the difference between arms at each visit and the slope difference of a linear-time fit. Bend one trajectory to see the two codings disagree. Starting values: the observed visit means of the simulated trial (simulated data), the same means as in the table of observed means below.

The simulated trial: what the mixed model returns

The rest of this article analyses one simulated dataset. It holds 300 participants, 150 per arm, each scored at four visits, so 1,200 rows with one row per participant-visit. The true means match the hand example. The true differences between arms are -2, -4 and -6 points at weeks 4, 8 and 12.

Observed mean score by arm and week

Simulated data. Mean symptom score, lower is better, 150 participants per arm. At week 0 the arms differ by a fraction of a point, by chance alone.
ArmWeek 0 (points)Week 4 (points)Week 8 (points)Week 12 (points)
Control50.1648.1847.1144.96
Treatment49.9246.1841.8837.54

Fitting categorical time with random effects

The participant-level data are not published. The table of means above is enough to reproduce the coefficients by hand, and the code shows how the model was fitted.

The fitted model is a linear mixed model, fitted by REML (restricted maximum likelihood, the usual way to fit these models): the categorical-time mean model plus two participant-level terms, called random effects. A random intercept shifts a participant's whole trajectory up or down. A random slope tilts it, in points per week. These terms model how one participant's scores are correlated, and they do not change what the mean coefficients mean.

A hat marks a sample estimate. $\hat\beta_1$ is -0.24 points (95% CI -1.90 to 1.42), a chance baseline difference. The week-12 interaction $\hat\beta_{3,3}$ is -7.18 points (95% CI -8.98 to -5.38).

The week-12 difference between arms, $\hat\beta_1 + \hat\beta_{3,3}$, is -7.42 points. That last number equals 37.54 minus 44.96 from the table, because the mean model is saturated.

The code below also fits the three ways of using the week-0 score (see 'Three ways to use the week-0 score') and an unstructured covariance between the random intercept and slope (see 'The correlation between visits, and what it changes when visits are missing').

Difference between arms at each visit: truth and estimate

Simulated data. Each 95% confidence interval covers its true value. The joint test that all three interaction coefficients are zero gives a chi-square statistic of 70.56 on 3 degrees of freedom.
WeekTrue difference (points)Estimated difference (points)95% CI (points)
00-0.24-1.90 to 1.42
4-2-2.00-3.67 to -0.33
8-4-5.23-7.02 to -3.44
12-6-7.42-9.41 to -5.43

Stata: the mixed model, the visit contrasts and the week-12 baseline methods

Stata code d2_lmm.do
* Simulated trial: 300 participants, 1:1, symptom score at weeks 0, 4, 8, 12 (lower is better).
* Simulated data only: nothing here is evidence about any real drug or patient.
version 18
clear all
set more off
set linesize 120

* Load the simulated data (long format: one row per participant-visit).
import delimited using trial.csv, clear asdouble
label define armlab 0 "control" 1 "treatment"
label values arm armlab

* ---------------------------------------------------------------- mixed model, arm x visit
* Categorical visit, arm-by-visit interaction, random intercept and random slope on week (REML).
* stddeviations prints the random effects as standard deviations and their correlation.
mixed score i.arm##i.visit || id: week, covariance(unstructured) reml stddeviations
* beta1 = 1.arm: the difference between arms at week 0, the reference visit.
lincom 1.arm
* beta3,3 = 1.arm#3.visit: the week-12 interaction, a difference in differences.
lincom 1.arm#3.visit
* Difference between arms at each visit, beta1 + beta3,k (k = 1, 2, 3 for weeks 4, 8, 12).
contrast r.arm@visit, effects
forvalues k = 1/3 {
    lincom 1.arm + 1.arm#`k'.visit
}
* Joint Wald test that the three interaction coefficients are zero.
testparm 1.arm#i.visit

* ---------------------------------------------------------------- constrained baseline
* Same random-effects structure, but one common baseline mean for both arms.
generate byte trt_wk4 = arm * (visit == 1)
generate byte trt_wk8 = arm * (visit == 2)
generate byte trt_wk12 = arm * (visit == 3)
mixed score i.visit trt_wk4 trt_wk8 trt_wk12 || id: week, covariance(unstructured) reml stddeviations
lincom trt_wk12

* ---------------------------------------------------------------- week-12 ANCOVA and change score
* Baseline score copied to every row of the participant.
bysort id (visit): generate double score0 = score[1]
generate double change = score - score0
* ANCOVA: week-12 score on arm, adjusted for the baseline score (OLS).
regress score i.arm score0 if visit == 3
* Change score: (week-12 minus week-0) on arm, no baseline adjustment (OLS).
regress change i.arm if visit == 3
Output of the run d2_lmm.log
. * Simulated trial: 300 participants, 1:1, symptom score at weeks 0, 4, 8, 12
> (lower is better).
. * Simulated data only: nothing here is evidence about any real drug or patien
> t.
. version 18

. clear all

. set more off

. set linesize 120

.
. * Load the simulated data (long format: one row per participant-visit).
. import delimited using trial.csv, clear asdouble
(encoding automatically selected: ISO-8859-1)
(6 vars, 1,200 obs)

. label define armlab 0 "control" 1 "treatment"

. label values arm armlab

.
. * ---------------------------------------------------------------- mixed model, arm x visit
. * Categorical visit, arm-by-visit interaction, random intercept and random slope on week (REML).
. * stddeviations prints the random effects as standard deviations and their correlation.
. mixed score i.arm##i.visit || id: week, covariance(unstructured) reml stddeviations

Performing EM optimization ...

Performing gradient-based optimization:
Iteration 0:  Log restricted-likelihood = -3829.3213
Iteration 1:  Log restricted-likelihood = -3829.3199
Iteration 2:  Log restricted-likelihood = -3829.3199

Computing standard errors ...

Mixed-effects REML regression                        Number of obs    =  1,200
Group variable: id                                   Number of groups =    300
                                                     Obs per group:
                                                                  min =      4
                                                                  avg =    4.0
                                                                  max =      4
                                                     Wald chi2(7)     = 460.58
Log restricted-likelihood = -3829.3199               Prob > chi2      = 0.0000

----------------------------------------------------------------------------------
           score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-----------------+----------------------------------------------------------------
             arm |
      treatment  |  -.2397333   .8462269    -0.28   0.777    -1.898308    1.418841
                 |
           visit |
              1  |    -1.9842   .4868589    -4.08   0.000    -2.938426   -1.029974
              2  |  -3.056333   .5534852    -5.52   0.000    -4.141144   -1.971522
              3  |     -5.208    .649515    -8.02   0.000    -6.481026   -3.934974
                 |
       arm#visit |
    treatment#1  |  -1.761667   .6885225    -2.56   0.011    -3.111146   -.4121874
    treatment#2  |  -4.987867   .7827463    -6.37   0.000    -6.522021   -3.453712
    treatment#3  |  -7.177467   .9185529    -7.81   0.000    -8.977797   -5.377136
                 |
           _cons |   50.16413   .5983728    83.83   0.000     48.99134    51.33692
----------------------------------------------------------------------------------

------------------------------------------------------------------------------
  Random-effects parameters  |   Estimate   Std. err.     [95% conf. interval]
-----------------------------+------------------------------------------------
id: Unstructured             |
                    sd(week) |   .4654107   .0387788      .3952873    .5479739
                   sd(_cons) |   6.137018   .3306216       5.52205    6.820472
            corr(week,_cons) |  -.1110897    .092756     -.2872992    .0723929
-----------------------------+------------------------------------------------
                sd(Residual) |    4.00556   .1160179      3.784503     4.23953
------------------------------------------------------------------------------
LR test vs. linear model: chi2(3) = 684.31                Prob > chi2 = 0.0000

Note: LR test is conservative and provided only for reference.

. * beta1 = 1.arm: the difference between arms at week 0, the reference visit.
. lincom 1.arm

 ( 1)  [score]1.arm = 0

------------------------------------------------------------------------------
       score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-------------+----------------------------------------------------------------
         (1) |  -.2397333   .8462269    -0.28   0.777    -1.898308    1.418841
------------------------------------------------------------------------------

. * beta3,3 = 1.arm#3.visit: the week-12 interaction, a difference in differences.
. lincom 1.arm#3.visit

 ( 1)  [score]1.arm#3.visit = 0

------------------------------------------------------------------------------
       score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-------------+----------------------------------------------------------------
         (1) |  -7.177467   .9185529    -7.81   0.000    -8.977797   -5.377136
------------------------------------------------------------------------------

. * Difference between arms at each visit, beta1 + beta3,k (k = 1, 2, 3 for weeks 4, 8, 12).
. contrast r.arm@visit, effects

Contrasts of marginal linear predictions

Margins: asbalanced

-------------------------------------------------------------
                          |         df        chi2     P>chi2
--------------------------+----------------------------------
score                     |
                arm@visit |
(treatment vs control) 0  |          1        0.08     0.7769
(treatment vs control) 1  |          1        5.50     0.0190
(treatment vs control) 2  |          1       32.80     0.0000
(treatment vs control) 3  |          1       53.39     0.0000
                   Joint  |          4       79.42     0.0000
-------------------------------------------------------------

-------------------------------------------------------------------------------------------
                          |   Contrast   Std. err.      z    P>|z|     [95% conf. interval]
--------------------------+----------------------------------------------------------------
score                     |
                arm@visit |
(treatment vs control) 0  |  -.2397333   .8462269    -0.28   0.777    -1.898308    1.418841
(treatment vs control) 1  |    -2.0014   .8535013    -2.34   0.019    -3.674232   -.3285682
(treatment vs control) 2  |    -5.2276   .9128241    -5.73   0.000    -7.016702   -3.438498
(treatment vs control) 3  |    -7.4172   1.015111    -7.31   0.000    -9.406781   -5.427619
-------------------------------------------------------------------------------------------

. forvalues k = 1/3 {
  2.     lincom 1.arm + 1.arm#`k'.visit
  3. }

 ( 1)  [score]1.arm + [score]1.arm#1.visit = 0

------------------------------------------------------------------------------
       score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-------------+----------------------------------------------------------------
         (1) |    -2.0014   .8535013    -2.34   0.019    -3.674232   -.3285682
------------------------------------------------------------------------------

 ( 1)  [score]1.arm + [score]1.arm#2.visit = 0

------------------------------------------------------------------------------
       score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-------------+----------------------------------------------------------------
         (1) |    -5.2276   .9128241    -5.73   0.000    -7.016702   -3.438498
------------------------------------------------------------------------------

 ( 1)  [score]1.arm + [score]1.arm#3.visit = 0

------------------------------------------------------------------------------
       score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-------------+----------------------------------------------------------------
         (1) |    -7.4172   1.015111    -7.31   0.000    -9.406781   -5.427619
------------------------------------------------------------------------------

. * Joint Wald test that the three interaction coefficients are zero.
. testparm 1.arm#i.visit

 ( 1)  [score]1.arm#1.visit = 0
 ( 2)  [score]1.arm#2.visit = 0
 ( 3)  [score]1.arm#3.visit = 0

           chi2(  3) =   70.56
         Prob > chi2 =    0.0000

.
. * ---------------------------------------------------------------- constrained baseline
. * Same random-effects structure, but one common baseline mean for both arms.
. generate byte trt_wk4 = arm * (visit == 1)

. generate byte trt_wk8 = arm * (visit == 2)

. generate byte trt_wk12 = arm * (visit == 3)

. mixed score i.visit trt_wk4 trt_wk8 trt_wk12 || id: week, covariance(unstructured) reml stddeviations

Performing EM optimization ...

Performing gradient-based optimization:
Iteration 0:  Log restricted-likelihood = -3830.1128
Iteration 1:  Log restricted-likelihood = -3830.1114
Iteration 2:  Log restricted-likelihood = -3830.1114

Computing standard errors ...

Mixed-effects REML regression                        Number of obs    =  1,200
Group variable: id                                   Number of groups =    300
                                                     Obs per group:
                                                                  min =      4
                                                                  avg =    4.0
                                                                  max =      4
                                                     Wald chi2(6)     = 460.62
Log restricted-likelihood = -3830.1114               Prob > chi2      = 0.0000

----------------------------------------------------------------------------------
           score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-----------------+----------------------------------------------------------------
           visit |
              1  |  -1.945501   .4673096    -4.16   0.000    -2.861411   -1.029591
              2  |  -3.014831   .5337274    -5.65   0.000    -4.060917   -1.968744
              3  |  -5.163694   .6303518    -8.19   0.000    -6.399161   -3.928227
                 |
         trt_wk4 |  -1.839065   .6320851    -2.91   0.004    -3.077929   -.6002009
         trt_wk8 |  -5.070871   .7258901    -6.99   0.000     -6.49359   -3.648153
        trt_wk12 |  -7.266078   .8636518    -8.41   0.000    -8.958804   -5.573352
           _cons |   50.04427   .4225711   118.43   0.000     49.21604    50.87249
----------------------------------------------------------------------------------

------------------------------------------------------------------------------
  Random-effects parameters  |   Estimate   Std. err.     [95% conf. interval]
-----------------------------+------------------------------------------------
id: Unstructured             |
                    sd(week) |   .4652983   .0387653      .3951986    .5478321
                   sd(_cons) |   6.125979   .3297757       5.51256    6.807657
            corr(week,_cons) |  -.1098813   .0927455     -.2861117    .0735397
-----------------------------+------------------------------------------------
                sd(Residual) |   4.005283   .1159944       3.78427    4.239204
------------------------------------------------------------------------------
LR test vs. linear model: chi2(3) = 684.45                Prob > chi2 = 0.0000

Note: LR test is conservative and provided only for reference.

. lincom trt_wk12

 ( 1)  [score]trt_wk12 = 0

------------------------------------------------------------------------------
       score | Coefficient  Std. err.      z    P>|z|     [95% conf. interval]
-------------+----------------------------------------------------------------
         (1) |  -7.266078   .8636518    -8.41   0.000    -8.958804   -5.573352
------------------------------------------------------------------------------

.
. * ---------------------------------------------------------------- week-12 ANCOVA and change score
. * Baseline score copied to every row of the participant.
. bysort id (visit): generate double score0 = score[1]

. generate double change = score - score0

. * ANCOVA: week-12 score on arm, adjusted for the baseline score (OLS).
. regress score i.arm score0 if visit == 3

      Source |       SS           df       MS      Number of obs   =       300
-------------+----------------------------------   F(2, 297)       =     96.75
       Model |  11054.4924         2  5527.24619   Prob > F        =    0.0000
    Residual |  16967.1828       297  57.1285616   R-squared       =    0.3945
-------------+----------------------------------   Adj R-squared   =    0.3904
       Total |  28021.6752       299  93.7179772   Root MSE        =    7.5583

------------------------------------------------------------------------------
       score | Coefficient  Std. err.      t    P>|t|     [95% conf. interval]
-------------+----------------------------------------------------------------
         arm |
  treatment  |   -7.25869   .8728811    -8.32   0.000    -8.976506   -5.540875
      score0 |   .6611917   .0600397    11.01   0.000     .5430346    .7793488
       _cons |   11.78802   3.074414     3.83   0.000     5.737628    17.83842
------------------------------------------------------------------------------

. * Change score: (week-12 minus week-0) on arm, no baseline adjustment (OLS).
. regress change i.arm if visit == 3

      Source |       SS           df       MS      Number of obs   =       300
-------------+----------------------------------   F(1, 298)       =     61.29
       Model |  3863.70208         1  3863.70208   Prob > F        =    0.0000
    Residual |  18786.4013       298  63.0416152   R-squared       =    0.1706
-------------+----------------------------------   Adj R-squared   =    0.1678
       Total |  22650.1034       299  75.7528542   Root MSE        =    7.9399

------------------------------------------------------------------------------
      change | Coefficient  Std. err.      t    P>|t|     [95% conf. interval]
-------------+----------------------------------------------------------------
         arm |
  treatment  |  -7.177467   .9168178    -7.83   0.000    -8.981724   -5.373209
       _cons |     -5.208   .6482881    -8.03   0.000    -6.483803   -3.932197
------------------------------------------------------------------------------
Simulated data, output of the code shown. The mixed command fits categorical time with a random intercept and slope by REML; contrast and lincom print the difference between arms at each visit, and testparm gives the joint test. The last three fits give the constrained-baseline, ANCOVA and change-score estimates at week 12. Every estimate, standard error and confidence interval in this article's model tables is printed in this output.

R: the same models with lme4

R code d2_lmm_r.R
# Simulated trial: 300 participants, 1:1, symptom score at weeks 0, 4, 8, 12 (lower is better).
# Simulated data only: nothing here is evidence about any real drug or patient.
suppressPackageStartupMessages(library(lme4))
z975 <- qnorm(0.975)

# Load the simulated data (long format: one row per participant-visit).
trial <- read.csv("trial.csv")
trial <- trial[order(trial$id, trial$visit), ]
trial$visitf <- factor(trial$visit)

# ---------------------------------------------------------------- mixed model, arm x visit
# Categorical visit, arm-by-visit interaction, random intercept and random slope on week (REML).
lmm <- lmer(score ~ arm * visitf + (week | id), data = trial, REML = TRUE)
print(summary(lmm), correlation = FALSE)
b <- fixef(lmm)
V <- as.matrix(vcov(lmm))
# Wald estimate, SE and 95% CI (normal) of a sum of coefficients.
lc <- function(terms) {
  L <- setNames(numeric(length(b)), names(b))
  L[terms] <- 1
  est <- sum(L * b)
  se <- sqrt(drop(t(L) %*% V %*% L))
  c(estimate = est, se = se, lo = est - z975 * se, hi = est + z975 * se)
}
# beta1 = arm: the difference between arms at week 0, the reference visit.
print(round(lc("arm"), 4))
# beta3,3 = arm:visitf3: the week-12 interaction, a difference in differences.
print(round(lc("arm:visitf3"), 4))
# Difference between arms at each visit, beta1 + beta3,k (k = 1, 2, 3 for weeks 4, 8, 12).
diffs <- t(sapply(0:3, function(k) lc(if (k == 0) "arm" else c("arm", paste0("arm:visitf", k)))))
rownames(diffs) <- paste("week", 4 * (0:3))
print(round(diffs, 4))
# Joint Wald test that the three interaction coefficients are zero.
idx <- paste0("arm:visitf", 1:3)
chi2 <- drop(t(b[idx]) %*% solve(V[idx, idx]) %*% b[idx])
cat(sprintf("Joint test: chi2(3) = %.4f, p = %.4g\n", chi2, pchisq(chi2, 3, lower.tail = FALSE)))

# ---------------------------------------------------------------- constrained baseline
# Same random-effects structure, but one common baseline mean for both arms.
trial$trt_wk4 <- trial$arm * (trial$visit == 1)
trial$trt_wk8 <- trial$arm * (trial$visit == 2)
trial$trt_wk12 <- trial$arm * (trial$visit == 3)
cb <- lmer(score ~ visitf + trt_wk4 + trt_wk8 + trt_wk12 + (week | id), data = trial, REML = TRUE)
est <- fixef(cb)[["trt_wk12"]]
se <- sqrt(as.matrix(vcov(cb))["trt_wk12", "trt_wk12"])
print(round(c(estimate = est, se = se, lo = est - z975 * se, hi = est + z975 * se), 4))

# ---------------------------------------------------------------- week-12 ANCOVA and change score
# One row per participant: baseline and week-12 scores side by side.
wide <- data.frame(id = trial$id[trial$visit == 0], arm = trial$arm[trial$visit == 0],
                   score0 = trial$score[trial$visit == 0], score12 = trial$score[trial$visit == 3])
# ANCOVA: week-12 score on arm, adjusted for the baseline score (OLS).
anc <- lm(score12 ~ arm + score0, data = wide)
print(summary(anc))
print(round(confint(anc), 4))
# Change score: (week-12 minus week-0) on arm, no baseline adjustment (OLS).
chg <- lm(I(score12 - score0) ~ arm, data = wide)
print(summary(chg))
print(round(confint(chg), 4))
Output of the run d2_lmm_r.log
> suppressPackageStartupMessages(library(lme4))

> z975 <- qnorm(0.975)

> trial <- read.csv("trial.csv")

> trial <- trial[order(trial$id, trial$visit), ]

> trial$visitf <- factor(trial$visit)

> lmm <- lmer(score ~ arm * visitf + (week | id), data = trial,
+     REML = TRUE)

> print(summary(lmm), correlation = FALSE)
Linear mixed model fit by REML ['lmerMod']
Formula: score ~ arm * visitf + (week | id)
   Data: trial

REML criterion at convergence: 7658.6

Scaled residuals:
    Min      1Q  Median      3Q     Max
-2.8884 -0.5185 -0.0007  0.5334  3.1753

Random effects:
 Groups   Name        Variance Std.Dev. Corr
 id       (Intercept) 37.6629  6.1370
          week         0.2166  0.4654   -0.11
 Residual             16.0445  4.0056
Number of obs: 1200, groups:  id, 300

Fixed effects:
            Estimate Std. Error t value
(Intercept)  50.1641     0.5984  83.834
arm          -0.2397     0.8462  -0.283
visitf1      -1.9842     0.4869  -4.076
visitf2      -3.0563     0.5535  -5.522
visitf3      -5.2080     0.6495  -8.018
arm:visitf1  -1.7617     0.6885  -2.559
arm:visitf2  -4.9879     0.7827  -6.372
arm:visitf3  -7.1775     0.9186  -7.814

> b <- fixef(lmm)

> V <- as.matrix(vcov(lmm))

> lc <- function(terms) {
+     L <- setNames(numeric(length(b)), names(b))
+     L[terms] <- 1
+     est <- sum(L * b)
+     se <- sqrt(drop(t(L) %*% V %*% L))
+     c(estimate = est, se = se, lo = est - z975 * se, hi = est +
+         z975 * se)
+ }

> print(round(lc("arm"), 4))
estimate       se       lo       hi
 -0.2397   0.8462  -1.8983   1.4188

> print(round(lc("arm:visitf3"), 4))
estimate       se       lo       hi
 -7.1775   0.9186  -8.9778  -5.3771

> diffs <- t(sapply(0:3, function(k) lc(if (k == 0) "arm" else c("arm",
+     paste0("arm:visitf", k)))))

> rownames(diffs) <- paste("week", 4 * (0:3))

> print(round(diffs, 4))
        estimate     se      lo      hi
week 0   -0.2397 0.8462 -1.8983  1.4188
week 4   -2.0014 0.8535 -3.6742 -0.3286
week 8   -5.2276 0.9128 -7.0167 -3.4385
week 12  -7.4172 1.0151 -9.4068 -5.4276

> idx <- paste0("arm:visitf", 1:3)

> chi2 <- drop(t(b[idx]) %*% solve(V[idx, idx]) %*%
+     b[idx])

> cat(sprintf("Joint test: chi2(3) = %.4f, p = %.4g\n",
+     chi2, pchisq(chi2, 3, lower.tail = FALSE)))
Joint test: chi2(3) = 70.5554, p = 3.246e-15

> trial$trt_wk4 <- trial$arm * (trial$visit == 1)

> trial$trt_wk8 <- trial$arm * (trial$visit == 2)

> trial$trt_wk12 <- trial$arm * (trial$visit == 3)

> cb <- lmer(score ~ visitf + trt_wk4 + trt_wk8 + trt_wk12 +
+     (week | id), data = trial, REML = TRUE)

> est <- fixef(cb)[["trt_wk12"]]

> se <- sqrt(as.matrix(vcov(cb))["trt_wk12", "trt_wk12"])

> print(round(c(estimate = est, se = se, lo = est -
+     z975 * se, hi = est + z975 * se), 4))
estimate       se       lo       hi
 -7.2661   0.8636  -8.9588  -5.5734

> wide <- data.frame(id = trial$id[trial$visit == 0],
+     arm = trial$arm[trial$visit == 0], score0 = trial$score[trial$visit ==
+         0], score12 = trial$score[trial$visit == 3])

> anc <- lm(score12 ~ arm + score0, data = wide)

> print(summary(anc))

Call:
lm(formula = score12 ~ arm + score0, data = wide)

Residuals:
     Min       1Q   Median       3Q      Max
-24.6458  -5.1035   0.8545   4.7741  15.7149

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept) 11.78802    3.07441   3.834 0.000154 ***
arm         -7.25869    0.87288  -8.316 3.32e-15 ***
score0       0.66119    0.06004  11.013  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 7.558 on 297 degrees of freedom
Multiple R-squared:  0.3945,	Adjusted R-squared:  0.3904
F-statistic: 96.75 on 2 and 297 DF,  p-value: < 2.2e-16


> print(round(confint(anc), 4))
              2.5 %  97.5 %
(Intercept)  5.7376 17.8384
arm         -8.9765 -5.5409
score0       0.5430  0.7793

> chg <- lm(I(score12 - score0) ~ arm, data = wide)

> print(summary(chg))

Call:
lm(formula = I(score12 - score0) ~ arm, data = wide)

Residuals:
     Min       1Q   Median       3Q      Max
-25.0045  -5.0189   0.9755   5.0555  16.9255

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)  -5.2080     0.6483  -8.033 2.23e-14 ***
arm          -7.1775     0.9168  -7.829 8.69e-14 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 7.94 on 298 degrees of freedom
Multiple R-squared:  0.1706,	Adjusted R-squared:  0.1678
F-statistic: 61.29 on 1 and 298 DF,  p-value: 8.689e-14


> print(round(confint(chg), 4))
              2.5 %  97.5 %
(Intercept) -6.4838 -3.9322
arm         -8.9817 -5.3732
Simulated data, output of the code shown. The lmer function fits the same model, and the sums of coefficients written out by hand reproduce the Stata contrasts. The joint test, the constrained baseline, ANCOVA and the change score agree with the Stata output.

Three ways to use the week-0 score

A trial that measures the outcome at baseline can use that score in at least three ways when the target is the week-12 difference [2, 3].

In a randomised trial all three target the same week-12 difference, because the expected baseline difference is zero. They differ in how they treat the chance baseline difference, and so in precision.

Week-12 difference between arms by baseline method

Simulated data; the true value is -6 points. The baseline methods agree closely. ANCOVA and the constrained baseline have the narrowest intervals, and the unadjusted contrast has the widest.
MethodEstimate (points)Standard error (points)95% CI (points)
Mixed model, unadjusted contrast at week 12-7.421.02-9.41 to -5.43
ANCOVA-7.260.87-8.98 to -5.54
Change score-7.180.92-8.98 to -5.37
Constrained baseline-7.270.86-8.96 to -5.57

How the three estimates are linked

For these complete data the links are exact. The change-score estimate, -7.18, equals $\hat\beta_{3,3}$, since both are the treatment-arm change minus the control-arm change. The change-score interval differs in the second decimal because it comes from a separate regression.

The ANCOVA estimate equals the raw week-12 difference minus 0.66 times the baseline difference, where 0.66 is the fitted baseline coefficient. A change score fixes that multiplier at 1.

Because ANCOVA estimates the multiplier from the data, it is usually the most precise of the simple approaches [2]. The constrained-baseline estimate, -7.27, landed close to ANCOVA with a similar standard error.

The unadjusted week-12 contrast from the mixed model has the largest standard error, 1.02 points, and the widest interval. It compares the week-12 means directly and ignores the information in the baseline score, which ANCOVA and the constrained baseline use to remove part of the chance variation.

The correlation between visits, and what it changes when visits are missing

Scores from one participant are correlated: someone who starts high tends to stay high. Treating 1,200 rows as 1,200 independent people would misstate the standard errors, so the model needs a covariance structure for the scores across visits.

The model above uses a random intercept and slope with an unstructured covariance between them, so their variances and correlation are estimated freely. The estimated standard deviations are 6.14 points for intercepts and 0.47 points per week for slopes. Their correlation is -0.11, and the residual standard deviation is 4.01 points.

A widely used alternative is the MMRM, a mixed model for repeated measures. It keeps categorical time, drops the random effects and puts an unstructured covariance on the residuals. Each visit gets its own variance and each pair of visits its own correlation [1].

With complete data and a saturated mean model, both choices give the same point estimates and differ only in standard errors. With missing visits the estimates move too. A likelihood-based model picks the parameter values that make the observed scores most probable. It uses every observed visit of each participant, so it borrows strength from them.

Borrowing strength from observed visits is valid under missing at random (MAR): whether a visit is missing depends only on data already observed. It also needs the mean and covariance models to be correctly specified. A random intercept and slope that fit the data poorly can therefore shift the week-12 contrast when visits are missing. This is one reason an unstructured covariance across visits is often prespecified when dropout is expected [1].

Name the visit in the estimand

An estimand is the precise quantity a study aims to estimate. The ICH E9(R1) addendum describes it by five attributes: the treatment, the population, the variable (the outcome measured), the handling of intercurrent events, and the population-level summary [4]. Intercurrent events are events after treatment starts, such as stopping treatment or taking extra medication, that affect whether the outcome can be measured or how it is read.

In a four-visit trial, "the treatment effect" is not yet an estimand, because three post-baseline differences need not agree. A usable statement compares treatment with control in the randomised population, takes the symptom score at week 12 as the variable, and summarises it as the difference in mean score between arms. A full estimand also says how intercurrent events are handled.

Once the visit is named, the estimate is the contrast at that visit: $\hat\beta_1 + \hat\beta_{3,k}$, or the ANCOVA arm coefficient. An average over weeks 4, 8 and 12 is a different estimand, computed as a linear combination, meaning a weighted sum of the coefficients (here the average of the three post-baseline differences, with its own confidence interval).

Common misreadings and their fixes

  • "beta1 is the treatment effect."

    With an interaction, the arm coefficient is read at the reference visit. At a pre-treatment baseline it measures chance imbalance.

    Fix: In a model with arm, visit and their interaction, beta1 is the difference between arms at the reference visit. The treatment effect at a later visit is beta1 plus that visit's interaction coefficient, and the estimand must name the visit.

  • "beta3 is always the treatment effect."

    In a randomised trial with a pre-treatment baseline, $\hat\beta_{3,k}$ is the change-score estimate of the same week-$k$ difference: -7.18 points at week 12, against -7.42 for $\hat\beta_1 + \hat\beta_{3,3}$. The two differ only by the chance baseline imbalance, and ANCOVA (-7.26) or the constrained baseline (-7.27) is usually more precise. Reading $\beta_{3,k}$ alone as the effect is wrong when the groups are not randomised, when the reference visit comes after treatment starts, or when the baseline is not measured before treatment.

    Fix: With a baseline visit, the treatment effect at a later visit is the sum $\beta_1 + \beta_{3,k}$, which equals $\beta_{3,k}$ only when $\beta_1 = 0$.

  • "The arm coefficient is the average effect across all visits."

    With an interaction in the model, no single coefficient applies to every visit.

    Fix: Name the average as its own estimand, and compute it as a linear combination with its own confidence interval.

  • "The arm coefficient is the effect at the final visit."

    Only if the final visit is the reference level. Recoding changes the coefficient, not the fitted means.

    Fix: Check the reference visit, or report the contrast at the named visit, which does not depend on coding.

  • "The visit coefficients show how the treatment works over time."

    Each $\beta_{2,k}$ is the change from baseline in the control arm only.

    Fix: The change in the treatment arm is $\beta_{2,k} + \beta_{3,k}$.

  • "Dropping the interaction gives one common treatment effect."

    With a pre-treatment baseline visit in the model, this forces the week-0 difference to equal every later difference. The single coefficient then blends a baseline difference that is zero by design with the later ones, typically pulling it toward zero.

    Fix: Keep the interaction, or adjust for the baseline score and model only the post-baseline visits, stating any common effect as an assumption.

  • "The covariance model does not matter, because the estimates do not change."

    That holds only for complete data with categorical time, and even then the standard errors differ.

    Fix: Prespecify the covariance model and report it with the results.

What to do in your own analysis

Glossary

treatment-by-time interaction (ปฏิกิริยาสัมพันธ์ระหว่างการรักษากับเวลา)
The model term that lets the difference between arms change across visits.
difference in differences
The change in the treatment arm minus the change in the control arm.
categorical time
Each visit coded as its own category, with no assumed trajectory shape.
MMRM (แบบจำลองผสมสำหรับการวัดซ้ำ)
Mixed model for repeated measures: categorical visit, treatment-by-visit terms and an unstructured covariance for the repeated outcomes.
unstructured covariance
A covariance model whose variances and correlations are all estimated freely.
ANCOVA
Analysis of covariance: the follow-up score regressed on arm and the baseline score.
change score
The follow-up score minus the baseline score, compared between arms.
constrained baseline
A longitudinal model with one common baseline mean for both arms.
estimand (ปริมาณเป้าหมายของการประมาณ)
The precise quantity a study aims to estimate, described in ICH E9(R1) by the treatment, the population, the variable, the handling of intercurrent events and the population-level summary.

References

  1. Fitzmaurice GM, Laird NM, Ware JH. Applied longitudinal analysis. 2nd ed. Wiley; 2011. doi:10.1002/9781119513469 https://doi.org/10.1002/9781119513469
  2. Vickers AJ, Altman DG. Analysing controlled trials with baseline and follow up measurements. BMJ. 2001;323(7321):1123-1124. doi:10.1136/bmj.323.7321.1123 https://doi.org/10.1136/bmj.323.7321.1123
  3. Twisk J, Bosman L, Hoekstra T, Rijnhart J, Welten M, Heymans M. Different ways to estimate treatment effects in randomised controlled trials. Contemp Clin Trials Commun. 2018;10:80-85. doi:10.1016/j.conctc.2018.03.008 https://doi.org/10.1016/j.conctc.2018.03.008
  4. International Council for Harmonisation (ICH). ICH E9(R1): Addendum on estimands and sensitivity analysis in clinical trials to the guideline on statistical principles for clinical trials. ICH Harmonised Guideline, Step 4; 2019. https://database.ich.org/sites/default/files/E9-R1_Step4_Guideline_2019_1203.pdf

Key takeaways

  • In a model with arm, visit and their interaction, the arm coefficient is the difference between arms at the reference visit.
  • The difference between arms at a later visit is the arm coefficient plus that visit's interaction coefficient.
  • Categorical time assumes no trajectory shape, while linear time uses one slope difference and assumes straight lines.
  • ANCOVA, change score and constrained baseline target the same week-12 difference in a randomised trial and differ mainly in precision.
  • Name the visit in the estimand and state the covariance model with the result.

Related in the wiki: [[repeated-measures-modeling-guide]] [[mixed-model-series-guide]]

0
Message for International and Thai ReadersUnderstanding My Medical Context in ThailandRead more →Message for International and Thai ReadersUnderstanding My Broader Content Beyond MedicineRead more →

Comments

No comments yet. Be the first to share your thoughts.

Sign in to comment

Treatment-by-Time Interaction: Which Coefficient Is the Treatment Effect? — Uniqcret