Introduction
Interrupted time series analysis (ITSA) is a study design used to study the effects of an intervention across time. An important feature of the ITSA is the time when the intervention occurs. The time before and after the intervention are of interest because we want to visualize if the trends are similar or different. Additionally, we want to visualize the change immediately after the intervention is implemented. I call this period the index date.
In this article, I’ll review the single-group ITSA and multiple
groups ITSA. Then I’ll review how to perform an ITSA in
Stata
.
Single-group ITSA
Let’s look at Figure 1 and visualize an ITSA (this
is a modified version based on Linden’s
paper; I highly encourage you to read his paper to learn more about
ITSA for Stata
). Figure 1 illustrates the
basic features of a single-group ITSA. The single group has an
increasing slope in the period before the intervention and then there is
a jump in the level immediately after the intervention at the index date
\(X\) followed by a steeper slope in
the period after the intervention.
The structure of the ITSA is written as:
\(Y_i = \beta_0 + \beta_1(T_i) + \beta_2(X_i) + \beta_3(T_i * X_i) + \epsilon_i\),
where \(Y_i\) denotes the dependent variable or outcome of interest, \(\beta_0\) denotes the intercept, \(\beta_1\) denotes the change outcome due to a one-unit change in \(T_i\), \(\beta_2\) denotes the change in outcome due to a change in \(X_i\) (which is another way of saying that this is the chance in the outcome when a subject goes from the before \(X\) period to the after \(X\) period), \(\beta_3\) denotes the differences in the trends (e.g., slopes) after and before the intervention \(X\), \(T_i\) denotes the time for the \(i\)-th subject, \(X_i\) denotes the index date when the intervention was implemented, and \(\epsilon_i\) denotes the error term. The dash line denotes the counterfactual.
Multiple groups ITSA
Things get a little more complicated when we have more than one group in the ITSA. Let’s take a look at Figure 2, which provides an ITSA for two groups. The first group is the same one from Figure 1, which we’ll call the control. The new group is the Treatment group, which we denote as \(G\). We can see that the Treatment group starts out lower than the Control group and has a less steep slope. We also can see that immediately after implementation of the intervention at the index date \(X\), there is a jump in the level and the slope increases.
The regression model can be expanded to include the Treatment group:
\(Y_i = \beta_0 + \beta_1(T_i) + \beta_2(X_i) + \beta_3(T_i * X_i) + \beta_4(G_i) + \beta_5(G_i * T_i) + \beta_6(G_i * X_i) + \beta_7(G_i * T_i * X_i) + \epsilon_i\),
where \(G_i\) is a new variable that denotes the groups, \(\beta_4\) denotes the difference in the outcomes between the groups at beginning of the study (\(T = 0\)), \(\beta_5\) denotes the difference in the slopes between the groups before the intervention, \(\beta_6\) denotes the difference in the level changes between the groups immediately after implementation of the intervention \(X\), and \(\beta_7\) denotes the difference in the slopes after and before the intervention between the groups (e.g., difference-in-differences).
ITSA with Stata
We will use Stata
to explore how to perform an ITSA.
First, we will need to download the data. You can download the data from my GitHub site.
The sleep_cat3pw.dta
comes from the excellent text book
by Michael N. Mitchell, whcih you can find on the Stata
website (link).
(Note: I have the first edition where this data came from. The link is
for the second edition of the text.)
Once you’ve downloaded the data, you can load it onto
Stata
. Make sure you use the correct path. Here is an
example of how I loaded the sleep_cat3pw.dta
onto
Stata
.
clear all
cd "C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stata\ivrm2"
use sleep_cat3pw.dta, replace
C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stat
> a\ivrm2
Once you’ve loaded the data, let’s take a look using the
summarize
command.
summarize
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Variable | Obs Mean Std. dev. Min Max
-------------+---------------------------------------------------------
id | 600 38 21.66677 1 75
group | 600 2 .8171778 1 3
obsday | 600 23.815 15.02877 1 54
sleep | 600 362.4817 39.72333 207 531
The data sleep_cat3pw.dta
contains information on the
amount of sleep for subjects in a study. The amount of sleep was
captured once per week for a total of eight weeks. This means that a
subject can have their sleep captured any day between Sunday and
Saturday for each week. For example Subject A can have their sleep
measured on Monday of Week 1, and Subject B can have their sleep
measured on Wednesday of Week 1. This corresponds to Day 2 for Subject A
and Day 4 for Subject B. You will notice that the days correspond to
when the subject’s sleep was measured for that week.
The data contains four variables:
id
: This unique identifier of the subjectgroup
: Intervention group (Control, Medication, and Education)obsday
: The observation day when the sleep measurement was capturedsleep
: Duration of sleep (minutes)
There are there groups in the sleep_cat3pw.dta
data:
Control, Medication, and Education.
The Control denotes the subjects who did not receive an intervention.
The Medication denotes the subjects who received a medication for their sleep.
The Education denotes the subjects who received education to help them with their sleep.
You can view the number of observations for each group using the
tabulate
command in Stata
.
tabulate group, m
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Treatment |
group | Freq. Percent Cum.
------------+-----------------------------------
Control | 200 33.33 33.33
Medication | 200 33.33 66.67
Education | 200 33.33 100.00
------------+-----------------------------------
Total | 600 100.00
The time variable is obsday
, which is the day when the
measurement (sleep duration) was captured.
The outcome variable is sleep
, which is the duration
(minutes) of sleep that the subject experienced during that week of the
study.
We can view the data structure for a subject in each of the three
groups using the list
command:
list if id == 12 | id == 45 | id == 68
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
+----------------------------------+
| id group obsday sleep |
|----------------------------------|
89. | 12 Control 1 360 |
90. | 12 Control 8 356 |
91. | 12 Control 14 342 |
92. | 12 Control 20 360 |
93. | 12 Control 26 366 |
|----------------------------------|
94. | 12 Control 32 350 |
95. | 12 Control 38 383 |
96. | 12 Control 45 385 |
353. | 45 Medication 1 332 |
354. | 45 Medication 7 338 |
|----------------------------------|
355. | 45 Medication 13 349 |
356. | 45 Medication 18 357 |
357. | 45 Medication 26 370 |
358. | 45 Medication 32 415 |
359. | 45 Medication 37 402 |
|----------------------------------|
360. | 45 Medication 44 413 |
537. | 68 Education 1 360 |
538. | 68 Education 6 358 |
539. | 68 Education 13 367 |
540. | 68 Education 19 358 |
|----------------------------------|
541. | 68 Education 25 368 |
542. | 68 Education 33 389 |
543. | 68 Education 40 424 |
544. | 68 Education 46 419 |
+----------------------------------+
Notice that the days when the sleep measurement was captured varies between the subjects. However, they all occurred within the same corresponding week.
Conducting an ITSA in Stata
I know two methods to perform an ITSA in Stata
. The
first method uses the mkplines
command and the second uses
several interaction terms.
The first ITSA example will be a single-group ITSA.
The second ITSA example will be a multiple groups ITSA.
Single-group ITSA
To start off, we’ll go over how to construct an ITSA model with a single group. This will get us comfortable with understanding the parameters that estimates the slopes before and after the intervention, the level change immediately after the intervention, and the differences in the slopes after and before the intervention.
Method 1: Splines
The splines method takes advantage of the mkspline
command which will generate several new variables that take into
consideration the time after the intervention. This makes interpretation
of the coefficients easier than using a lot of interaction terms.
To begin, we need to figure out where on the X-axis the intervention
occurred. In the sleep_cat3pw.dta
data, the intervention
occurred at day 31 (obsday = 31
). We will use the
mkspline
command to create a knot at
obsday = 31
. These knots are the same as time sequences or
intervals. They help to keep track of when to start the clock with
respect to the index date. For example, knot1
should
correspond to the main time variable obsday
, but
knot2
should restart the clock to start after the
implementation of the intervention.
But before we do, we only want to keep the Control group for the single-ITSA example. Let’s put all these into a code chunk:
// Keep only the control group
keep if group == 1
// Use mkspline to create knots. We will create a knot at obsday = 31 (index date)
/* The marginal option => estimate the change in slope b/w knot2 v. knot1 */
mkspline knot1 31 knot2 = obsday, marginal
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
(400 observations deleted)
Once the knots have been created, we want to create a variable that partitions time periods to before and after the implementation of the intervention. Since there are only two time periods (before the intervention and after the intervention), we will create a binary indicator.
// Create a variable to separate the treatment periods.
gen period = .
replace period = 0 if obsday < 31 /* Baseline phase */
replace period = 1 if obsday >= 31 & !missing(obsday) /* Treatment phase */
tab period, m
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
(200 missing values generated)
(126 real changes made)
(74 real changes made)
period | Freq. Percent Cum.
------------+-----------------------------------
0 | 126 63.00 63.00
1 | 74 37.00 100.00
------------+-----------------------------------
Total | 200 100.00
Let’s take a look at the date. Notice the sequence of the numbers for
knot1
, knot2
and period
.
knot1
should reflect the obsday
variable
exactly, but knot2
restarts the time to after the
implementation of the intervention, and period
should be
0
during the period before the intervention and
1
after the intervention.
list if id == 1 | id == 3 | id == 6
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
+--------------------------------------------------------+
| id group obsday sleep knot1 knot2 period |
|--------------------------------------------------------|
1. | 1 Control 1 353 1 0 0 |
2. | 1 Control 9 345 9 0 0 |
3. | 1 Control 15 340 15 0 0 |
4. | 1 Control 21 337 21 0 0 |
5. | 1 Control 26 324 26 0 0 |
|--------------------------------------------------------|
6. | 1 Control 33 332 33 2 1 |
7. | 1 Control 41 326 41 10 1 |
8. | 1 Control 49 329 49 18 1 |
17. | 3 Control 1 345 1 0 0 |
18. | 3 Control 9 360 9 0 0 |
|--------------------------------------------------------|
19. | 3 Control 16 347 16 0 0 |
20. | 3 Control 24 348 24 0 0 |
21. | 3 Control 29 351 29 0 0 |
22. | 3 Control 37 348 37 6 1 |
23. | 3 Control 44 334 44 13 1 |
|--------------------------------------------------------|
24. | 3 Control 50 335 50 19 1 |
41. | 6 Control 1 353 1 0 0 |
42. | 6 Control 8 340 8 0 0 |
43. | 6 Control 15 334 15 0 0 |
44. | 6 Control 22 330 22 0 0 |
|--------------------------------------------------------|
45. | 6 Control 28 327 28 0 0 |
46. | 6 Control 35 306 35 4 1 |
47. | 6 Control 41 321 41 10 1 |
48. | 6 Control 49 319 49 18 1 |
+--------------------------------------------------------+
Linear mixed effects model - Using splines
Now that we have our necessary variables, we can begin to construct our ITSA model. We will use the linear mixed effects model for this ITSA. You can use other models such as the generalized estimating equation (GEE) model or a simple linear regression. I chose to use the linear mixed effects model because this was the one that Mitchell used in his textbook, but also because I was working on another study that used a similar model using triple interaction terms, and I wanted to see if I can replicate this result. (Note: In Method 2, we will see that we generate the same answers.)
After the model completes, it is a good idea to use the
predict
command to estimate the outcomes for each subject,
which will generate a new column called linear_spline
. We
will use this to plot our results.
// Linear mixed effects model for the single-group ITSA
xtmixed sleep i.period c.knot1 c.knot2 || id: period knot1 knot2, covariance(unstructured)
predict linear_spline
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Performing EM optimization:
Performing gradient-based optimization:
Iteration 0: Log likelihood = -815.91977
Iteration 1: Log likelihood = -815.91239
Iteration 2: Log likelihood = -815.91238
Computing standard errors:
Mixed-effects ML regression Number of obs = 200
Group variable: id Number of groups = 25
Obs per group:
min = 8
avg = 8.0
max = 8
Wald chi2(3) = 2.16
Log likelihood = -815.91238 Prob > chi2 = 0.5404
------------------------------------------------------------------------------
sleep | Coefficient Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
1.period | -4.061266 3.17595 -1.28 0.201 -10.28601 2.163481
knot1 | -.0393757 .3208933 -0.12 0.902 -.668315 .5895635
knot2 | -.1248309 .4277671 -0.29 0.770 -.963239 .7135771
_cons | 351.3585 2.465165 142.53 0.000 346.5268 356.1901
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Random-effects parameters | Estimate Std. err. [95% conf. interval]
-----------------------------+------------------------------------------------
id: Unstructured |
sd(period) | 10.22294 3.868926 4.868934 21.46434
sd(knot1) | 1.553309 .2347396 1.155108 2.088784
sd(knot2) | 1.896657 .3445179 1.328533 2.707728
sd(_cons) | 10.30786 2.098042 6.916981 15.36104
corr(period,knot1) | -.389369 .2899772 -.7935565 .2532219
corr(period,knot2) | .5930494 .3983103 -.4791216 .9550717
corr(period,_cons) | .1307331 .3606115 -.5281599 .6913624
corr(knot1,knot2) | -.5681853 .1626752 -.8060611 -.1722627
corr(knot1,_cons) | .077858 .2518023 -.3956807 .5186924
corr(knot2,_cons) | -.1536023 .2735296 -.6068313 .3750053
-----------------------------+------------------------------------------------
sd(Residual) | 8.254314 .6082031 7.144336 9.536744
------------------------------------------------------------------------------
LR test vs. linear model: chi2(10) = 421.77 Prob > chi2 = 0.0000
Note: LR test is conservative and provided only for reference.
(option xb assumed)
We can plot the predicted lines. Notice that the slope in the period before the intervention is slightly negative. Then, at the index date (immediately after the intervention) there is a level decrease or drop followed by a steeper negative slope in the period after the intervention.
*** Plot single-group ITSA
graph twoway (lfit linear_spline obsday if group == 1 & period == 0, lcol(navy)) ///
(lfit linear_spline obsday if group == 1 & period == 1, lcol(navy) ///
xline(31) ///
legend(order(1 "Before intervention" 2 "After intervention")))
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Slope before the intervention
To estimate the slope before the intervention, we can use the
margins
command:
margins, dydx(knot1) /* Slope before the intervention */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 200
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: knot1
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
knot1 | -.0393757 .3208933 -0.12 0.902 -.668315 .5895635
------------------------------------------------------------------------------
The slope in the period before the intervention was -0.04 minutes per week (95% CI: -0.67, 0.59), which was not statistically significant. Since the slope is negative, this means that the predicted fit should also decrease. We can confirm this with the figure above.
Level change immediately after the intervention
To estimate the level change immediately after the intervention, we
can use the margins
command:
margins, dydx(period) /* Level change immediately after the intervention */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 200
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: 1.period
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
1.period | -4.061266 3.17595 -1.28 0.201 -10.28601 2.163481
------------------------------------------------------------------------------
Note: dy/dx for factor levels is the discrete change from the base level.
The sleep duration dropped by -4.06 minutes (95% CI: -10.29, 2.16) at
obsday = 31
, but this was not statistically
significant.
Comparing the Slopes after the intervention
The slope after the intervention can be estimated in two ways using
(1) margins
command and (2) lincom
command:
/* Slope after the intervention */
margins, expression(_b[knot1] + _b[knot2]) /* Method 1 */
lincom knot1+knot2 /* Method 2 */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
warning: option expression() does not contain option predict() or xb().
warning: prediction constant over observations.
Predictive margins Number of obs = 200
Expression: _b[knot1] + _b[knot2]
------------------------------------------------------------------------------
| Delta-method
| Margin std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
_cons | -.1642067 .3733492 -0.44 0.660 -.8959576 .5675442
------------------------------------------------------------------------------
( 1) [sleep]knot1 + [sleep]knot2 = 0
------------------------------------------------------------------------------
sleep | Coefficient Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
(1) | -.1642067 .3733492 -0.44 0.660 -.8959576 .5675442
------------------------------------------------------------------------------
The slope after the intervention was decreasing by -0.16 minutes per week (95% CI: -0.90, 0.57), which was not statistically significant.
Difference in slopes after and before the intervention
The differences in the slopes after and before the intervention can
be estimated using the margins
command with the
pwcompare(effects)
option:
margins, dydx(knot2) /* Diff in slopes after and before the intervention */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 200
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: knot2
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
knot2 | -.1248309 .4277671 -0.29 0.770 -.963239 .7135771
------------------------------------------------------------------------------
The slope in the period after the intervention has a greater decrease compared to the slope in the period before the intervention by -0.12 minutes per week (95% CI: -0.96, 0.71), which is not statistically significant. In other words, the sleep duration was decreasing at a faster rate after the intervention compared to before.
Method 2: Using an interaction term
The mkspline
method makes it easy to perform an ITSA in
Stata
. However, we can do a lot of the
mkspline
work ourselves using interaction terms,
particularly the interaction between the group
and
obsday
variables. We also want to restrict our sample to
the Control group.
Let’s start over and reload the data:
clear all
cd "C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stata\ivrm2"
use sleep_cat3pw.dta, replace
// Keep only the control group
keep if group == 1
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stat
> a\ivrm2
(400 observations deleted)
Next, we want to create a variable that partitions time periods to before and after the implementation of the intervention. Since there are only two time periods (before the intervention and after the intervention), we will create a binary indicator.
// Create a variable to separate the treatment periods.
gen period = .
replace period = 0 if obsday < 31 /* Baseline phase */
replace period = 1 if obsday >= 31 & !missing(obsday) /* Treatment phase */
tab period, m
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
(200 missing values generated)
(126 real changes made)
(74 real changes made)
period | Freq. Percent Cum.
------------+-----------------------------------
0 | 126 63.00 63.00
1 | 74 37.00 100.00
------------+-----------------------------------
Total | 200 100.00
Linear mixed effects model - Using an interaction term
Now that we have our necessary variables, we can begin to construct
our ITSA model. We’ll construct the same type of model: linear mixed
effects model. We’ll also created fitted values using the
predict linear_int
command. Not how the interaction terms
are constructed:
// Linear mixed effects model for the single-group ITSA
xtmixed sleep i.period c.obsday i.period#c.obsday || id: period obsday i.period#c.obsday, covariance(unstructured)
predict linear_int
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Performing EM optimization:
Performing gradient-based optimization:
Iteration 0: Log likelihood = -819.10509
Iteration 1: Log likelihood = -816.20946 (not concave)
Iteration 2: Log likelihood = -815.98347
Iteration 3: Log likelihood = -815.91256
Iteration 4: Log likelihood = -815.91238
Iteration 5: Log likelihood = -815.91238
Computing standard errors:
Mixed-effects ML regression Number of obs = 200
Group variable: id Number of groups = 25
Obs per group:
min = 8
avg = 8.0
max = 8
Wald chi2(3) = 2.16
Log likelihood = -815.91238 Prob > chi2 = 0.5404
------------------------------------------------------------------------------
sleep | Coefficient Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
1.period | -.1915202 12.97583 -0.01 0.988 -25.62367 25.24063
obsday | -.0393758 .3208933 -0.12 0.902 -.6683152 .5895636
|
period#|
c.obsday |
1 | -.1248306 .427767 -0.29 0.770 -.9632385 .7135773
|
_cons | 351.3585 2.465166 142.53 0.000 346.5268 356.1901
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Random-effects parameters | Estimate Std. err. [95% conf. interval]
-----------------------------+------------------------------------------------
id: Unstructured |
sd(period) | 53.37212 11.43859 35.06605 81.23479
sd(obsday) | 1.55331 .2347451 1.1551 2.088798
sd(1.period#obsday) | 1.896656 .3445258 1.328522 2.70775
sd(_cons) | 10.30787 2.098045 6.916985 15.36105
corr(period,obsday) | .5513518 .1901583 .0846336 .8196685
corr(period,1.period#obsday) | -.9880365 .0144753 -.9988931 -.8772388
corr(period,_cons) | .1942535 .2899708 -.3746878 .6569181
corr(obsday,1.period#obsday) | -.5681866 .1627069 -.8060944 -.1721743
corr(obsday,_cons) | .0778578 .2518162 -.395704 .5187123
corr(1.period#obsday,_cons) | -.1536021 .2735914 -.6069096 .3751121
-----------------------------+------------------------------------------------
sd(Residual) | 8.254318 .6082069 7.144333 9.536756
------------------------------------------------------------------------------
LR test vs. linear model: chi2(10) = 421.77 Prob > chi2 = 0.0000
Note: LR test is conservative and provided only for reference.
(option xb assumed)
*** Plot single-group ITSA
graph twoway (lfit linear_int obsday if group == 1 & period == 0, lcol(navy)) ///
(lfit linear_int obsday if group == 1 & period == 1, lcol(navy) ///
xline(31) ///
legend(order(1 "Before intervention" 2 "After intervention")))
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
The figure looks exactly the same as the one created with the
mkspline
method.
Slope before the intervention
To estimate the slope before the intervention, we can use the
margins
command. We have to use the if
statement to limit the estimation to the period before the intervention
\(obsday < 31\):
margins if obsday < 31, dydx(obsday) /* Slope before the intervention */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 126
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday | -.0393758 .3208933 -0.12 0.902 -.6683152 .5895636
------------------------------------------------------------------------------
This is exactly the same as the slope we estimate with the
mkpline
approach. The slope in the period before the
intervention was -0.04 minutes per week (95% CI: -0.67, 0.59), which was
not statistically significant. Since the slope is negative, this means
that the predicted fit should also decrease. We can confirm this with
the figure above.
Level change immediately after the intervention
To estimate the level change immediately after the intervention, we
can use the margins
command. We have to use the
at
operator to estimate the level change at
obsday = 31
:
margins, dydx(period) at(obsday = 31) /* Estimate the level change at obsday == 31 */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Conditional marginal effects Number of obs = 200
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: 1.period
At: obsday = 31
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
1.period | -4.061269 3.175945 -1.28 0.201 -10.28601 2.163468
------------------------------------------------------------------------------
Note: dy/dx for factor levels is the discrete change from the base level.
This is exactly the same as the slope we estimate with the
mkpline
approach. The sleep duration dropped by -4.06
minutes (95% CI: -10.29, 2.16) at obsday = 31
, but this was
not statistically significant.
Slope after the intervention
The slope after the intervention can be estimated in two ways using
(1) margins
command and (2) lincom
command:
/* Slope after the intervention */
margins, expression(_b[obsday] + _b[1.period#c.obsday]) /* Method 1 */
lincom obsday + 1.period#c.obsday /* Method 2 */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
warning: option expression() does not contain option predict() or xb().
warning: prediction constant over observations.
Predictive margins Number of obs = 200
Expression: _b[obsday] + _b[1.period#c.obsday]
------------------------------------------------------------------------------
| Delta-method
| Margin std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
_cons | -.1642064 .3733487 -0.44 0.660 -.8959565 .5675437
------------------------------------------------------------------------------
( 1) [sleep]obsday + [sleep]1.period#c.obsday = 0
------------------------------------------------------------------------------
sleep | Coefficient Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
(1) | -.1642064 .3733487 -0.44 0.660 -.8959565 .5675437
------------------------------------------------------------------------------
This is exactly the same as the slope we estimate with the
mkpline
approach. The slope after the intervention was
decreasing by -0.16 minutes per week (95% CI: -0.90, 0.57), which was
not statistically significant.
Note: You can estimate the both the slopes before and after the
intervention with the following margins
command:
margins, dydx(obsday) over(period) /* Est slopes before and after intervention */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 200
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
Over: period
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
period |
0 | -.0393758 .3208933 -0.12 0.902 -.6683152 .5895636
1 | -.1642064 .3733487 -0.44 0.660 -.8959565 .5675437
------------------------------------------------------------------------------
Difference in slopes after and before the intervention
The differences in the slopes after and before the intervention can
be estimated using the margins
command with the
pwcompare(effects)
option:
margins, dydx(obsday) over(period) pwcompare(effects) /* Diff between slopes after and before the intervention */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Pairwise comparisons of average marginal effects
Number of obs = 200
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
Over: period
------------------------------------------------------------------------------
| Contrast Delta-method Unadjusted Unadjusted
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
period |
1 vs 0 | -.1248306 .427767 -0.29 0.770 -.9632385 .7135773
------------------------------------------------------------------------------
The answer is exactly the same with the mkspline
method.
The slope in the period after the intervention has a greater decrease
compared to the slope in the period before the intervention by -0.12
minutes per week (95% CI: -0.96, 0.71), which is not statistically
significant. In other words, the sleep duration was decreasing at a
faster rate after the intervention compared to before.
Multiple groups ITSA
In this section, we’ll examine how to construct ITSA models with
multiple groups. This will be a little more complicated because of the
interpretations of the coefficients due to the introduction of the
group
variable. The example will include three groups:
Control
, Medication
, and
Education.
Method 1: Splines
Let’s start over and reload the data:
clear all
cd "C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stata\ivrm2"
use sleep_cat3pw.dta, replace
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stat
> a\ivrm2
The splines method takes advantage of the mkspline
command which will generate several new variables that take into
consideration the time after the intervention. This makes interpreting
the difference-in-differences estimation much easier for an ITSA. I like
this method because it takes the guess-work out of trying to make sure
your interaction terms are properly set up because the
mkspline
command takes care that for you.
To begin, we need to figure out where on the X-axis the intervention
occurred. In the sleep_cat3pw.dta
data, the intervention
occurred at day 31 (obsday = 31
). We will use the
mkspline
command to create a knot at
obsday = 31
. These knots are the same as time sequences or
intervals. They help to keep track of when to start the clock with
respect to the index date. For example, knot1
should
correspond to the main time variable obsday
, but
knot2
should restart the clock to start after the
implementation of the intervention.
We use the marginal
option because we want to make
comparisons to the slopes before and after the intervention.
// Use mkspline to create knots. We will create a knot at obsday = 31 (index date)
/* The marginal option => estimate the change in slope b/w knot2 v. knot1 */
mkspline knot1 31 knot2 = obsday, marginal
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Once the knots have been created, let’s take a look at the data
structure. You should notice that two new variables have been added
(knot1
and knot2
). knot1
should
reflect the obsday
variable exactly, but knot2
restarts the time to after the implementation of the intervention:
list if id == 12 | id == 45 | id == 68
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
+--------------------------------------------------+
| id group obsday sleep knot1 knot2 |
|--------------------------------------------------|
89. | 12 Control 1 360 1 0 |
90. | 12 Control 8 356 8 0 |
91. | 12 Control 14 342 14 0 |
92. | 12 Control 20 360 20 0 |
93. | 12 Control 26 366 26 0 |
|--------------------------------------------------|
94. | 12 Control 32 350 32 1 |
95. | 12 Control 38 383 38 7 |
96. | 12 Control 45 385 45 14 |
353. | 45 Medication 1 332 1 0 |
354. | 45 Medication 7 338 7 0 |
|--------------------------------------------------|
355. | 45 Medication 13 349 13 0 |
356. | 45 Medication 18 357 18 0 |
357. | 45 Medication 26 370 26 0 |
358. | 45 Medication 32 415 32 1 |
359. | 45 Medication 37 402 37 6 |
|--------------------------------------------------|
360. | 45 Medication 44 413 44 13 |
537. | 68 Education 1 360 1 0 |
538. | 68 Education 6 358 6 0 |
539. | 68 Education 13 367 13 0 |
540. | 68 Education 19 358 19 0 |
|--------------------------------------------------|
541. | 68 Education 25 368 25 0 |
542. | 68 Education 33 389 33 2 |
543. | 68 Education 40 424 40 9 |
544. | 68 Education 46 419 46 15 |
+--------------------------------------------------+
Once the knots have been created, we want to create a variable that partitions time periods to before and after the implementation of the intervention. Since there are only two time periods (before the intervention and after the intervention), we will create a binary indicator.
// Create a variable to separate the treatment periods.
gen period = .
replace period = 0 if obsday < 31 /* Baseline phase */
replace period = 1 if obsday >= 31 & !missing(obsday) /* Treatment phase */
tab period, m
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
(600 missing values generated)
(378 real changes made)
(222 real changes made)
period | Freq. Percent Cum.
------------+-----------------------------------
0 | 378 63.00 63.00
1 | 222 37.00 100.00
------------+-----------------------------------
Total | 600 100.00
Let’s re-examine our data. You should notice that a new variable
called period
has been added:
list if id == 12 | id == 45 | id == 68
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
+-----------------------------------------------------------+
| id group obsday sleep knot1 knot2 period |
|-----------------------------------------------------------|
89. | 12 Control 1 360 1 0 0 |
90. | 12 Control 8 356 8 0 0 |
91. | 12 Control 14 342 14 0 0 |
92. | 12 Control 20 360 20 0 0 |
93. | 12 Control 26 366 26 0 0 |
|-----------------------------------------------------------|
94. | 12 Control 32 350 32 1 1 |
95. | 12 Control 38 383 38 7 1 |
96. | 12 Control 45 385 45 14 1 |
353. | 45 Medication 1 332 1 0 0 |
354. | 45 Medication 7 338 7 0 0 |
|-----------------------------------------------------------|
355. | 45 Medication 13 349 13 0 0 |
356. | 45 Medication 18 357 18 0 0 |
357. | 45 Medication 26 370 26 0 0 |
358. | 45 Medication 32 415 32 1 1 |
359. | 45 Medication 37 402 37 6 1 |
|-----------------------------------------------------------|
360. | 45 Medication 44 413 44 13 1 |
537. | 68 Education 1 360 1 0 0 |
538. | 68 Education 6 358 6 0 0 |
539. | 68 Education 13 367 13 0 0 |
540. | 68 Education 19 358 19 0 0 |
|-----------------------------------------------------------|
541. | 68 Education 25 368 25 0 0 |
542. | 68 Education 33 389 33 2 1 |
543. | 68 Education 40 424 40 9 1 |
544. | 68 Education 46 419 46 15 1 |
+-----------------------------------------------------------+
Linear mixed effects model - Using splines
Now that we have our necessary variables, we can begin to construct our ITSA model. We will use the linear mixed effects model for this ITSA. You can use other models such as the generalized estimating equation (GEE) model or a simple linear regression. I chose to use the linear mixed effects model because this was the one that Mitchell used in his textbook, but also because I was working on another study that used a similar model using triple interaction terms, and I wanted to see if I can replicate this result. (Note: In Method 2, we will see that we generate the same answers.)
After the model completes, it is a good idea to use the
predict
command to estimate the outcomes for each subject,
which will generate a new column called linear1
. We will
use this to plot our results.
// Linear mixed effects regression model
xtmixed sleep i.group i.period c.knot1 c.knot2 i.group#i.period i.group#c.knot1 i.group#c.knot2 || id: period knot1 knot2, covariance(unstructured)
predict linear1 /* Predict the linear estimates */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Performing EM optimization:
Performing gradient-based optimization:
Iteration 0: Log likelihood = -2427.9356
Iteration 1: Log likelihood = -2427.8869
Iteration 2: Log likelihood = -2427.8865
Iteration 3: Log likelihood = -2427.8865
Computing standard errors:
Mixed-effects ML regression Number of obs = 600
Group variable: id Number of groups = 75
Obs per group:
min = 8
avg = 8.0
max = 8
Wald chi2(11) = 194.53
Log likelihood = -2427.8865 Prob > chi2 = 0.0000
------------------------------------------------------------------------------
sleep | Coefficient Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
group |
Medication | -2.072872 3.411818 -0.61 0.543 -8.759912 4.614168
Education | 16.31454 3.410371 4.78 0.000 9.630336 22.99875
|
1.period | -4.203853 2.793214 -1.51 0.132 -9.678451 1.270745
knot1 | -.0415024 .2998389 -0.14 0.890 -.6291758 .5461711
knot2 | -.0966276 .5077213 -0.19 0.849 -1.091743 .8984879
|
group#period |
Medication #|
1 | 34.28463 3.997248 8.58 0.000 26.45016 42.11909
Education#1 | 1.647258 3.973666 0.41 0.678 -6.140983 9.4355
|
group#|
c.knot1 |
Medication | .4016104 .4238518 0.95 0.343 -.4291239 1.232345
Education | -.1437658 .4240338 -0.34 0.735 -.9748567 .6873251
|
group#|
c.knot2 |
Medication | -.2913187 .7196931 -0.40 0.686 -1.701891 1.119254
Education | 2.478031 .7176651 3.45 0.001 1.071433 3.884629
|
_cons | 351.3643 2.414271 145.54 0.000 346.6324 356.0962
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Random-effects parameters | Estimate Std. err. [95% conf. interval]
-----------------------------+------------------------------------------------
id: Unstructured |
sd(period) | 7.622454 2.261546 4.261351 13.6346
sd(knot1) | 1.449165 .1262265 1.221732 1.718937
sd(knot2) | 2.352807 .2239956 1.95231 2.835461
sd(_cons) | 10.19626 1.173629 8.136996 12.77666
corr(period,knot1) | -.1047645 .2214208 -.495967 .3217899
corr(period,knot2) | .1578074 .2444491 -.3205053 .5719962
corr(period,_cons) | -.0429446 .2586461 -.501153 .4340715
corr(knot1,knot2) | -.6348598 .079245 -.7656375 -.4536861
corr(knot1,_cons) | -.1454689 .1370307 -.3976797 .1271808
corr(knot2,_cons) | .1491897 .1433531 -.1361996 .411715
-----------------------------+------------------------------------------------
sd(Residual) | 7.89317 .3226308 7.285491 8.551534
------------------------------------------------------------------------------
LR test vs. linear model: chi2(10) = 1169.63 Prob > chi2 = 0.0000
Note: LR test is conservative and provided only for reference.
(option xb assumed)
We can plot the results of the linear mixed effects model. We can see that the Control trend before the intervention is slightly negative with a small drop immediately after the intervention, and a similar negative trend after the intervention. The Medication trend is increasing in the period before the intervention, it has a large jump in the level immediately after the intervention, but the slope is neutral after the intervention. The Education tend is slightly negative in the period before the intervention, there is a very small drop immediately after the intervention, and a steep increase in the slope after the intervention.
*** Plot linear estimates
graph twoway (lfit linear1 obsday if group == 1 & period == 0, lcol(navy) ) ///
(lfit linear1 obsday if group == 1 & period == 1, lcol(navy)) ///
(lfit linear1 obsday if group == 2 & period == 0, lcol(green) lpattern(dash)) ///
(lfit linear1 obsday if group == 2 & period == 1, lcol(green) lpattern(dash)) ///
(lfit linear1 obsday if group == 3 & period == 0, lcol(cranberry) lpattern(shortdash)) ///
(lfit linear1 obsday if group == 3 & period == 1, lcol(cranberry) lpattern(shortdash) ///
xline(31) ///
legend(title("Treatment groups", size(small)) size(vsmall) position(3) ///
order(1 "Control" 3 "Medication" 5 "Education")))
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Slopes before the intervention
We can estimate the marginal effects at different points along the ITSA.
To get the slopes for the three groups at the period before the intervention, we can write the following code:
*** Estimate the slopes for the three groups in the period == 0 (baseline phase)
margins, dydx(knot1) over(group)
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: knot1
Over: group
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
knot1 |
group |
Control | -.0415024 .2998389 -0.14 0.890 -.6291758 .5461711
Medication | .360108 .299578 1.20 0.229 -.2270542 .9472702
Education | -.1852682 .2998354 -0.62 0.537 -.7729347 .4023984
------------------------------------------------------------------------------
The slope for the Control group was -0.04 minutes per week (95% CI: -0.63, 0.55) before the intervention.
The slope for the Medication group was 0.36 minutes per week (95% CI: -0.23, 0.95) before the intervention.
The slope for the Education group was -0.19 minutes per week (95% CI: -0.77, 0.40) before the intervention.
None of these slopes were significant.
To test the difference in the slopes between the groups, we can add
the pwcompare(effects)
option:
*** Estimate the slopes for the three groups in the period == 0 (baseline phase)
margins, dydx(knot1) over(group) pwcompare
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Pairwise comparisons of average marginal effects
Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: knot1
Over: group
--------------------------------------------------------------------------
| Contrast Delta-method Unadjusted
| dy/dx std. err. [95% conf. interval]
-------------------------+------------------------------------------------
knot1 |
group |
Medication vs Control | .4016104 .4238518 -.4291239 1.232345
Education vs Control | -.1437658 .4240338 -.9748567 .6873251
Education vs Medication | -.5453762 .4238493 -1.376106 .2853533
--------------------------------------------------------------------------
The P-values are all above 0.05; hence, there were no statistically significant differences in the slopes between the groups prior to the intervention.
Level change immediately after the intervention
Next, we can compare the level change immediately after the
implementation of the intervention. This analysis provides use with
information on how much the levels jumped or dropped immediately after
the implementation of the intervention at obsday = 31
.
There are two ways to write this code (Note: I prefer the
margins
command):
*** Estimate the amount of level change for each group
/* Method 1: using the contrast command */
contrast period@group, pveffects nowald
/* Method 2: using the margins command */
margins, dydx(period) over(group)
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Contrasts of marginal linear predictions
Margins: asbalanced
----------------------------------------------------------------
| Contrast Std. err. z P>|z|
------------------------+---------------------------------------
sleep |
period@group |
(1 vs base) Control | -4.203853 2.793214 -1.51 0.132
(1 vs base) Medication | 30.08077 2.859362 10.52 0.000
(1 vs base) Education | -2.556595 2.826301 -0.90 0.366
----------------------------------------------------------------
Average marginal effects Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: 1.period
Over: group
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
0.period | (base outcome)
-------------+----------------------------------------------------------------
1.period |
group |
Control | -4.203853 2.793214 -1.51 0.132 -9.678451 1.270745
Medication | 30.08077 2.859362 10.52 0.000 24.47653 35.68502
Education | -2.556595 2.826301 -0.90 0.366 -8.096042 2.982853
------------------------------------------------------------------------------
Note: dy/dx for factor levels is the discrete change from the base level.
In the Control group, the level changed was -4.20 minutes (95% CI:
-9.68, 1.27) immediately after implementation of the intervention;
however, this was not statistically significant (P=0.132). We visualize
this in the Figure above by the decrease in the level at
obsday = 31
.
In the Medication group, the level change was +30.08 minutes (95% CI:
24.48, 35.69) immediately after implementation of the intervention; this
was statistically significant (P<0.001). We visualize this in the
Figure above by the large increase in the level at
obsday = 31
.
In the Education group, the level change was -2.56 minutes (95% CI:
-8.10, 2.98) immediately after implementation of the intervention;
however, this was not statistically significant (P=0.366). We visualize
this in the Figure above by the very small decrease in the level at
obsday = 31
.
Comparing the Slopes after the intervention
Lastly, we can measure the differences in the slopes after and before the intervention between the groups, which is also called the difference-in-differences. This will yield information about the slope changes between the groups and the differences in the slopes after and before the intervention.
Let’s see what the differences in the slopes after and before the intervention for each group without comparing them to each other:
*** Estimate the change in slopes for each group
margins, dydx(knot2) over(group)
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: knot2
Over: group
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
knot2 |
group |
Control | -.0966276 .5077213 -0.19 0.849 -1.091743 .8984879
Medication | -.3879464 .5100757 -0.76 0.447 -1.387676 .6117837
Education | 2.381403 .5072103 4.70 0.000 1.38729 3.375517
------------------------------------------------------------------------------
In the Control group, the slope in the period after the intervention was lower than before the intervention by -0.10 minutes per week (95% CI: -1.09, 0.90); however, this was not statistically significant (P=0.849).
In the Medication group, the slope in the period after the intervention was lower than before the intervention by -0.39 minutes per week (95% CI: -1.39, 0.61); however, this was not statistically significant (P=0.447).
In the Eduation group, the slope in the period after the intervention was greater than before the intervention by 2.38 minute per week (95% CI: 1.39, 3.38); this was statistically significant (P<0.001).
We can compare these difference to each other using the
margins
command with the pwcompare(effectS)
option:
*** Estimate the change in slopes for each group
margins, dydx(knot2) over(group) pwcompare(effects)
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Pairwise comparisons of average marginal effects
Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: knot2
Over: group
------------------------------------------------------------------------------
| Contrast Delta-method Unadjusted Unadjusted
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
knot2 |
group |
Medication |
vs |
Control | -.2913187 .7196931 -0.40 0.686 -1.701891 1.119254
Education |
vs |
Control | 2.478031 .7176651 3.45 0.001 1.071433 3.884629
Education |
vs |
Medication | 2.76935 .7193327 3.85 0.000 1.359484 4.179216
------------------------------------------------------------------------------
In the comparison between the Medication and Control groups, the difference in the slope change was -0.29 minute per week (95% CI: -1.70, 1.12); however, this was not statistically signficiant (P=0.686).
In the comaprison between the Eduation and Control groups, the difference in the slope change was 2.48 minutes per week (95% CI: 1.07, 3.88); this was statistically significant (P=0.001).
In the comparison between the Education versus and Medication groups, the difference in teh slope change was 2.77 mintues per week (95% CI: 1.36, 4.18); this was statistically significant (P<0.001).
Method 2: Triple Interaction Term
The mkspline
method makes it easy to perform an ITSA in
Stata
. However, we can do a lot of the
mkspline
work ourselves using interaction terms,
particularly the triple interaction between the group
,
obsday
, and period
variables.
clear all
cd "C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stata\ivrm2"
use sleep_cat3pw.dta, replace
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
C:\Users\carn3_a5ada\Dropbox\STATA references\Mitchels book - Visualing in Stat
> a\ivrm2
Recall the following formula:
\(Y_i = \beta_0 + \beta_1(T_i) + \beta_2(X_i) + \beta_3(T_i * X_i) + \beta_4(G_i) + \beta_5(G_i * T_i) + \beta_6(G_i * X_i) + \beta_7(G_i * T_i * X_i) + \epsilon_i\)
We will use this to our advantage to create the \(\beta_7\) coefficient in our model.
First, we’ll need to generate the binary period
variable
that partitions the time period before and after the intervention.
// Generate a variable for the pre- and post-index date (obsday == 31)
gen period = .
replace period = 0 if obsday < 31 /* Baseline phase */
replace period = 1 if obsday >= 31 & !missing(obsday) /* Treatment phase */
tab period, m
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
(600 missing values generated)
(378 real changes made)
(222 real changes made)
period | Freq. Percent Cum.
------------+-----------------------------------
0 | 378 63.00 63.00
1 | 222 37.00 100.00
------------+-----------------------------------
Total | 600 100.00
Second, we will need to create lots of interaction terms. Pay attention to how the terms are created. There are a total of three two-way interaction terms and one three-way interaction term (triple interaction).
After the model completes, it is a good idea to use the
predict
command to estimate the outcomes for each subject,
which will generate a new column called linear2
. We will
use this to plot our results.
// Linear mixed effects regression model
xtmixed sleep i.group c.obsday i.period i.group#c.obsday i.group#i.period c.obsday#i.period i.group#c.obsday#i.period || id: i.period obsday c.obsday#i.period, covariance(unstructured)
predict linear2 /* Predict the linear estimates */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Performing EM optimization:
Performing gradient-based optimization:
Iteration 0: Log likelihood = -2440.1403
Iteration 1: Log likelihood = -2429.4305
Iteration 2: Log likelihood = -2428.2399
Iteration 3: Log likelihood = -2427.8876
Iteration 4: Log likelihood = -2427.8865
Iteration 5: Log likelihood = -2427.8865
Computing standard errors:
Mixed-effects ML regression Number of obs = 600
Group variable: id Number of groups = 75
Obs per group:
min = 8
avg = 8.0
max = 8
Wald chi2(11) = 194.53
Log likelihood = -2427.8865 Prob > chi2 = 0.0000
------------------------------------------------------------------------------
sleep | Coefficient Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
group |
Medication | -2.072872 3.41182 -0.61 0.543 -8.759916 4.614172
Education | 16.31454 3.410373 4.78 0.000 9.630332 22.99875
|
obsday | -.0415024 .2998387 -0.14 0.890 -.6291755 .5461707
1.period | -1.208401 16.09127 -0.08 0.940 -32.7467 30.3299
|
group#|
c.obsday |
Medication | .4016104 .4238516 0.95 0.343 -.4291235 1.232344
Education | -.1437658 .4240335 -0.34 0.735 -.9748562 .6873247
|
group#period |
Medication #|
1 | 43.31551 22.86307 1.89 0.058 -1.495271 88.1263
Education#1 | -75.1717 22.75371 -3.30 0.001 -119.7682 -30.57525
|
period#|
c.obsday |
1 | -.0966275 .5077213 -0.19 0.849 -1.091743 .8984879
|
group#|
period#|
c.obsday |
Medication #|
1 | -.2913189 .7196931 -0.40 0.686 -1.701891 1.119254
Education#1 | 2.478031 .7176651 3.45 0.001 1.071433 3.884629
|
_cons | 351.3643 2.414273 145.54 0.000 346.6324 356.0962
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Random-effects parameters | Estimate Std. err. [95% conf. interval]
-----------------------------+------------------------------------------------
id: Unstructured |
sd(1.period) | 72.12794 7.416293 58.9633 88.23181
sd(obsday) | 1.449164 .1262334 1.221719 1.718952
sd(1.period#obsday) | 2.352807 .224007 1.952292 2.835488
sd(_cons) | 10.19626 1.173635 8.136995 12.77668
corr(1.period,obsday) | .6309106 .0869351 .4299745 .7722948
corr(1.period, |
1.period# |
c.obsday) | -.9945401 .003436 -.9984118 -.9813177
corr(1.period,_cons) | -.1554014 .1485937 -.4260955 .1408325
corr(obsday,1.period#obsday) | -.6348605 .0792723 -.7656752 -.4536155
corr(obsday,_cons) | -.1454687 .1370455 -.3977045 .1272102
corr(1.period#obsday,_cons) | .1491895 .1434002 -.1362924 .4117932
-----------------------------+------------------------------------------------
sd(Residual) | 7.893171 .3226315 7.285491 8.551537
------------------------------------------------------------------------------
LR test vs. linear model: chi2(10) = 1169.63 Prob > chi2 = 0.0000
Note: LR test is conservative and provided only for reference.
(option xb assumed)
Once the model run is complete, we can plot the predicted values.
Notice that these plots are exactly the same as the previous plot based
on the mkspline
method.
*** Plot linear estimates
graph twoway (lfit linear2 obsday if group == 1 & period == 0, lcol(navy) ) ///
(lfit linear2 obsday if group == 1 & period == 1, lcol(navy)) ///
(lfit linear2 obsday if group == 2 & period == 0, lcol(green) lpattern(dash)) ///
(lfit linear2 obsday if group == 2 & period == 1, lcol(green) lpattern(dash)) ///
(lfit linear2 obsday if group == 3 & period == 0, lcol(cranberry) lpattern(shortdash)) ///
(lfit linear2 obsday if group == 3 & period == 1, lcol(cranberry) lpattern(shortdash) ///
xline(31) ///
legend(title("Treatment groups", size(small)) size(vsmall) position(3) ///
order(1 "Control" 3 "Medication" 5 "Education")))
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Slopes before the intervention
We can estimate the marginal effects at different points along the ITSA.
There are two methods to estimate the slopes for the three groups at the period before the intervention:
*** Estimate the slopes for the three groups in the period == 0 (baseline phase)
margins if period == 0, dydx(obsday) over(group) /* Method 1 */
margins group, dydx(obsday) at(period = (0 1)) /* Method 2 */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 378
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
Over: group
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
group |
Control | -.0415024 .2998387 -0.14 0.890 -.6291755 .5461707
Medication | .360108 .2995779 1.20 0.229 -.2270538 .9472699
Education | -.1852682 .2998352 -0.62 0.537 -.7729344 .4023981
------------------------------------------------------------------------------
Average marginal effects Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
1._at: period = 0
2._at: period = 1
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
_at#group |
1#Control | -.0415024 .2998387 -0.14 0.890 -.6291755 .5461707
1 #|
Medication | .360108 .2995779 1.20 0.229 -.2270538 .9472699
1#Education | -.1852682 .2998352 -0.62 0.537 -.7729344 .4023981
2#Control | -.1381299 .4038305 -0.34 0.732 -.9296232 .6533634
2 #|
Medication | -.0278384 .4069828 -0.07 0.945 -.82551 .7698332
2#Education | 2.196135 .4031956 5.45 0.000 1.405886 2.986384
------------------------------------------------------------------------------
Compare these results to the mkspline
method. They are
exactly the same.
We can also compare the slopes between the groups using the
pwcompare(effects)
option.
margins if period == 0, dydx(obsday) over(group) pwcompare(effects) /* Method 1 */
margins group, dydx(obsday) at(period = 0) pwcompare(effects) /* Method 2 */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Pairwise comparisons of average marginal effects
Number of obs = 378
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
Over: group
------------------------------------------------------------------------------
| Contrast Delta-method Unadjusted Unadjusted
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
group |
Medication |
vs |
Control | .4016104 .4238516 0.95 0.343 -.4291235 1.232344
Education |
vs |
Control | -.1437658 .4240335 -0.34 0.735 -.9748562 .6873247
Education |
vs |
Medication | -.5453762 .4238491 -1.29 0.198 -1.376105 .2853528
------------------------------------------------------------------------------
Pairwise comparisons of average marginal effects
Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
At: period = 0
------------------------------------------------------------------------------
| Contrast Delta-method Unadjusted Unadjusted
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
group |
Medication |
vs |
Control | .4016104 .4238516 0.95 0.343 -.4291235 1.232344
Education |
vs |
Control | -.1437658 .4240335 -0.34 0.735 -.9748562 .6873247
Education |
vs |
Medication | -.5453762 .4238491 -1.29 0.198 -1.376105 .2853528
------------------------------------------------------------------------------
Once again, these results are exactly the same as the
mkspline
method.
Level change immediately after the intervention
We can perform this analysis using the margins
commnand
in Stata
.
margins if obsday == 31, dydx(period) over(group)
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Average marginal effects Number of obs = 7
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: 1.period
Over: group
------------------------------------------------------------------------------
| Delta-method
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
0.period | (base outcome)
-------------+----------------------------------------------------------------
1.period |
group |
Control | -4.203854 2.793213 -1.51 0.132 -9.67845 1.270742
Medication | 30.08077 2.859361 10.52 0.000 24.47653 35.68502
Education | -2.556595 2.8263 -0.90 0.366 -8.096041 2.982851
------------------------------------------------------------------------------
Note: dy/dx for factor levels is the discrete change from the base level.
When compared to the mkspline
method, these results are
exactly the same.
Comparing the Slopes after the intervention
Lastly, we can measure the differences in the slopes after and before the intervention between the groups, which is also called the difference-in-differences. This will yield information about the slope changes between the groups and the differences in the slopes after and before the intervention.
There is no easy way to do this like the mkspline
approach due to the numerous interactions that are occurring. Rather
than give you the comparisons of the changes in the slopes between the
groups, the margins
command will give you multiple
combinations of comparisons. For example, this will yield comparisons
between the Medication group in the period before the intervention with
the Control group in the period before the intervention, which we
already acquired in the previous analysis. However, the
difference-in-differences that we are looking for is in the output, we
just need to search for it.
There are three ways to evaluate the triple interaction:
*** Estimate the change in slopes for each group
margins group, dydx(obsday) at(period = (0 1)) pwcompare(effects) /* Method 1 */
margins, dydx(obsday) over(group period) pwcompare(effects) /* Method 2 */
margins group, dydx(obsday) over(period) pwcompare(effects) /* Method 3 */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Pairwise comparisons of average marginal effects
Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
1._at: period = 0
2._at: period = 1
------------------------------------------------------------------------------
| Contrast Delta-method Unadjusted Unadjusted
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
_at#group |
(1 #|
Medication) |
vs |
(1 #|
Control) | .4016104 .4238516 0.95 0.343 -.4291235 1.232344
(1 #|
Education) |
vs |
(1 #|
Control) | -.1437658 .4240335 -0.34 0.735 -.9748562 .6873247
(2#Control) |
vs |
(1#Control) | -.0966275 .5077213 -0.19 0.849 -1.091743 .8984879
(2 #|
Medication) |
vs |
(1 #|
Control) | .013664 .5055079 0.03 0.978 -.9771133 1.004441
(2 #|
Education) |
vs |
(1 #|
Control) | 2.237638 .5024639 4.45 0.000 1.252826 3.222449
(1 #|
Education) |
vs |
(1 #|
Medication) | -.5453762 .4238491 -1.29 0.198 -1.376105 .2853528
(2 #|
Control) |
vs |
(1 #|
Medication) | -.4982379 .5028181 -0.99 0.322 -1.483743 .4872674
(2 #|
Medication) |
vs |
(1 #|
Medication) | -.3879464 .5100757 -0.76 0.447 -1.387676 .6117836
(2 #|
Education) |
vs |
(1 #|
Medication) | 1.836027 .5023083 3.66 0.000 .8515211 2.820533
(2 #|
Control) |
vs |
(1 #|
Education) | .0471382 .5029714 0.09 0.925 -.9386677 1.032944
(2 #|
Medication) |
vs |
(1 #|
Education) | .1574297 .5055058 0.31 0.755 -.8333435 1.148203
(2 #|
Education) |
vs |
(1 #|
Education) | 2.381403 .5072102 4.70 0.000 1.38729 3.375517
(2 #|
Medication) |
vs |
(2 #|
Control) | .1102915 .5733359 0.19 0.847 -1.013426 1.234009
(2 #|
Education) |
vs |
(2 #|
Control) | 2.334265 .5706538 4.09 0.000 1.215804 3.452726
(2 #|
Education) |
vs |
(2 #|
Medication) | 2.223974 .5728889 3.88 0.000 1.101132 3.346815
------------------------------------------------------------------------------
Pairwise comparisons of average marginal effects
Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
Over: group period
------------------------------------------------------------------------------
| Contrast Delta-method Unadjusted Unadjusted
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
group#period |
(Control#1) |
vs |
(Control#0) | -.0966275 .5077213 -0.19 0.849 -1.091743 .8984879
(Medication #|
0) |
vs |
(Control #|
0) | .4016104 .4238516 0.95 0.343 -.4291235 1.232344
(Medication #|
1) |
vs |
(Control #|
0) | .013664 .5055079 0.03 0.978 -.9771133 1.004441
(Education #|
0) |
vs |
(Control #|
0) | -.1437658 .4240335 -0.34 0.735 -.9748562 .6873247
(Education #|
1) |
vs |
(Control #|
0) | 2.237638 .5024639 4.45 0.000 1.252826 3.222449
(Medication #|
0) |
vs |
(Control #|
1) | .4982379 .5028181 0.99 0.322 -.4872674 1.483743
(Medication #|
1) |
vs |
(Control #|
1) | .1102915 .5733359 0.19 0.847 -1.013426 1.234009
(Education #|
0) |
vs |
(Control #|
1) | -.0471382 .5029714 -0.09 0.925 -1.032944 .9386677
(Education #|
1) |
vs |
(Control #|
1) | 2.334265 .5706538 4.09 0.000 1.215804 3.452726
(Medication #|
1) |
vs |
(Medication #|
0) | -.3879464 .5100757 -0.76 0.447 -1.387676 .6117836
(Education #|
0) |
vs |
(Medication #|
0) | -.5453762 .4238491 -1.29 0.198 -1.376105 .2853528
(Education #|
1) |
vs |
(Medication #|
0) | 1.836027 .5023083 3.66 0.000 .8515211 2.820533
(Education #|
0) |
vs |
(Medication #|
1) | -.1574297 .5055058 -0.31 0.755 -1.148203 .8333435
(Education #|
1) |
vs |
(Medication #|
1) | 2.223974 .5728889 3.88 0.000 1.101132 3.346815
(Education #|
1) |
vs |
(Education #|
0) | 2.381403 .5072102 4.70 0.000 1.38729 3.375517
------------------------------------------------------------------------------
Pairwise comparisons of average marginal effects
Number of obs = 600
Expression: Linear prediction, fixed portion, predict()
dy/dx wrt: obsday
Over: period
------------------------------------------------------------------------------
| Contrast Delta-method Unadjusted Unadjusted
| dy/dx std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
obsday |
period#group |
(0 #|
Medication) |
vs |
(0 #|
Control) | .4016104 .4238516 0.95 0.343 -.4291235 1.232344
(0 #|
Education) |
vs |
(0 #|
Control) | -.1437658 .4240335 -0.34 0.735 -.9748562 .6873247
(1#Control) |
vs |
(0#Control) | -.0966275 .5077213 -0.19 0.849 -1.091743 .8984879
(1 #|
Medication) |
vs |
(0 #|
Control) | .013664 .5055079 0.03 0.978 -.9771133 1.004441
(1 #|
Education) |
vs |
(0 #|
Control) | 2.237638 .5024639 4.45 0.000 1.252826 3.222449
(0 #|
Education) |
vs |
(0 #|
Medication) | -.5453762 .4238491 -1.29 0.198 -1.376105 .2853528
(1 #|
Control) |
vs |
(0 #|
Medication) | -.4982379 .5028181 -0.99 0.322 -1.483743 .4872674
(1 #|
Medication) |
vs |
(0 #|
Medication) | -.3879464 .5100757 -0.76 0.447 -1.387676 .6117836
(1 #|
Education) |
vs |
(0 #|
Medication) | 1.836027 .5023083 3.66 0.000 .8515211 2.820533
(1 #|
Control) |
vs |
(0 #|
Education) | .0471382 .5029714 0.09 0.925 -.9386677 1.032944
(1 #|
Medication) |
vs |
(0 #|
Education) | .1574297 .5055058 0.31 0.755 -.8333435 1.148203
(1 #|
Education) |
vs |
(0 #|
Education) | 2.381403 .5072102 4.70 0.000 1.38729 3.375517
(1 #|
Medication) |
vs |
(1 #|
Control) | .1102915 .5733359 0.19 0.847 -1.013426 1.234009
(1 #|
Education) |
vs |
(1 #|
Control) | 2.334265 .5706538 4.09 0.000 1.215804 3.452726
(1 #|
Education) |
vs |
(1 #|
Medication) | 2.223974 .5728889 3.88 0.000 1.101132 3.346815
------------------------------------------------------------------------------
The output yields lots of comparisons, but the ones we want are:
(1#Control) vs (0#Control)
, which yields the differences
in the slopes after and before the intervention for the Control
group.
(1#Medication) vs (0#Medication)
, which yields the
differences in the slopes after and before the intervention for the
Medication group.
(1#Education) vs (0#Education)
, which yields the
differences in the slopes after and before the intervention for the
Education group.
When compared to the mkspline
results, these are exactly
the same.
Finally, to get the difference-in-differences estimates, we need to
use the constrast
command in Stata
. I could
not get the contrast
command to give me all the pair-wise
comparisons between the three groups, so I had to write another
contrast
command using the ar.factor
operator,
which means that the difference will be made with the previous level; in
our scenario, this will make Medication as the reference for the
Education comparison.
contrast i.group#c.obsday#i.period, effects /* difference-in-differences */
contrast ar.group#c.obsday#i.period, effects /* difference-in-differences */
Running C:\Users\carn3_a5ada\Dropbox\Marks blog\ITSA\R Markdown code\profile.do
> ...
Contrasts of marginal linear predictions
Margins: asbalanced
---------------------------------------------------------
| df chi2 P>chi2
----------------------+----------------------------------
sleep |
group#period#c.obsday | 2 17.95 0.0001
---------------------------------------------------------
------------------------------------------------------------------------------
| Contrast Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
sleep |
group#|
period#|
c.obsday |
(Medication |
vs |
base) |
(1 vs base) | -.2913189 .7196931 -0.40 0.686 -1.701891 1.119254
(Education |
vs |
base) |
(1 vs base) | 2.478031 .7176651 3.45 0.001 1.071433 3.884629
------------------------------------------------------------------------------
Contrasts of marginal linear predictions
Margins: asbalanced
----------------------------------------------------------------------
| df chi2 P>chi2
-----------------------------------+----------------------------------
sleep |
group#period#c.obsday |
(Medication vs Control) (joint) | 1 0.16 0.6856
(Education vs Medication) (joint) | 1 14.82 0.0001
Joint | 2 17.95 0.0001
----------------------------------------------------------------------
------------------------------------------------------------------------------
| Contrast Std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
sleep |
group#|
period#|
c.obsday |
(Medication |
vs |
Control) |
(1 vs base) | -.2913189 .7196931 -0.40 0.686 -1.701891 1.119254
(Education |
vs |
Medication) |
(1 vs base) | 2.76935 .7193326 3.85 0.000 1.359484 4.179216
------------------------------------------------------------------------------
Based on these findings, we can see that difference in the changes in the slopes between Medication and Control is -0.29 minutes per week (95% CI: -1.70, 1.12), which is not statistically significant (P=0.686).
However, there was a greater difference in the changes in the slope between the Education versus Control, which was +2.47 minutes per week 995% CI: 1.07, 3.89); this is statistically significant (P=0.001).
Similarly, the difference in the changes in the slope was greater for the Medication group versus the Education group by +2.77 minutes per week (95% CI: 1.36, 4.18), which was statistically significant (P<0.001).
Once again, these results are exactly the same as the
mkspline
approach.
Conclusions
ITSA is a power tool that can help us quantify the trends before and
after the implementation of an intervention. This can be used for a
single group design or a multiple groups design. The ease of the
mkspline
methods facilitates our ability to create and
interpret the linear mixed effects model. However, the triple
interaction term method is also viable despite requiring a little bit of
additional coding with the margins
and
constrast
commands.
Acknowledgements
I have been exposed to many different approaches to performing ITSA, but the two that I found to be the most helpful were by Ariel Linden and Michael N. Mitchell.
Linden’s paper, “Conducting interrupted time-series analysis for single- and multiple-group comparisons,” is available here. This was a great paper on the theory and principles of ITSA; and it was written in a way that was easy to absorb and understand. The citation is Linden A. Conducting interrupted time-series analysis for single- and multiple-group comparisons. The Stata Journal. 2015;15(2):480-500.
Micheal N. Mitchell’s book, “Interpreting and Visualizing Regression
Models Using Stata, Second Edition,” is available on the Stata
website. I recommend reading Chapters 12 and 16; I found these to be
the most helpful in writing code for ITSA.
Another useful guide is the Stata
documentation on
contrast
options, which is available here.
My code for this exercise is available on my GitHub site.
Work in progress
This is a work in progress, and I plan to make updates in the future. So stay tuned.
Lastly, this is for education purposes only.