Skip to main content
added 538 characters in body
Source Link
dipetkov
  • 10.7k
  • 2
  • 20
  • 56

The standard errors for the indepvar1 time trends are the same because the design is balanced with respect to the indepvar1:time product terms:. The balance manifests as patterns of symmetry in the design matrix $\mathbf{X}$ and those are also reflected in the variance covariance matrix of the regression coefficients, $\operatorname{Var}(\boldsymbol{\beta}) = \sigma^2(\mathbf{X}'\mathbf{X})^{-1}$. See also How are the standard errors of coefficients calculated in a regression?.

Notice how each indepvar1 category has the same number of observations per time point (even, even though that number varies across time points). So each indepvar1 category has a block of rows in $\mathbf{X}$ with the same structure, which creates balance/symmetry in $\mathbf{X}$.

This is the main reason the trend SEstd. errors are the same. It also matters that there is balance between indepvar1:time and indepvar2.

demo_data |>
  count(indepvar1, time, indepvar2) |>
  pivot_wider(
    names_from = time,
    values_from = n
  )
#> indepvar1                indepvar2           `0`   `3`   `6`   `9`  `12`  `15`
#> unedited_vehicle         MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_vehicle         MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_vehicle         MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_vehicle         MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1    NA     1     1     1

Notice how the pattern of NAs repeats 5 times (once for each indepvar1 category) with one observation per combination otherwise. A NA indicateindicates there is no observation for the corresponding combination of the three predictors.

An easy way to "break" the second balance conditionbetween indepvar1:time and indepvar2 is to shuffle indepvar2. Effectively this redistributes the NAs in an imbalanced way.

The standard errors for the indepvar1 time trends are the same because the design is balanced with respect to the indepvar1:time product terms:

Notice how each indepvar1 category has the same number of observations per time point (even though that number varies across time points).

This is the main reason the trend SE are the same. It also matters that there is balance between indepvar1:time and indepvar2.

demo_data |>
  count(indepvar1, time, indepvar2) |>
  pivot_wider(
    names_from = time,
    values_from = n
  )
#> indepvar1                indepvar2           `0`   `3`   `6`   `9`  `12`  `15`
#> unedited_vehicle         MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_vehicle         MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_vehicle         MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_vehicle         MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1    NA     1     1     1

Notice how the pattern of NAs repeats 5 times (once for each indepvar1 category) with one observation per combination otherwise. A NA indicate there is no observation for the corresponding combination of the three predictors.

An easy way to "break" the second balance condition is to shuffle indepvar2. Effectively this redistributes the NAs in an imbalanced way.

The standard errors for the indepvar1 time trends are the same because the design is balanced with respect to the indepvar1:time product terms. The balance manifests as patterns of symmetry in the design matrix $\mathbf{X}$ and those are also reflected in the variance covariance matrix of the regression coefficients, $\operatorname{Var}(\boldsymbol{\beta}) = \sigma^2(\mathbf{X}'\mathbf{X})^{-1}$. See also How are the standard errors of coefficients calculated in a regression?.

Notice how each indepvar1 category has the same number of observations per time point, even though that number varies across time points. So each indepvar1 category has a block of rows in $\mathbf{X}$ with the same structure, which creates balance/symmetry in $\mathbf{X}$.

This is the main reason the trend std. errors are the same. It also matters that there is balance between indepvar1:time and indepvar2.

demo_data |>
  count(indepvar1, time, indepvar2) |>
  pivot_wider(
    names_from = time,
    values_from = n
  )
#> indepvar1                indepvar2          `0`   `3`   `6`   `9`  `12`  `15`
#> unedited_vehicle         MSH3aso_dose_ti…    1     1     1     1    NA    NA
#> unedited_vehicle         MSH3aso_dose_ti…    1     1     1    NA     1     1
#> unedited_vehicle         MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_vehicle         MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…    1     1     1     1    NA    NA
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…    1     1     1    NA     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…    1     1     1     1    NA    NA
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…    1     1     1    NA     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…    1     1     1     1    NA    NA
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…    1     1     1    NA     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…    1     1     1     1    NA    NA
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…    1     1     1    NA     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…    1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…    1     1    NA     1     1     1

Notice how the pattern of NAs repeats 5 times (once for each indepvar1 category) with one observation per combination otherwise. A NA indicates there is no observation for the corresponding combination of the three predictors.

An easy way to "break" the balance between indepvar1:time and indepvar2 is to shuffle indepvar2. Effectively this redistributes the NAs in an imbalanced way.

Source Link
dipetkov
  • 10.7k
  • 2
  • 20
  • 56

The standard errors for the indepvar1 time trends are the same because the design is balanced with respect to the indepvar1:time product terms:

demo_data |>
  count(indepvar1, time) |>
  pivot_wider(
    names_from = time,
    values_from = n
  )
#> indepvar1                   `0`   `3`   `6`   `9`  `12`  `15`
#> unedited_vehicle             4     4     2     3     3     3
#> unedited_MSH3aso_0.022uM     4     4     2     3     3     3
#> unedited_MSH3aso_0.26uM      4     4     2     3     3     3
#> unedited_MSH3aso_3uM         4     4     2     3     3     3
#> unedited_SCRaso_3uM          4     4     2     3     3     3

Notice how each indepvar1 category has the same number of observations per time point (even though that number varies across time points).

This is the main reason the trend SE are the same. It also matters that there is balance between indepvar1:time and indepvar2.

demo_data |>
  count(indepvar1, time, indepvar2) |>
  pivot_wider(
    names_from = time,
    values_from = n
  )
#> indepvar1                indepvar2           `0`   `3`   `6`   `9`  `12`  `15`
#> unedited_vehicle         MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_vehicle         MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_vehicle         MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_vehicle         MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.022uM MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_0.26uM  MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_MSH3aso_3uM     MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1     1     1    NA    NA
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1     1    NA     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1    NA     1     1     1
#> unedited_SCRaso_3uM      MSH3aso_dose_ti…     1     1    NA     1     1     1

Notice how the pattern of NAs repeats 5 times (once for each indepvar1 category) with one observation per combination otherwise. A NA indicate there is no observation for the corresponding combination of the three predictors.

An easy way to "break" the second balance condition is to shuffle indepvar2. Effectively this redistributes the NAs in an imbalanced way.

set.seed(123)

demo_data <- demo_data |>
  mutate(
    indepvar2 = sample(indepvar2, replace = FALSE)
  )

my_lm <- lm(
  responsevar ~ indepvar1 * time + indepvar2,
  data = demo_data
)

emtrends(my_lm, ~indepvar1, var = "time")
#>  indepvar1                time.trend     SE df lower.CL upper.CL
#>  unedited_vehicle             0.0848 0.0212 82   0.0426   0.1271
#>  unedited_MSH3aso_0.022uM     0.0782 0.0208 82   0.0368   0.1196
#>  unedited_MSH3aso_0.26uM      0.0220 0.0214 82  -0.0205   0.0646
#>  unedited_MSH3aso_3uM        -0.0206 0.0205 82  -0.0613   0.0201
#>  unedited_SCRaso_3uM          0.1062 0.0221 82   0.0623   0.1501
#> 
#> Results are averaged over the levels of: indepvar2 
#> Confidence level used: 0.95

Now the std. errors of the time trends vary a bit between categories. Adding a continuous covariate would (most likely) have a similar effect; it's harder to get exact balance with continuous variables.