“Objective Assessment of Wear Time During the Initial Phase of Orthodontic Aligner Therapy Using Microsensors - a Randomized Controlled Trial”

Data Supplement - Manuscript (ref. AJODO-D-25-00406R2) accepted 2025/10/03

Authors
Affiliations

Uwe Baumert

Department of Orthodontics and Dentofacial Orthopedics, Dental School, LMU Medical Center, LMU Munich, Germany

Hisham Sabbagh

Published

April 21, 2025

Modified

October 8, 2025

1 Data preparation and code book

Show the code
theramon_long <- haven::read_sav("Theramon_data_long2.sav")

theramon_long <- theramon_long |>
  mutate(Id = factor(Id), 
         age = as.numeric(sprintf(age_yr, fmt = "%#.1f")), # 'age' rounded to 1 significant digit
         study_arm = factor(study_arm, 
                            levels = c("0", "1"), 
                            labels = c("Group 1 (unaware)", "Group 2 (aware)")),
         sex = factor(sex, 
                      levels = c("0", "1"), 
                      labels = c("Male", "Female")),
         visit_n = as.integer(visit),
         visit = factor(visit, levels = c("1", "2", "3", "4", "5", "6"),
                              labels = c("T0-T1", "T1-T2", "T2-T3", "T3-T4", "T4-T5", "T5-T6")),
         row = row_number()) |>
  rename(wear_time.visit = wear_appointmentx_h,
         mean_dApp_hours = mean_dApp_days,
         delta_visit.days = diff_Appointment_days,
         delta_visit.hours = dApp_h) |>
  select(Id, study_arm, age, sex, visit, visit_n, wear_time.visit, delta_visit.days, delta_visit.hours, mean_wear_h, mean_diff_days, mean_dApp_hours, row)
# [1] "Id"                "study_arm"         "age"               "sex"               "visit"             "visit_n"          
# [7] "wear_time.visit"   "delta_visit.days"  "delta_visit.hours" "mean_wear_h"       "mean_diff_days"    "mean_dApp_hours"  

theramon_long <- theramon_long |>
  group_by(Id) |>
  mutate(cum_days = cumsum(delta_visit.days)) |>
  ungroup() |>
  var_labels(
    Id = "Id",
    age = "Age (years)",
    study_arm = "Study arm",
    visit_n = "Period number",
    visit = "Period",
    sex = "Sex",
    wear_time.visit = "WT at visit (h)",
    delta_visit.days = "Interval between visits (days)",
    delta_visit.hours = "Change in WT between visits (h)",
    cum_days = "Cumulative treatment time (days)",
    mean_wear_h = "Mean WT (h)",
    mean_dApp_hours = "Mean WT change (h)",
    row = "Observation number")

#names(theramon_long)
#  [1] "Id"                "study_arm"         "age"               "sex"               "visit"             "visit_n"          
#  [7] "wear_time.visit"   "delta_visit.days"  "delta_visit.hours" "mean_wear_h"       "mean_diff_days"    "mean_dApp_hours"  
# [13] "row"               "cum_days"    

Originally, the data was collected in a Microsoft Excel spreadsheet in wide format. In accordance with the study protocol, the following data was entered anonymized for each participant after completion of the 6th wear period:

  • Id (factor; 1…40),
  • sex (factor; male = 0, female = 1),
  • age (continuous; years),
  • study_arm (factor; Group 1 (unaware) = 0, Group 2 (aware) = 1),
  • and data exported from the Theramon program:
    • for each wear period the duration of the specific period (days) (delta_visit.days) and
    • the wear time (WT) in hours (wear_time.visit).

This data was used to calculate other variables for each patient:

  • change in mean wear time between visits (h) (delta_visit.hours) for each study subject
  • and mean wear time (h) (mean_wear_h) for each study subject.

Do aid further analysis, the row number corresponding to an individual observation was added to the theramon_long data frame (“Observation number”).

For analysis, this table was reshaped to “long” format in Excel and then imported in SPSS 29. Each variable was labelled accordingly and if necessary, factor levels were defined. The statistical analysis and figure preparation was done using this data file (Theramon_data_long.sav).

The final statistical analysis was done using R (R Core Team 2025) using RStudio version 2025.5.1.513. All analysis and output was documented in this Quarto file.

In R, the variable cum_days representing cumulative treatment time (days) was additionally calculated using the R base function cumsum.

Data is available in the data frame theramon_long, which is in “long” format. Variable definitions are summarized in Table 1.1.

Show the code
labelled::generate_dictionary(theramon_long) |> 
  labelled::convert_list_columns_to_character() |> 
  select(pos, variable, label, col_type, levels) |> 
  rename(Pos = pos, 
         Variable = variable,
         Label = label, 
         "Col. type" = col_type, 
         Levels = levels)  |>
  flextable() |>
  bold(bold = TRUE, part = "header") |>
  autofit()
Table 1.1: Variable definitions (aka ‘codebook’). WT = wear time

Pos

Variable

Label

Col. type

Levels

1

Id

Id

fct

1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21; 22; 23; 24; 25; 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39; 40

2

study_arm

Study arm

fct

Group 1 (unaware); Group 2 (aware)

3

age

Age (years)

dbl

4

sex

Sex

fct

Male; Female

5

visit

Period

fct

T0-T1; T1-T2; T2-T3; T3-T4; T4-T5; T5-T6

6

visit_n

Period number

int

7

wear_time.visit

WT at visit (h)

dbl

8

delta_visit.days

Interval between visits (days)

dbl

9

delta_visit.hours

Change in WT between visits (h)

dbl

10

mean_wear_h

Mean WT (h)

dbl

11

mean_diff_days

Mean time between appointments (days)

dbl

12

mean_dApp_hours

Mean WT change (h)

dbl

13

row

Observation number

int

14

cum_days

Cumulative treatment time (days)

dbl

2 Baseline data

2.1 Patient’s age

In the following table (Table 2.1), a summary of age stratified by study arm is given.

Show the code
set.seed(2)

theramon_long |>
  filter(visit == "T0-T1") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  tbl_summary(include = c(age),
              by = study_arm,
              statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} [{p25}, {p75}]", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1) |>
  add_overall() |>
  add_n() |>
  as_flex_table() |>
  set_table_properties(width = 0.7)
Table 2.1: Descriptive statistics for age by study_arm.

Characteristic

N

Overall
N = 401

Group 1
N = 201

Group 2
N = 201

Age (years)

40

36.2 (14.2)
31.1 [25.8, 48.2]

33.4 (14.7)
30.0 [23.4, 33.1]

39.0 (13.4)
41.4 [26.4, 51.8]

1Mean (SD)
Median [Q1, Q3]

2.2 Variable: sex

Cross-tabulation was applied to investigate the distribution of sex by study_arm (Table 2.2).

Show the code
set.seed(2)

theramon_long |>
  filter(visit == "T0-T1") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(sex, study_arm) |>
  tbl_summary(by = study_arm) |>
  add_overall() |>
  as_flex_table() |>
  set_table_properties(layout = "autofit") 
Table 2.2: Fisher’s exact test: sex by study_arm.

Characteristic

Overall
N = 401

Group 1
N = 201

Group 2
N = 201

Sex

Male

12 (30%)

5 (25%)

7 (35%)

Female

28 (70%)

15 (75%)

13 (65%)

1n (%)

A mosaic plot shows the properties (Figure 2.1).

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg")

mosaic.data <- theramon_long |>
  filter(visit == "T0-T1") |>
  select(sex, study_arm) |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  as_tibble()

mosaic.ggplot <- ggplot(mosaic.data) +
  geom_mosaic(aes(x = product(sex, study_arm), fill = study_arm)) +
  scale_fill_npg() +
  labs(x = "Study arm", y = "Sex") +
  theme_bw(base_size = 12) +
  theme(axis.title.x = element_text(size = 12, face = "bold"),
        axis.text.x = element_text(size = 10),
        axis.title.y = element_text(size = 12, face = "bold"),
        axis.text.y = element_text(size = 10)) |>
  theme(legend.position = "below")

mosaic.ggplot

# since ggplot >= 4.0.0 breaks the current available 'ggmosaic' 0.3.3
# the mosaic plot can also be generated using 'vcd' 
#vcd::mosaic(~ sex + study_arm, data = mosaic.data, highlighting = "study_arm", highlighting_fill = pal_npg(palette = c("nrc"))(2))
Figure 2.1: Mosaicplot: study_arm by sex.

2.3 Baseline summary

Baseline summary statistics is shown in Table 2.3.

Show the code
set.seed(2)

theramon_long |>
  filter(visit == "T0-T1") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  tbl_summary(include = c(age, sex),
              by = study_arm,
              statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1) |>
  add_overall() |>
  add_n() |>
  as_flex_table() |>
  set_table_properties(layout = "autofit")
Table 2.3: Summary statistics of baseline data.

Characteristic

N

Overall
N = 401

Group 1
N = 201

Group 2
N = 201

Age (years)

40

36.2 (14.2)
31.1 (25.8, 48.2)

33.4 (14.7)
30.0 (23.4, 33.1)

39.0 (13.4)
41.4 (26.4, 51.8)

Sex

40

Male

12 (30%)

5 (25%)

7 (35%)

Female

28 (70%)

15 (75%)

13 (65%)

1Mean (SD)
Median (Q1, Q3); n (%)

3 Outcomes

3.1 Time interval (days) between two consecutive appointments

Variables:

  • delta_visit.days: duration of the individual wear periods T0-T1; 2: T1-T2; …; T5-T6;
  • mean_diff_days: covers duration of all individual wear periods (T0-T1 up to and including T5-T6, i.e. T0-T6) and is the mean of these for each individual case.

Patients were scheduled for six clinical appointments following a biweekly protocol. However, due to factors such as professional obligations, illness, and other circumstances, strict adherence to the prescribed schedule was not always feasible. In Table 3.1 the intervals between two consecutive appointments (i.e., wear periods) and the overall mean time of all wear periods covering periods T0-T1, …, T5-T6 were summarized.

Show the code
set.seed(2)

tbl_mean_diff_days <- theramon_long |>
  filter(visit == "T5-T6") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  tbl_summary(include = mean_diff_days,
                by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(mean_diff_days = "Period T0-T6")) |>
  add_overall()

tbl_delta_visit.1 <- theramon_long |>
  filter(visit == "T0-T1") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, delta_visit.days) |>
  tbl_summary(by = study_arm,
              type = list(all_continuous() ~ "continuous2",
                          all_categorical() ~ "continuous2"),
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(delta_visit.days = "Period T0-T1")) |>
  add_overall()

tbl_delta_visit.2 <- theramon_long |>
  filter(visit == "T1-T2") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, delta_visit.days) |>
  tbl_summary(by = study_arm,
              type = list(all_continuous() ~ "continuous2",
                          all_categorical() ~ "continuous2"),
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(delta_visit.days = "Period T1-T2")) |>
  add_overall()

tbl_delta_visit.3 <- theramon_long |>
  filter(visit == "T2-T3") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, delta_visit.days) |>
  tbl_summary(by = study_arm,
              type = list(all_continuous() ~ "continuous2",
                          all_categorical() ~ "continuous2"),
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(delta_visit.days = "Period T2-T3")) |>
  add_overall()

tbl_delta_visit.4 <- theramon_long |>
  filter(visit == "T3-T4") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, delta_visit.days) |>
  tbl_summary(by = study_arm,
              type = list(all_continuous() ~ "continuous2",
                          all_categorical() ~ "continuous2"),
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(delta_visit.days = "Period T3-T4")) |>
  add_overall()

tbl_delta_visit.5 <- theramon_long |>
  filter(visit == "T4-T5") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, delta_visit.days) |>
  tbl_summary(by = study_arm,
              type = list(all_continuous() ~ "continuous2",
                          all_categorical() ~ "continuous2"),
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(delta_visit.days = "Period T4-T5")) |>
  add_overall()

tbl_delta_visit.6 <- theramon_long |>
  filter(visit == "T5-T6") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, delta_visit.days) |>
  tbl_summary(by = study_arm,
              type = list(all_continuous() ~ "continuous2",
                          all_categorical() ~ "continuous2"),
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(delta_visit.days = "Period T5-T6")) |>
  add_overall()

tbl_stack(list(tbl_delta_visit.1,
          tbl_delta_visit.2,
          tbl_delta_visit.3,
          tbl_delta_visit.4,
          tbl_delta_visit.5,
          tbl_delta_visit.6,
          tbl_mean_diff_days)) |>
  as_flex_table() |>
  set_table_properties(layout = "autofit")
Table 3.1: Number of days between appointments and overall time between appointments

Characteristic

Overall
N = 401

Group 1
N = 201

Group 2
N = 201

Period T0-T1

Mean (SD)
Median (Q1, Q3)

14.6 (2.7)
14.0 (14.0, 14.0)

13.9 (1.9)
14.0 (13.0, 14.0)

15.2 (3.3)
14.0 (14.0, 15.0)

Period T1-T2

Mean (SD)
Median (Q1, Q3)

14.5 (2.2)
14.0 (14.0, 15.0)

14.0 (2.3)
14.0 (14.0, 14.0)

15.0 (2.0)
14.0 (14.0, 15.0)

Period T2-T3

Mean (SD)
Median (Q1, Q3)

15.3 (4.0)
14.0 (14.0, 14.5)

15.1 (4.2)
14.0 (14.0, 14.0)

15.4 (3.9)
14.0 (13.5, 15.5)

Period T3-T4

Mean (SD)
Median (Q1, Q3)

14.1 (1.2)
14.0 (14.0, 14.0)

13.9 (0.9)
14.0 (14.0, 14.0)

14.2 (1.5)
14.0 (14.0, 14.0)

Period T4-T5

Mean (SD)
Median (Q1, Q3)

14.6 (2.3)
14.0 (14.0, 14.0)

14.7 (2.8)
14.0 (14.0, 15.0)

14.6 (1.6)
14.0 (14.0, 14.0)

Period T5-T6

Mean (SD)
Median (Q1, Q3)

16.0 (6.2)
14.5 (14.0, 16.0)

17.1 (7.9)
15.0 (14.0, 16.0)

15.0 (3.9)
14.0 (14.0, 15.0)

Period T0-T6

14.8 (1.5)
14.3 (14.0, 15.4)

14.8 (1.8)
14.3 (13.9, 15.0)

14.9 (1.1)
14.5 (14.0, 15.5)

1Mean (SD)
Median (Q1, Q3)

The abacus plot (Figure 3.1) shows the distribution of visits among the patients, illustrating both the clustering of appointment waves and the individuals’ variability in time intervals between consecutive appointments.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg")

data_cumdays <- theramon_long |>
  select(Id, study_arm, visit, cum_days) |>
  mutate(Id = as.numeric(Id),
         visit = as.numeric(visit))|>
  # add_row(Id = 1:40, visit = 0, cum_days = 0) |>
  add_row(Id = c(1:2, 4:7, 9:11, 13, 15, 18, 21, 25, 26, 29, 31, 34, 36, 37), visit = 0, cum_days = 0, study_arm = "Group 1 (unaware)") |>
  add_row(Id = c(3, 8, 12, 14, 16, 17, 19, 20, 22:24, 27, 28, 30, 32, 33, 35, 38:40), visit = 0, cum_days = 0, study_arm = "Group 2 (aware)") |>
  mutate(visit = factor(visit, levels = c("0", "1", "2", "3", "4", "5", "6"))) |>
  arrange(Id, visit)

fig.abacus_plot_cumdays_with0_high <- data_cumdays |>
  ggplot(aes(x = fct_rev(as.factor(Id)), 
             y = cum_days, 
             group = Id, colour = study_arm)) +
  geom_point(size = 1.2, aes(colour = study_arm)) +
  scale_y_continuous(name = "Visit waves (days)", limits = c(0, 120), breaks = seq(0, 120, by = 10), expand = c(0,1)) + # 10-tägig
  labs(x = "Case Id") +
  guides(color = guide_legend(title = "Study arm:")) +
  annotate("rect", xmin = 0, xmax = Inf, ymin = 13, ymax = 15, alpha = .2) +
  annotate("rect", xmin = 0, xmax = Inf, ymin = 27, ymax = 29, alpha = .2) +
  annotate("rect", xmin = 0, xmax = Inf, ymin = 41, ymax = 43, alpha = .2) +
  annotate("rect", xmin = 0, xmax = Inf, ymin = 55, ymax = 57, alpha = .2) +
  annotate("rect", xmin = 0, xmax = Inf, ymin = 69, ymax = 71, alpha = .2) +
  annotate("rect", xmin = 0, xmax = Inf, ymin = 83, ymax = 85, alpha = .2) +
  coord_flip() +
  theme_bw(base_size = 14) +
  theme(axis.title.x = element_text(size = 14, face = "bold"),
        axis.text.x = element_text(size = 12),
        axis.title.y = element_text(size = 14, face = "bold"),
        axis.text.y = element_text(size = 12)) +
  theme(panel.grid.minor.x = element_blank()) +
  theme(legend.position = "bottom")

fig.abacus_plot_cumdays_with0_high
Figure 3.1: Abacus plot: visit waves for each study subject. Grey shaded areas label the 14-days visit intervals as proposed.

3.2 Wear period specific wear time

Variables:

  • wear_time.visit: wear time for each case/wear period
  • mean_wear_h: mean wear time over all wear periods for each case

Wear times per wear period and the overall mean wear time (periods T0-T1 … T5-T6) were summarized for both study arms and the complete study group in Table 3.2.

Show the code
tbl_mean_wear_h <- theramon_long |>
  filter(visit == "T5-T6") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  tbl_summary(include = mean_wear_h,
              by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(mean_wear_h = "Period T0-T6")) |>
  add_overall()

tbl_wear_time_visit.1 <- theramon_long |>
  filter(visit == "T0-T1") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, wear_time.visit) |>
  tbl_summary(by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(wear_time.visit = "Period T0-T1")) |>
  add_overall()

tbl_wear_time_visit.2 <- theramon_long |>
  filter(visit == "T1-T2") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, wear_time.visit) |>
  tbl_summary(by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(wear_time.visit = "Period T1-T2")) |>
  add_overall()

tbl_wear_time_visit.3 <- theramon_long |>
  filter(visit == "T2-T3") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, wear_time.visit) |>
  tbl_summary(by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(wear_time.visit = "Period T2-T3")) |>
  add_overall()

tbl_wear_time_visit.4 <- theramon_long |>
  filter(visit == "T3-T4") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, wear_time.visit) |>
  tbl_summary(by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(wear_time.visit = "Period T3-T4")) |>
  add_overall()

tbl_wear_time_visit.5 <- theramon_long |>
  filter(visit == "T4-T5") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, wear_time.visit) |>
  tbl_summary(by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(wear_time.visit = "Period T4-T5")) |>
  add_overall()

tbl_wear_time_visit.6 <- theramon_long |>
  filter(visit == "T5-T6") |>
  mutate(study_arm = recode(study_arm, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  select(study_arm, wear_time.visit) |>
  tbl_summary(by = study_arm,
                            statistic = list(all_continuous() ~ "{mean} ({sd}) \n {median} ({p25}, {p75})", all_categorical() ~ "{n} ({p}%)"),
              digits = all_continuous() ~1,
              label = list(wear_time.visit = "Period T5-T6")) |>
  add_overall()

tbl_stack(list(tbl_wear_time_visit.1,
          tbl_wear_time_visit.2,
          tbl_wear_time_visit.3,
          tbl_wear_time_visit.4,
          tbl_wear_time_visit.5,
          tbl_wear_time_visit.6,
          tbl_mean_wear_h)) |>
  as_flex_table() |>
  set_table_properties(layout = "autofit")
Table 3.2: Descriptive statistics of wear_time.visit by study_arm and visit and mean_wear_h by study_arm.

Characteristic

Overall
N = 401

Group 1
N = 201

Group 2
N = 201

Period T0-T1

15.7 (3.9)
15.8 (13.8, 19.2)

14.3 (4.3)
14.7 (12.8, 17.0)

17.1 (3.1)
17.4 (14.9, 19.6)

Period T1-T2

15.9 (4.2)
16.3 (13.3, 19.3)

14.5 (4.6)
15.8 (12.0, 17.1)

17.3 (3.4)
17.7 (15.4, 20.1)

Period T2-T3

15.5 (4.6)
15.7 (13.0, 19.2)

14.2 (5.0)
14.7 (11.8, 17.5)

16.9 (3.9)
17.2 (15.3, 19.9)

Period T3-T4

15.2 (4.5)
15.9 (13.2, 19.1)

13.7 (4.9)
14.2 (10.8, 17.0)

16.7 (3.5)
16.9 (15.4, 19.5)

Period T4-T5

14.9 (4.5)
15.5 (12.0, 18.3)

13.1 (4.9)
12.6 (10.3, 16.6)

16.7 (3.2)
17.4 (14.4, 19.4)

Period T5-T6

14.0 (4.5)
13.7 (11.5, 18.4)

12.3 (4.6)
12.5 (9.1, 14.9)

15.7 (3.9)
16.0 (12.2, 19.4)

Period T0-T6

15.2 (4.1)
15.2 (12.6, 18.8)

13.7 (4.4)
14.8 (11.7, 16.1)

16.7 (3.2)
16.7 (14.6, 19.7)

1Mean (SD)
Median (Q1, Q3)

Trajectories of each participant overlaid with the mean WT (and its 95% CI) at each visit for both study arms are shown in Figure 3.2.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg")

fig.study_indiv <- theramon_long |>
  select(Id, study_arm, visit, wear_time.visit) |>
  mutate(visit = as.numeric(visit)) |>
  arrange(Id, visit) |>
  ggplot(aes(x = visit, y = wear_time.visit, group = Id)) +
  geom_line(colour = "lightgrey") +
  geom_point(colour = "darkgrey") +
  guides(shape = "none", color = "none") +
  labs(x = "Wear period", y = "Mean wear time (h) with 95% CI") +
  scale_x_continuous(limit = c(.5, 6.5), breaks = seq(1, 6, by = 1), expand = c(0,0), labels = c("T0-T1", "T1-T2", "T2-T3", "T3-T4", "T4-T5", "T5-T6")) +
  scale_y_continuous(limit = c(0, 25), breaks = seq(0, 25, by = 10), expand = c(0,0)) +
  facet_grid(cols = vars(study_arm), labeller = labeller(study_arm = c("0" = "Temperature", "1" = "Wear time"))) +
  theme_bw(base_size = 14) +
  theme(axis.title.x = element_text(size = 14, face = "bold"),
        axis.text.x = element_text(size = 12),
        axis.title.y = element_text(size = 14, face = "bold"),
        axis.text.y = element_text(size = 12))+
  theme(legend.position = "bottom") +
  theme(panel.grid.major.y = element_line(color = "darkgrey", linetype = "dashed"), panel.grid.minor.y = element_blank(), panel.grid.major.x = element_blank()) +
  theme(strip.text.x = element_text(size = 12, face = "bold"))

fig.study_indiv2 <- fig.study_indiv + 
  stat_summary(fun.data = "mean_cl_normal", geom = "errorbar", width = 0.2, color = "red", group = 1, linewidth = .8) + 
  stat_summary(fun = "mean", geom = "point", shape = 16, size = 2.5, color = "red", group = 1)

fig.study_indiv2
Figure 3.2: Individual mean WT for the six wear periods and both study arms

The individual patters during the six periods of this study are shown in the next figure (Figure 3.3). Ordinary least square regression was applied to visualize the individual differences as indicated by the different, individual slopes.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg") 

theramon_long.slopes <- theramon_long |>
  group_by(Id) |>
  do(tidy(lm(wear_time.visit ~ as.numeric(visit), data = .))) |>
  select(Id, term, estimate) |>
  pivot_wider(names_from = term, values_from = estimate) |>
  rename(intercept = '(Intercept)', 
         slope = 'as.numeric(visit)') |>
  ungroup() 

theramon_long.w_slopes <- theramon_long |>
  group_by(Id) |>
  do(tidy(lm(wear_time.visit ~ as.numeric(visit), data = .))) |>
  select(Id, term, estimate) |>
  pivot_wider(names_from = term, values_from = estimate) |>
  rename(intercept = '(Intercept)', 
         slope = 'as.numeric(visit)') |>
  ungroup()  |>
  merge(theramon_long, by = 'Id')

case_names <- as_labeller(function(x) paste0('Case ', x))

## https://github.com/aphalo/ggpmisc/issues/12
## https://stackoverflow.com/questions/7549694/add-regression-line-equation-and-r2-on-graph
## https://www.reddit.com/r/rstats/comments/bwp5sg/how_do_i_get_r2_values_and_line_equation_for_geom/

theramon_long.slopes_round <- theramon_long.slopes |>
  mutate_if(is.numeric, round, 3)

fig.wear_time.Id_lm <- theramon_long |>
  arrange(Id, visit) |>
  ggplot(aes(x = visit, y = wear_time.visit, group = 1, color = study_arm)) +
  geom_line() +
  geom_point(shape = 21, size = 2, fill = "white") +
  stat_poly_line(formula = y ~ x, colour = "black", linewidth = 0.5, se = FALSE) +
  geom_text(data = theramon_long.slopes_round, aes(x = 2, y = 25, label = paste0("slope: ", slope)), colour = "black", size = 3) +
  guides(shape = "none") + 
  labs(x = "Wear period", y = "Wear time (h)") +
  scale_y_continuous(limit = c(0, 30), breaks = seq(0, 30, by = 10), expand = c(0,0)) +
  scale_colour_discrete(name = "Study arm", labels = c("Group 1 (unaware)", "Group 2 (aware)")) +
  facet_wrap(facet = vars(Id), ncol = 5, labeller = case_names) +
  theme_bw(base_size = 14) +
  theme(legend.position = "bottom") +
  theme(panel.grid.major.y = element_line(color = "lightgrey", linetype = "dashed"), 
        panel.grid.minor.y = element_blank(), panel.grid.major.x = element_blank()) +
  theme(strip.text.x = element_text(size = 11, color = "black", face = "bold")) +
  theme(axis.text.x = element_text(angle = 30, vjust = 0.8, hjust = 0.8))

fig.wear_time.Id_lm
Figure 3.3: Wear time (WT) for each individual case across the six follow-up appointments. Slopes were calculated for each case separately.

To get an idea on the different patters, the slopes calcuated for Figure 3.3 above, were used to classify the study subjects into those with increasing slope over the six periods (slope >= 0.1), with constant slope over the six periods (-0.1 <= slope <= 0.1), and with decreasing slope (slope < -0.1). The findings were summarized in Figure 3.4.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg")

fig.theramon_slope <- theramon_long.w_slopes |>
  ggplot(aes(x = as.numeric(visit), y = wear_time.visit, group = Id)) +
  geom_line(aes(colour = Id), linewidth = 1.5) +
  labs(x = "Wear period", y = "Wear time (h)") +
  scale_x_continuous(limit = c(.5, 6.5), breaks = seq(1, 6, by = 1), expand = c(0,0), labels = c("T0-T1", "T1-T2", "T2-T3", "T3-T4", "T4-T5", "T5-T6")) +
  scale_y_continuous(limit = c(0, 25), breaks = seq(0, 25, by = 10), expand = c(0,0)) +
  facet_grid(cols = vars(study_arm)) +
  theme_bw(base_size = 14) +
  theme(axis.title.x = element_text(size = 14, face = "bold"),
        axis.title.y = element_text(size = 14, face = "bold"),
        axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12)) +
  theme(panel.grid.major.y = element_line(color = "darkgrey", linetype = "dashed"), 
        panel.grid.minor.y = element_blank(), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank()) +
  theme(strip.text.x = element_text(size = 12, face = "bold")) +
  theme(legend.position = "none")

# fig.theramon_slope

## Increasing slop from visit 1 to 6
# theramon_long.w_slopes |>
#   filter(slope > 0.1) |>
#   filter(as.numeric(visit) == 1 | as.numeric(visit) == 6) |>
#   group_by(Id, visit) |>
#   select(Id, visit, slope, sex, wear_time.visit, study_arm) |>
#   pivot_wider(names_from = visit, values_from = c(wear_time.visit)) |>
#   kable(digits = 3)

fig.theramon_slope_inc <- fig.theramon_slope + 
  gghighlight(slope  > 0.1, calculate_per_facet = TRUE, keep_scales = TRUE, label_key = Id, 
              use_direct_label = FALSE, unhighlighted_params = list(linewidth = .8)) 

## more or less stable slope from visit 1 to 6
# theramon_long.w_slopes |>
#   filter(slope <= 0.1 & slope >= -0.1) |>
#   filter(as.numeric(visit) == 1 | as.numeric(visit) == 6) |>
#   group_by(Id, visit) |>
#   select(Id, visit, slope, sex, wear_time.visit, study_arm) |>
#   pivot_wider(names_from = visit, values_from = wear_time.visit) |>
#   kable(digits = 3)

fig.theramon_slope_stable <- fig.theramon_slope +
  gghighlight(max(slope) <=0.1, min(slope) >= -0.1, calculate_per_facet = TRUE, keep_scales = TRUE, 
              label_key = Id, use_direct_label = FALSE, unhighlighted_params = list(linewidth = .8))

## Decreasing slope from visit 1 to 6
# theramon_long.w_slopes |>
#   filter(slope < -0.1) |>
#   filter(as.numeric(visit) == 1 | as.numeric(visit) == 6) |>
#   group_by(Id, visit) |>
#   arrange(Id) |>
#   select(Id, visit, slope, sex, wear_time.visit, study_arm) |>
#   pivot_wider(names_from = visit, values_from = wear_time.visit) |>
#   kable(digits = 3)

fig.theramon_slope_dec <- fig.theramon_slope + 
  gghighlight(min(slope) < -0.1,  calculate_per_facet = TRUE, keep_scales = TRUE, label_key = Id, 
              use_direct_label = FALSE, unhighlighted_params = list(linewidth = .8)) 

grid3 <- grid::grid.draw(fig.theramon_slope_inc + 
                           fig.theramon_slope_stable + 
                           fig.theramon_slope_dec + 
                           plot_layout(ncol = 1) + 
                           plot_annotation(tag_levels = 'a'))
Figure 3.4: Individual participant trajectories. (a) increasing slope (slope >= 0.1), (b) constant slope (-0.1 ≤ slope ≤ 0.1 ), and (c) decreasing slope (slope < -0.1).

4 Linear mixed model

Subject-specific trajectories (Figure 3.3 and Figure 3.4) revealed extensive variation in wear_time.visit between subjects. Within each subject wear_time.visit was also fluctuating over time, and either slightly increasing, nearly constant, or decreasing (Figure 3.4).

Due to the nested structure of the data, a linear mixed model (LMM) was established to test the effect of time (variable visit; ordered), study arm* (variable study_arm; nominal; Group 1 (unaware) = 0, Group 2 (aware) = 1), and the fixed predictors (sex, age) on wear period specific wear time (h) (variable wear_time.visit), and potential interactions between them after controlling for subject (Id) variation.

4.1 Model selection

Models of different complexity were evaluated in this order:

  1. fit_lmer_1ml: Intercept model: first and second level predictors (visit and study_arm) and the random intercept (Id).
  2. fit_lmer_2aml: Potential interaction between visit and study_arm.
  3. fit_lmer_3aml: Addition of sex, and age.
  4. fit_lmer_4ml: Potential interaction between study_arm and sex.
  5. fit_lmer_4bml: Potential interaction between study_arm and age.

In all of the following steps, REML was deactivated (REML = FALSE) to ease model comparisons as suggested by the lme4 R package authors (Bates et al. 2015; Kuznetsova, Brockhoff, and Christensen 2017).

4.1.1 Intercept model

The first model (fit_lmer_1ml) consisted of wear_time.visit as response variable, visit (time; first level) and study_arm (groups; second level), and the subject-contributed random effects (Id). The latter were described by:

  1. the random intercept, which is an estimate for the variation of the intercept and as such wear time at visit (wear_time.visit) between subjects (Id).
  2. the level 1-residues, describing the variation of wear_time.visit within a study subject.
Show the code
set.seed(2)
options(width = 100)

fit_lmer_1ml <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + (1 | Id), data = theramon_long, REML = FALSE)
summary(fit_lmer_1ml)
Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's method [lmerModLmerTest]
Formula: wear_time.visit ~ visit + study_arm + (1 | Id)
   Data: theramon_long

      AIC       BIC    logLik -2*log(L)  df.resid 
     1080      1112      -531      1062       231 

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.148 -0.399  0.027  0.467  2.888 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 13.66    3.70    
 Residual              2.77    1.66    
Number of obs: 240, groups:  Id, 40

Fixed effects:
                         Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                14.161      0.874  46.741   16.21  < 2e-16 ***
visitT1-T2                  0.191      0.372 200.000    0.51    0.609    
visitT2-T3                 -0.158      0.372 200.000   -0.42    0.672    
visitT3-T4                 -0.458      0.372 200.000   -1.23    0.220    
visitT4-T5                 -0.784      0.372 200.000   -2.11    0.036 *  
visitT5-T6                 -1.652      0.372 200.000   -4.44  1.5e-05 ***
study_armGroup 2 (aware)    3.042      1.188  40.000    2.56    0.014 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6
visitT1-T2  -0.213                                   
visitT2-T3  -0.213  0.500                            
visitT3-T4  -0.213  0.500  0.500                     
visitT4-T5  -0.213  0.500  0.500  0.500              
visitT5-T6  -0.213  0.500  0.500  0.500  0.500       
stdy_rmG2() -0.680  0.000  0.000  0.000  0.000  0.000

4.1.2 Interaction between visit and study_arm

Next, a potential interaction between time and study arm (visit:study_arm) was analyzed and compared this model to the previous one without interaction, i.e., fit_lmer_1ml.

Show the code
set.seed(2)
options(width = 100)

fit_lmer_2ml <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + visit:study_arm + (1 | Id), data = theramon_long, REML = FALSE)
summary(fit_lmer_2ml) |> print(width = 100)
Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's method [lmerModLmerTest]
Formula: wear_time.visit ~ visit + study_arm + visit:study_arm + (1 |      Id)
   Data: theramon_long

      AIC       BIC    logLik -2*log(L)  df.resid 
     1088      1136      -530      1060       226 

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.157 -0.407  0.029  0.451  2.821 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 13.66    3.70    
 Residual              2.73    1.65    
Number of obs: 240, groups:  Id, 40

Fixed effects:
                                    Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)                          14.2615     0.9054  53.6636   15.75   <2e-16 ***
visitT1-T2                            0.2335     0.5227 200.0000    0.45   0.6556    
visitT2-T3                           -0.0700     0.5227 200.0000   -0.13   0.8936    
visitT3-T4                           -0.5290     0.5227 200.0000   -1.01   0.3127    
visitT4-T5                           -1.1745     0.5227 200.0000   -2.25   0.0257 *  
visitT5-T6                           -1.9250     0.5227 200.0000   -3.68   0.0003 ***
study_armGroup 2 (aware)              2.8405     1.2804  53.6636    2.22   0.0308 *  
visitT1-T2:study_armGroup 2 (aware)  -0.0855     0.7392 200.0000   -0.12   0.9080    
visitT2-T3:study_armGroup 2 (aware)  -0.1755     0.7392 200.0000   -0.24   0.8126    
visitT3-T4:study_armGroup 2 (aware)   0.1420     0.7392 200.0000    0.19   0.8479    
visitT4-T5:study_armGroup 2 (aware)   0.7800     0.7392 200.0000    1.06   0.2926    
visitT5-T6:study_armGroup 2 (aware)   0.5460     0.7392 200.0000    0.74   0.4610    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 s_G2() vT1-2( vT2-2( vT3-2( vT4-2(
visitT1-T2  -0.289                                                                      
visitT2-T3  -0.289  0.500                                                               
visitT3-T4  -0.289  0.500  0.500                                                        
visitT4-T5  -0.289  0.500  0.500  0.500                                                 
visitT5-T6  -0.289  0.500  0.500  0.500  0.500                                          
stdy_rmG2() -0.707  0.204  0.204  0.204  0.204  0.204                                   
vT1-T2:_G2(  0.204 -0.707 -0.354 -0.354 -0.354 -0.354 -0.289                            
vT2-T3:_G2(  0.204 -0.354 -0.707 -0.354 -0.354 -0.354 -0.289  0.500                     
vT3-T4:_G2(  0.204 -0.354 -0.354 -0.707 -0.354 -0.354 -0.289  0.500  0.500              
vT4-T5:_G2(  0.204 -0.354 -0.354 -0.354 -0.707 -0.354 -0.289  0.500  0.500  0.500       
vT5-T6:_G2(  0.204 -0.354 -0.354 -0.354 -0.354 -0.707 -0.289  0.500  0.500  0.500  0.500

To test, if the addition of study_arm:visit interaction was contributing further information to the fit_lmer_1ml model a likelihood ratio test was applied:

Show the code
set.seed(2)

anova(fit_lmer_1ml, fit_lmer_2ml)
Data: theramon_long
Models:
fit_lmer_1ml: wear_time.visit ~ visit + study_arm + (1 | Id)
fit_lmer_2ml: wear_time.visit ~ visit + study_arm + visit:study_arm + (1 | Id)
             npar  AIC  BIC logLik -2*log(L) Chisq Df Pr(>Chisq)
fit_lmer_1ml    9 1080 1112   -531      1062                    
fit_lmer_2ml   14 1088 1136   -530      1060  2.63  5       0.76

According to this results, the interaction between visit and study_arm was not significant. Therefore, this interaction was not further considered and we continued with the less complex model fit_lmer_1ml.

4.1.3 Addition of the level-invariant predictors sex and age

Next, we added the level-invariant predictors sex and ageto the model from the previous step, yielding model

fit_lmer_3aml: wear_time.visit ~ visit + study_arm + sex + age + (1|Id).

To avoid, that the reference of age is set to 0 years, the minimum age of this patient cohort (i.e., 17.2 years) was subtracted from age to yield age-min(age) as reference.

The model’s summary is shown next:

Show the code
set.seed(2)
options(width = 100)
options(digits = 3)

fit_lmer_3aml <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + sex + I(age-17.2) + (1 | Id), data = theramon_long, REML = FALSE)
summary(fit_lmer_3aml)
Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's method [lmerModLmerTest]
Formula: wear_time.visit ~ visit + study_arm + sex + I(age - 17.2) + (1 |      Id)
   Data: theramon_long

      AIC       BIC    logLik -2*log(L)  df.resid 
     1079      1117      -528      1057       229 

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.194 -0.393  0.023  0.459  2.909 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 11.90    3.45    
 Residual              2.77    1.66    
Number of obs: 240, groups:  Id, 40

Fixed effects:
                         Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)               13.2071     1.3369  42.7026    9.88  1.3e-12 ***
visitT1-T2                 0.1908     0.3720 200.0000    0.51   0.6087    
visitT2-T3                -0.1577     0.3720 200.0000   -0.42   0.6720    
visitT3-T4                -0.4580     0.3720 200.0000   -1.23   0.2197    
visitT4-T5                -0.7845     0.3720 200.0000   -2.11   0.0362 *  
visitT5-T6                -1.6520     0.3720 200.0000   -4.44  1.5e-05 ***
study_armGroup 2 (aware)   3.6353     1.1460  40.0000    3.17   0.0029 ** 
sexFemale                  2.5751     1.2357  40.0000    2.08   0.0436 *  
I(age - 17.2)             -0.0602     0.0411  40.0000   -1.46   0.1511    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 s_G2() sexFml
visitT1-T2  -0.139                                                 
visitT2-T3  -0.139  0.500                                          
visitT3-T4  -0.139  0.500  0.500                                   
visitT4-T5  -0.139  0.500  0.500  0.500                            
visitT5-T6  -0.139  0.500  0.500  0.500  0.500                     
stdy_rmG2() -0.392  0.000  0.000  0.000  0.000  0.000              
sexFemale   -0.615  0.000  0.000  0.000  0.000  0.000  0.139       
I(age-17.2) -0.391  0.000  0.000  0.000  0.000  0.000 -0.217 -0.156

Next, we tested if either age (i.e., I(age-17.2)) or sex were significantly contributing to the model using a likelihood ratio test.

Show the code
set.seed(2)

anova(fit_lmer_3aml)
Type III Analysis of Variance Table with Satterthwaite's method
              Sum Sq Mean Sq NumDF DenDF F value  Pr(>F)    
visit           90.0   18.01     5   200    6.50 1.3e-05 ***
study_arm       27.9   27.86     1    40   10.06  0.0029 ** 
sex             12.0   12.02     1    40    4.34  0.0436 *  
I(age - 17.2)    5.9    5.93     1    40    2.14  0.1511    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

According to these results, age was not significant and thus removed from the model.

We continued with model fit_lmer_3ml containing visit, study_arm, and sex as predictors, and Id as random intercept:

Show the code
set.seed(2)
options(width = 100)
options(digits = 3)

fit_lmer_3ml <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + sex + (1 | Id), data = theramon_long, REML = FALSE)
summary(fit_lmer_3ml)
Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's method [lmerModLmerTest]
Formula: wear_time.visit ~ visit + study_arm + sex + (1 | Id)
   Data: theramon_long

      AIC       BIC    logLik -2*log(L)  df.resid 
     1079      1114      -530      1059       230 

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.167 -0.382  0.026  0.456  2.921 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 12.57    3.54    
 Residual              2.77    1.66    
Number of obs: 240, groups:  Id, 40

Fixed effects:
                         Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                12.442      1.262  43.052    9.86  1.3e-12 ***
visitT1-T2                  0.191      0.372 200.000    0.51   0.6087    
visitT2-T3                 -0.158      0.372 200.000   -0.42   0.6720    
visitT3-T4                 -0.458      0.372 200.000   -1.23   0.2197    
visitT4-T5                 -0.784      0.372 200.000   -2.11   0.0362 *  
visitT5-T6                 -1.652      0.372 200.000   -4.44  1.5e-05 ***
study_armGroup 2 (aware)    3.271      1.148  40.000    2.85   0.0069 ** 
sexFemale                   2.292      1.253  40.000    1.83   0.0748 .  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 s_G2()
visitT1-T2  -0.147                                          
visitT2-T3  -0.147  0.500                                   
visitT3-T4  -0.147  0.500  0.500                            
visitT4-T5  -0.147  0.500  0.500  0.500                     
visitT5-T6  -0.147  0.500  0.500  0.500  0.500              
stdy_rmG2() -0.531  0.000  0.000  0.000  0.000  0.000       
sexFemale   -0.745  0.000  0.000  0.000  0.000  0.000  0.109

4.1.4 Interaction between study_arm and sex

Then, a potential interaction between study_arm and sex (i.e., study_arm:sex) was tested, yielding fit_lmer_4ml.

Show the code
set.seed(2)
options(width = 100)

fit_lmer_4ml <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 | Id), data = theramon_long, REML = FALSE)
summary(fit_lmer_4ml)
Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's method [lmerModLmerTest]
Formula: wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 |      Id)
   Data: theramon_long

      AIC       BIC    logLik -2*log(L)  df.resid 
     1076      1114      -527      1054       229 

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.152 -0.397  0.023  0.468  2.973 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 10.99    3.31    
 Residual              2.77    1.66    
Number of obs: 240, groups:  Id, 40

Fixed effects:
                                   Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                          10.165      1.532  42.035    6.63  4.8e-08 ***
visitT1-T2                            0.191      0.372 200.000    0.51  0.60871    
visitT2-T3                           -0.158      0.372 200.000   -0.42  0.67201    
visitT3-T4                           -0.458      0.372 200.000   -1.23  0.21974    
visitT4-T5                           -0.784      0.372 200.000   -2.11  0.03622 *  
visitT5-T6                           -1.652      0.372 200.000   -4.44  1.5e-05 ***
study_armGroup 2 (aware)              7.174      1.981  40.000    3.62  0.00082 ***
sexFemale                             5.328      1.747  40.000    3.05  0.00406 ** 
study_armGroup 2 (aware):sexFemale   -5.538      2.360  40.000   -2.35  0.02399 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 st_G2() sexFml
visitT1-T2  -0.121                                                  
visitT2-T3  -0.121  0.500                                           
visitT3-T4  -0.121  0.500  0.500                                    
visitT4-T5  -0.121  0.500  0.500  0.500                             
visitT5-T6  -0.121  0.500  0.500  0.500  0.500                      
stdy_rmG2() -0.754  0.000  0.000  0.000  0.000  0.000               
sexFemale   -0.855  0.000  0.000  0.000  0.000  0.000  0.661        
stdy_G2():F  0.633  0.000  0.000  0.000  0.000  0.000 -0.840  -0.740

4.1.5 Model comparison

Model comparison between the ‘null’ model and the models accepted so far (Table 4.1).

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg")

sjPlot::tab_model(fit_lmer_1ml, fit_lmer_3ml, fit_lmer_4ml, show.reflvl = TRUE, p.val = "satterthwaite", df.method = "satterthwaite",
                  show.aic = TRUE, show.loglik = TRUE,
                  dv.labels = c("fit_lmer_1ml", "fit_lmer_3ml", "fit_lmer_4ml"))
Table 4.1: Model comparision between the models fit_lmer_1ml, fit_lmer_3ml, and fit_lmer_4aml.
  fit_lmer_1ml fit_lmer_3ml fit_lmer_4ml
Predictors Estimates CI p Estimates CI p Estimates CI p
(Intercept) 14.16 12.40 – 15.92 <0.001 12.44 9.90 – 14.99 <0.001 10.16 7.07 – 13.26 <0.001
T0-T1 Reference Reference Reference
T1-T2 0.19 -0.54 – 0.92 0.609 0.19 -0.54 – 0.92 0.609 0.19 -0.54 – 0.92 0.609
T2-T3 -0.16 -0.89 – 0.58 0.672 -0.16 -0.89 – 0.58 0.672 -0.16 -0.89 – 0.58 0.672
T3-T4 -0.46 -1.19 – 0.28 0.220 -0.46 -1.19 – 0.28 0.220 -0.46 -1.19 – 0.28 0.220
study_armGroup 2 (aware):sexFemale -5.54 -10.31 – -0.77 0.024
T4-T5 -0.78 -1.52 – -0.05 0.036 -0.78 -1.52 – -0.05 0.036 -0.78 -1.52 – -0.05 0.036
T5-T6 -1.65 -2.39 – -0.92 <0.001 -1.65 -2.39 – -0.92 <0.001 -1.65 -2.39 – -0.92 <0.001
Group 1 (unaware) Reference Reference Reference
Group 2 (aware) 3.04 0.64 – 5.44 0.014 3.27 0.95 – 5.59 0.007 7.17 3.17 – 11.18 0.001
Male Reference Reference Reference
Female 2.29 -0.24 – 4.82 0.075 5.33 1.80 – 8.86 0.004
Random Effects
σ2 2.77 2.77 2.77
τ00 13.66 Id 12.57 Id 10.99 Id
ICC 0.83 0.82 0.80
N 40 Id 40 Id 40 Id
Observations 240 240 240
Marginal R2 / Conditional R2 0.141 / 0.855 0.198 / 0.855 0.281 / 0.855
AIC 1079.586 1076.211 1069.848
log-Likelihood -531.148 -529.540 -526.961

Additionally, the performance of these models using compare_performance() (the “performance” R package) was compared (Table 4.2).

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg")

performance::compare_performance(fit_lmer_1ml, fit_lmer_3ml, fit_lmer_4ml, rank = TRUE) |> 
  select("Name", "R2_conditional", "R2_marginal", "ICC", "RMSE", "Sigma", "AIC_wt", "AICc_wt", "BIC_wt", "Performance_Score") |>
  rename("R2 cond." = R2_conditional,
         "R2 marg." = R2_marginal,
         "Performance Score" = Performance_Score) |>
  as_flextable() |> 
  colformat_double(digits = 3) |>
  bold(bold = TRUE, part = "header") |> autofit()
Table 4.2: Ranked mixed model performance.

Name

R2 cond.

R2 marg.

ICC

RMSE

Sigma

AIC_wt

AICc_wt

BIC_wt

Performance Score

character

numeric

numeric

numeric

numeric

numeric

numeric

numeric

numeric

numeric

fit_lmer_4ml

0.855

0.281

0.799

1.525

1.664

0.758

0.734

0.172

0.625

fit_lmer_1ml

0.855

0.141

0.831

1.524

1.664

0.085

0.099

0.626

0.387

fit_lmer_3ml

0.855

0.198

0.819

1.524

1.664

0.156

0.167

0.202

0.296

n: 3

Taken together, we accepted fit_lmer_4ml.

4.2 Accepted model

4.2.1 General description of the accepted model

The formula of the accepted model was:

wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 | Id).

This time, REML was enabled. Degrees of freedom and p-values were calculated with the Kenward-Roger approximation.

Show the code
set.seed(2)
options(width = 100)

final <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 | Id), data = theramon_long, REML = TRUE)

# Degrees of freedom and t-statistics were computed using Kenward-Roger's method.
summary(final, ddf = "Kenward-Roger")
Linear mixed model fit by REML. t-tests use Kenward-Roger's method ['lmerModLmerTest']
Formula: wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 |      Id)
   Data: theramon_long

REML criterion at convergence: 1048

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.097 -0.396  0.021  0.463  2.933 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 12.25    3.50    
 Residual              2.84    1.68    
Number of obs: 240, groups:  Id, 40

Fixed effects:
                                   Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                          10.165      1.614  37.689    6.30  2.3e-07 ***
visitT1-T2                            0.191      0.377 195.000    0.51   0.6132    
visitT2-T3                           -0.158      0.377 195.000   -0.42   0.6759    
visitT3-T4                           -0.458      0.377 195.000   -1.22   0.2256    
visitT4-T5                           -0.784      0.377 195.000   -2.08   0.0386 *  
visitT5-T6                           -1.652      0.377 195.000   -4.38  1.9e-05 ***
study_armGroup 2 (aware)              7.174      2.089  36.000    3.43   0.0015 ** 
sexFemale                             5.328      1.842  36.000    2.89   0.0064 ** 
study_armGroup 2 (aware):sexFemale   -5.538      2.488  36.000   -2.23   0.0324 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 st_G2() sexFml
visitT1-T2  -0.117                                                  
visitT2-T3  -0.117  0.500                                           
visitT3-T4  -0.117  0.500  0.500                                    
visitT4-T5  -0.117  0.500  0.500  0.500                             
visitT5-T6  -0.117  0.500  0.500  0.500  0.500                      
stdy_rmG2() -0.755  0.000  0.000  0.000  0.000  0.000               
sexFemale   -0.856  0.000  0.000  0.000  0.000  0.000  0.661        
stdy_G2():F  0.634  0.000  0.000  0.000  0.000  0.000 -0.840  -0.740

The model’s performance (performance::performance(final)) is summarized in Table 4.3.

Show the code
set.seed(2)

performance::performance(final) |>
  rename("R2_cond" = R2_conditional,
         "R2_marg" = R2_marginal) |>
  flextable() |> 
  colformat_double(j = c("AIC", "AICc", "BIC"), digits = 0) |>
  colformat_double(j = c("R2_cond", "R2_marg", "ICC", "RMSE", "Sigma"), digits = 3) |>
  bold(bold = TRUE, part = "header") |> 
  set_table_properties(layout = "autofit")
Table 4.3: Performance of the accepted model final.

AIC

AICc

BIC

R2_cond

R2_marg

ICC

RMSE

Sigma

1,070

1,071

1,108

0.861

0.263

0.812

1.524

1.685

4.2.2 LMM model assumptions

The final model was then analyzed for deviations from the assumptions of linear mixed models using performance::check_model() from the “performance” R package (Figure 4.1).

Show the code
final_performance.fig <- performance::check_model(final)
final_performance.fig

# cairo_pdf("Fig_S4 final_performance.pdf", family = "sans", height = 15, width = 10)
# final_performance.fig
# dev.off()
Figure 4.1: Accepted model overview. Visual check of various model assumptions using performance::check_model().

4.2.2.1 Heteroscedasticity

Checking the assumption of heteroscedasticity using the Breusch-Pagan test was applied as implemented in the check_heteroscedasticity() function implemented in the “performance” R package (Lüdecke et al. 2021) and depicted (Figure 4.2)

Show the code
plot(performance::check_heteroscedasticity(final))
Figure 4.2: Check for homogeneity of variance
Show the code
performance::check_heteroscedasticity(final)
OK: Error variance appears to be homoscedastic (p = 0.209).

4.2.2.2 Outliers

Check for potential outliers using check_outliers() from the “performance” R package using Cook’s distance.

Show the code
performance::check_outliers(final)
1 outlier detected: case 145.
- Based on the following method and threshold: cook (0.5).
- For variable: (Whole model).

Observation “145” (Id = 3, visit = T3-T4) was identified as a potential outlier according to Cook’s distance. The related data is summarized in the following table (Table 4.4).

Show the code
theramon_long |>
  mutate(Row = row_number()) |>
  filter(Row == 145) |>
  select(Row, Id, study_arm, sex, visit, wear_time.visit) |>
  flextable() |> 
  colformat_num(digits = 3) |>
  colformat_double(digits = 1) |>
  bold(bold = TRUE, part = "header") |> 
  set_table_properties(layout = "autofit")
Table 4.4: Observations identified as potential outliers by observation #145.

Row

Id

Study arm

Sex

Period

WT at visit (h)

145

3

Group 2 (aware)

Female

T3-T4

8.6

A sensitivity analysis was done (see to section Section 4.2.4 for details).

4.2.2.3 multicollinearity of model terms

Multicollinearity of the model terms was assessed with check_collinerarity() from the “performance” R package (Lüdecke et al. 2021) by calculating the (generalized) variance inflation factor (VIF) (Table 4.5).

Show the code
performance::check_collinearity(final) |>
  rename("VIF\n CI.l" = VIF_CI_low,
         "VIF\n CI.h" = VIF_CI_high,
         "SE\n factor" = SE_factor,
         "Tolerance\n CI.l" = Tolerance_CI_low,
         "Tolerance\n CI.h" = Tolerance_CI_high) |>
  flextable() |> 
  colformat_num(digits = 3) |>
  colformat_double(digits = 2) |>
  bold(bold = TRUE, part = "header") |> 
  autofit()
  #set_table_properties(layout = "autofit")
Table 4.5: Collinarity check

Term

VIF

VIF
CI.l

VIF
CI.h

SE
factor

Tolerance

Tolerance
CI.l

Tolerance
CI.h

visit

1.00

1.00

1.00

study_arm

3.43

2.82

4.25

1.85

0.29

0.24

0.36

sex

2.24

1.88

2.74

1.50

0.45

0.37

0.53

study_arm:sex

4.27

3.48

5.32

2.07

0.23

0.19

0.29

For all predictors, the VIF was <5. This indicated a low correlation of that predictor with the other predictors.

4.2.2.4 Normality

The model check for (non-)normality of residuals was done using a Q-Q and density plots (check_normality from R package “performance”) (Figure 4.3). This command checks the studentized residuals of a mixed model for normal distribution.

Visual inspection of this plot showed a deviation from normal distribution especially in the lower (i.e., left) tail of the distribution.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg") 

plot(performance::check_normality(final), type = "qq")

plot(performance::check_normality(final), type = "density")
(a) Q-Q plot
(b) Density plot
Figure 4.3: Check normality of residuals.

4.2.2.5 Uniformity of ranodmized quantile residuals

To test the model for uniformity of randomized quantile residuals, the command check_residuals() (R package “performance”) was applied to the final model. This function “checks generalized linear (mixed) models for uniformity of randomized quantile residuals, which can be used to identify typical model misspecification problems, such as over/underdispersion, zero-inflation, and residual spatial and temporal autocorrelation. … [This is done by simulated quantile residuals.] … The command then ”tests the distribution of the quantile residuals against the uniform distribution using a Kolmogorov-Smirnov test.” (from the help page of this function)

Show the code
final.res <- performance::simulate_residuals(final)

performance::check_residuals(final.res)
OK: Simulated residuals appear as uniformly distributed (p = 0.271).

4.2.3 Model description

4.2.3.1 Model parameters

Summary of the finally ‘accepted’ model is shown in Table 4.6. P-values (and degrees of freedom) were calculated using Kenward-Roger’s method.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg")

sjPlot::tab_model(final, show.reflvl = TRUE, p.val = "kr", df.method = "kr", dv.labels = c("Accepted model"))
Table 4.6: Comparision of model summarys of the full final model.
  Accepted model
Predictors Estimates CI p
(Intercept) 10.16 6.90 – 13.43 <0.001
T0-T1 Reference
T1-T2 0.19 -0.55 – 0.93 0.613
T2-T3 -0.16 -0.90 – 0.59 0.676
T3-T4 -0.46 -1.20 – 0.29 0.226
study_armGroup 2 (aware):sexFemale -5.54 -10.58 – -0.49 0.032
T4-T5 -0.78 -1.53 – -0.04 0.039
T5-T6 -1.65 -2.40 – -0.91 <0.001
Group 1 (unaware) Reference
Group 2 (aware) 7.17 2.94 – 11.41 0.002
Male Reference
Female 5.33 1.59 – 9.06 0.006
Random Effects
σ2 2.84
τ00 Id 12.25
ICC 0.81
N Id 40
Observations 240
Marginal R2 / Conditional R2 0.263 / 0.861

The model and its results were reported as follows using the report() (“reports” R package) applying Kenward-Roger’s method for 95% CI calculation.

Show the code
set.seed(2)
options(width = 100)

# parameters::standardize_parameters
# standardize_parameters(m, method = "pseudo", ci_method = "satterthwaite") => ci_method: ci_kenward

report::report(final, ci_method = "kenward")
We fitted a linear mixed model (estimated using REML and nloptwrap optimizer) to predict
wear_time.visit with visit, study_arm and sex (formula: wear_time.visit ~ visit + study_arm + sex +
study_arm:sex). The model included Id as random effect (formula: ~1 | Id). The model's total
explanatory power is substantial (conditional R2 = 0.86) and the part related to the fixed effects
alone (marginal R2) is of 0.26. The model's intercept, corresponding to visit = T0-T1, study_arm =
Group 1 (unaware) and sex = Male, is at 10.16 (95% CI [6.90, 13.43], t(37.69) = 6.30, p < .001).
Within this model:

  - The effect of visit [T1-T2] is statistically non-significant and positive (beta = 0.19, 95% CI
[-0.55, 0.93], t(195.00) = 0.51, p = 0.613; Std. beta = 0.04, 95% CI [-0.13, 0.21])
  - The effect of visit [T2-T3] is statistically non-significant and negative (beta = -0.16, 95% CI
[-0.90, 0.59], t(195.00) = -0.42, p = 0.676; Std. beta = -0.04, 95% CI [-0.21, 0.13])
  - The effect of visit [T3-T4] is statistically non-significant and negative (beta = -0.46, 95% CI
[-1.20, 0.29], t(195.00) = -1.22, p = 0.226; Std. beta = -0.10, 95% CI [-0.27, 0.07])
  - The effect of visit [T4-T5] is statistically significant and negative (beta = -0.78, 95% CI
[-1.53, -0.04], t(195.00) = -2.08, p = 0.039; Std. beta = -0.18, 95% CI [-0.35, -9.46e-03])
  - The effect of visit [T5-T6] is statistically significant and negative (beta = -1.65, 95% CI
[-2.40, -0.91], t(195.00) = -4.38, p < .001; Std. beta = -0.38, 95% CI [-0.55, -0.21])
  - The effect of study arm [Group 2 (aware)] is statistically significant and positive (beta = 7.17,
95% CI [2.94, 11.41], t(36.00) = 3.43, p = 0.002; Std. beta = 1.64, 95% CI [0.67, 2.60])
  - The effect of sex [Female] is statistically significant and positive (beta = 5.33, 95% CI [1.59,
9.06], t(36.00) = 2.89, p = 0.006; Std. beta = 1.22, 95% CI [0.36, 2.07])
  - The effect of study arm [Group 2 (aware)] × sex [Female] is statistically significant and
negative (beta = -5.54, 95% CI [-10.58, -0.49], t(36.00) = -2.23, p = 0.032; Std. beta = -1.26, 95%
CI [-2.42, -0.11])

Standardized parameters were obtained by fitting the model on a standardized version of the
dataset. 95% Confidence Intervals (CIs) and p-values were computed using a Wald t-distribution with
Kenward-Roger approximation.

4.2.3.2 Model figures

Figure 4.4 depicts the plots from the final model showing the random estimates and marginal effects next to each other.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg") 

fig.final_random <- sjPlot::plot_model(final, type = "re", colors = "bw", title = "", ci_method = "kenward") + 
  theme_bw() + 
  theme(legend.position = "bottom")
fig.LMM_interaction2 <- sjPlot::plot_model(final, type = "pred", terms = c("visit", "sex", "study_arm"), title = "", ci_method = "kenward") + 
  theme_bw() + 
  theme(legend.position = "bottom")

grid4 <- grid::grid.draw(fig.final_random + fig.LMM_interaction2  + plot_layout(nrow = 1, width = c(1,2))  + plot_annotation(tag_levels = 'a'))

ggsave("Fig_5 panel_LMM_intersection.pdf", plot = grid4, device = cairo_pdf, units = "in", width = 10, height = 5, dpi = 300)
ggsave("Fig_5 panel_LMM_intersection.png", plot = grid4, device = png, units = "in", width = 10, height = 5, dpi = 300)
Figure 4.4: Plots from the final model (Kenward-Roger). (a) Forest plot of random effects by subject’s Id. (b) Plot of the predicted values (marginal effects) for wear_time.visit by visit, study_arm and sex.

Fitting the final LMM to Figure 3.3 resulted in the following Figure 4.5:

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg") 

theramon_long.lmer <- theramon_long |>
  mutate(final.fixef = predict(final, re.form = NA),   # exclude all random effects (cf. lme4::predict.merMod)
         final.ranef = predict(final, re.form =~(1|Id))) # include all random effects

fig.wear_time.Id_lmm <- theramon_long.lmer |>
  ggplot(aes(x = visit, y = wear_time.visit, group = 1)) +
  geom_point(shape = 21, size = 2, fill = "white") +
  # geom_smooth(method = "lm", se = FALSE, aes(alpha = "OLS"), colour = "black", linewidth = 0.5) +
  geom_line(aes(y = final.fixef, alpha = "fixed effects only"), colour = "blue", linewidth = 0.7, linetype = 1) + 
  geom_line(aes(y = final.ranef, alpha = "fixed and random effects"), colour = "green", linewidth = 0.7, linetype = 1) +
  guides(shape = "none") +
  labs(x = "Wear period", y = "Wear time (h)") + 
  scale_y_continuous(limit = c(0, 30), breaks = seq(0, 30, by = 10), expand = c(0,0)) +
  scale_alpha_manual(name = NULL, values = c(1,1), breaks = c("fixed effects only", "fixed and random effects")) +
  facet_wrap(facet = vars(Id), ncol = 5, labeller = case_names) +
  theme_bw(base_size = 14) +
  theme(legend.position = "bottom") +
  theme(panel.grid.major.y = element_line(colour = "lightgrey", linetype = "dashed"),
        panel.grid.minor.y = element_blank(), panel.grid.major.x = element_blank()) +
  theme(strip.text.x = element_text(size = 11, color = "black", face = "bold")) +
  theme(axis.text.x = element_text(angle = 30, vjust = 0.8, hjust = 0.8))

fig.wear_time.Id_lmm
Figure 4.5: Mean WT for each individual case across the six follow-up appointments: prediction using fixed effects only and including random effects.

4.2.3.3 Multiple comparisions

Using functions from the “emmeans” package (Lenth 2025), marginal means (aka Least-Squares Means) and contrasts were calculated for specified factors or factor combinations from the final model. The p-values are based on the t-distribution using degres of freedom based on Kenward-Roger’s method. Adjustments for multiple comparisons were not applied, instead unadjusted p-values were reported.

Show the code
options(width = 100)
set.seed(2)

final.allsets <- emmeans::lsmeans(final, ".", lmer.df = "k")

cat("\n")
Show the code
cat("*** contrast(final.allsets, revpairwise, lmer.df = k, adjust = none) ***\n")
*** contrast(final.allsets, revpairwise, lmer.df = k, adjust = none) ***
Show the code
cat("\n")
Show the code
emmeans::contrast(final.allsets, "revpairwise", lmer.df = "k", adjust = "none")
$`contrasts of lsmeans of visit`
 contrast          estimate    SE  df t.ratio p.value
 (T1-T2) - (T0-T1)    0.191 0.377 195   0.510  0.6130
 (T2-T3) - (T0-T1)   -0.158 0.377 195  -0.420  0.6760
 (T2-T3) - (T1-T2)   -0.348 0.377 195  -0.920  0.3560
 (T3-T4) - (T0-T1)   -0.458 0.377 195  -1.220  0.2260
 (T3-T4) - (T1-T2)   -0.649 0.377 195  -1.720  0.0870
 (T3-T4) - (T2-T3)   -0.300 0.377 195  -0.800  0.4260
 (T4-T5) - (T0-T1)   -0.784 0.377 195  -2.080  0.0390
 (T4-T5) - (T1-T2)   -0.975 0.377 195  -2.590  0.0100
 (T4-T5) - (T2-T3)   -0.627 0.377 195  -1.660  0.0980
 (T4-T5) - (T3-T4)   -0.327 0.377 195  -0.870  0.3870
 (T5-T6) - (T0-T1)   -1.652 0.377 195  -4.380  <.0001
 (T5-T6) - (T1-T2)   -1.843 0.377 195  -4.890  <.0001
 (T5-T6) - (T2-T3)   -1.494 0.377 195  -3.970  <.0001
 (T5-T6) - (T3-T4)   -1.194 0.377 195  -3.170  0.0020
 (T5-T6) - (T4-T5)   -0.867 0.377 195  -2.300  0.0220

Results are averaged over the levels of: study_arm, sex 
Degrees-of-freedom method: kenward-roger 

$`contrasts of lsmeans of study_arm`
 contrast                            estimate   SE df t.ratio p.value
 Group 2 (aware) - Group 1 (unaware)     4.41 1.24 36   3.540  0.0011

Results are averaged over the levels of: visit, sex 
Degrees-of-freedom method: kenward-roger 

$`contrasts of lsmeans of sex`
 contrast      estimate   SE df t.ratio p.value
 Female - Male     2.56 1.24 36   2.057  0.0470

Results are averaged over the levels of: visit, study_arm 
Degrees-of-freedom method: kenward-roger 

$`contrasts of lsmeans of study_arm, sex`
 contrast                                          estimate   SE df t.ratio p.value
 Group 2 (aware) Male - Group 1 (unaware) Male         7.17 2.09 36   3.430  0.0020
 Group 1 (unaware) Female - Group 1 (unaware) Male     5.33 1.84 36   2.890  0.0060
 Group 1 (unaware) Female - Group 2 (aware) Male      -1.85 1.63 36  -1.130  0.2660
 Group 2 (aware) Female - Group 1 (unaware) Male       6.96 1.88 36   3.710  0.0010
 Group 2 (aware) Female - Group 2 (aware) Male        -0.21 1.67 36  -0.130  0.9010
 Group 2 (aware) Female - Group 1 (unaware) Female     1.64 1.35 36   1.210  0.2340

Results are averaged over the levels of: visit 
Degrees-of-freedom method: kenward-roger 
Show the code
cat("\n ... and confidence intervals ... ")

 ... and confidence intervals ... 
Show the code
cat("\n")
Show the code
confint(emmeans::contrast(final.allsets, "revpairwise", lmer.df = "k", adjust = "none"))
$`contrasts of lsmeans of visit`
 contrast          estimate    SE  df lower.CL upper.CL
 (T1-T2) - (T0-T1)    0.191 0.377 195   -0.552    0.934
 (T2-T3) - (T0-T1)   -0.158 0.377 195   -0.901    0.585
 (T2-T3) - (T1-T2)   -0.348 0.377 195   -1.092    0.395
 (T3-T4) - (T0-T1)   -0.458 0.377 195   -1.201    0.285
 (T3-T4) - (T1-T2)   -0.649 0.377 195   -1.392    0.094
 (T3-T4) - (T2-T3)   -0.300 0.377 195   -1.043    0.443
 (T4-T5) - (T0-T1)   -0.784 0.377 195   -1.528   -0.041
 (T4-T5) - (T1-T2)   -0.975 0.377 195   -1.718   -0.232
 (T4-T5) - (T2-T3)   -0.627 0.377 195   -1.370    0.116
 (T4-T5) - (T3-T4)   -0.327 0.377 195   -1.070    0.417
 (T5-T6) - (T0-T1)   -1.652 0.377 195   -2.395   -0.909
 (T5-T6) - (T1-T2)   -1.843 0.377 195   -2.586   -1.100
 (T5-T6) - (T2-T3)   -1.494 0.377 195   -2.237   -0.751
 (T5-T6) - (T3-T4)   -1.194 0.377 195   -1.937   -0.451
 (T5-T6) - (T4-T5)   -0.867 0.377 195   -1.611   -0.124

Results are averaged over the levels of: study_arm, sex 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`contrasts of lsmeans of study_arm`
 contrast                            estimate   SE df lower.CL upper.CL
 Group 2 (aware) - Group 1 (unaware)     4.41 1.24 36     1.88     6.93

Results are averaged over the levels of: visit, sex 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`contrasts of lsmeans of sex`
 contrast      estimate   SE df lower.CL upper.CL
 Female - Male     2.56 1.24 36   0.0363     5.08

Results are averaged over the levels of: visit, study_arm 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`contrasts of lsmeans of study_arm, sex`
 contrast                                          estimate   SE df lower.CL upper.CL
 Group 2 (aware) Male - Group 1 (unaware) Male         7.17 2.09 36     2.94    11.41
 Group 1 (unaware) Female - Group 1 (unaware) Male     5.33 1.84 36     1.59     9.06
 Group 1 (unaware) Female - Group 2 (aware) Male      -1.85 1.63 36    -5.16     1.47
 Group 2 (aware) Female - Group 1 (unaware) Male       6.96 1.88 36     3.16    10.77
 Group 2 (aware) Female - Group 2 (aware) Male        -0.21 1.67 36    -3.60     3.18
 Group 2 (aware) Female - Group 1 (unaware) Female     1.64 1.35 36    -1.11     4.38

Results are averaged over the levels of: visit 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 
Show the code
cat("******************** \n")
******************** 
Show the code
cat("\n")

The following summarized the contrasts extracted from the `final’ model:

Show the code
set.seed(2)
options(width = 150)

# emmeans(final, ~ visit|study_arm*sex) |> contrast(interaction = c("consec", "consec", "consec"), simple = "each", combine = TRUE, adjust = "none")
# emmeans(final, ~ visit|study_arm*sex) |> contrast(interaction = c("consec", "consec", "consec"), simple = "each", combine = TRUE) |> confint(pairs, reverse = TRUE)

cat("\n")
Show the code
cat("*** emmeans(final, ~ visit|study_arm*sex) |> contrast(consec, simple = each, combine = TRUE) NOT adjusted! ***\n")
*** emmeans(final, ~ visit|study_arm*sex) |> contrast(consec, simple = each, combine = TRUE) NOT adjusted! ***
Show the code
cat("\n")
Show the code
emmeans::lsmeans(final, ~ visit|study_arm*sex, lmer.df = "k") |> 
  emmeans::contrast("consec", simple = "each", combine = TRUE, adjust = "none")
 study_arm         sex    visit contrast                            estimate    SE  df t.ratio p.value
 Group 1 (unaware) Male   .     (T1-T2) - (T0-T1)                       0.19 0.377 195   0.510  0.6130
 Group 1 (unaware) Male   .     (T2-T3) - (T1-T2)                      -0.35 0.377 195  -0.920  0.3560
 Group 1 (unaware) Male   .     (T3-T4) - (T2-T3)                      -0.30 0.377 195  -0.800  0.4260
 Group 1 (unaware) Male   .     (T4-T5) - (T3-T4)                      -0.33 0.377 195  -0.870  0.3870
 Group 1 (unaware) Male   .     (T5-T6) - (T4-T5)                      -0.87 0.377 195  -2.300  0.0220
 Group 2 (aware)   Male   .     (T1-T2) - (T0-T1)                       0.19 0.377 195   0.510  0.6130
 Group 2 (aware)   Male   .     (T2-T3) - (T1-T2)                      -0.35 0.377 195  -0.920  0.3560
 Group 2 (aware)   Male   .     (T3-T4) - (T2-T3)                      -0.30 0.377 195  -0.800  0.4260
 Group 2 (aware)   Male   .     (T4-T5) - (T3-T4)                      -0.33 0.377 195  -0.870  0.3870
 Group 2 (aware)   Male   .     (T5-T6) - (T4-T5)                      -0.87 0.377 195  -2.300  0.0220
 Group 1 (unaware) Female .     (T1-T2) - (T0-T1)                       0.19 0.377 195   0.510  0.6130
 Group 1 (unaware) Female .     (T2-T3) - (T1-T2)                      -0.35 0.377 195  -0.920  0.3560
 Group 1 (unaware) Female .     (T3-T4) - (T2-T3)                      -0.30 0.377 195  -0.800  0.4260
 Group 1 (unaware) Female .     (T4-T5) - (T3-T4)                      -0.33 0.377 195  -0.870  0.3870
 Group 1 (unaware) Female .     (T5-T6) - (T4-T5)                      -0.87 0.377 195  -2.300  0.0220
 Group 2 (aware)   Female .     (T1-T2) - (T0-T1)                       0.19 0.377 195   0.510  0.6130
 Group 2 (aware)   Female .     (T2-T3) - (T1-T2)                      -0.35 0.377 195  -0.920  0.3560
 Group 2 (aware)   Female .     (T3-T4) - (T2-T3)                      -0.30 0.377 195  -0.800  0.4260
 Group 2 (aware)   Female .     (T4-T5) - (T3-T4)                      -0.33 0.377 195  -0.870  0.3870
 Group 2 (aware)   Female .     (T5-T6) - (T4-T5)                      -0.87 0.377 195  -2.300  0.0220
 .                 Male   T0-T1 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36   3.430  0.0020
 .                 Male   T1-T2 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36   3.430  0.0020
 .                 Male   T2-T3 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36   3.430  0.0020
 .                 Male   T3-T4 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36   3.430  0.0020
 .                 Male   T4-T5 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36   3.430  0.0020
 .                 Male   T5-T6 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36   3.430  0.0020
 .                 Female T0-T1 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36   1.210  0.2340
 .                 Female T1-T2 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36   1.210  0.2340
 .                 Female T2-T3 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36   1.210  0.2340
 .                 Female T3-T4 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36   1.210  0.2340
 .                 Female T4-T5 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36   1.210  0.2340
 .                 Female T5-T6 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36   1.210  0.2340
 Group 1 (unaware) .      T0-T1 Female - Male                           5.33 1.840  36   2.890  0.0060
 Group 1 (unaware) .      T1-T2 Female - Male                           5.33 1.840  36   2.890  0.0060
 Group 1 (unaware) .      T2-T3 Female - Male                           5.33 1.840  36   2.890  0.0060
 Group 1 (unaware) .      T3-T4 Female - Male                           5.33 1.840  36   2.890  0.0060
 Group 1 (unaware) .      T4-T5 Female - Male                           5.33 1.840  36   2.890  0.0060
 Group 1 (unaware) .      T5-T6 Female - Male                           5.33 1.840  36   2.890  0.0060
 Group 2 (aware)   .      T0-T1 Female - Male                          -0.21 1.670  36  -0.130  0.9010
 Group 2 (aware)   .      T1-T2 Female - Male                          -0.21 1.670  36  -0.130  0.9010
 Group 2 (aware)   .      T2-T3 Female - Male                          -0.21 1.670  36  -0.130  0.9010
 Group 2 (aware)   .      T3-T4 Female - Male                          -0.21 1.670  36  -0.130  0.9010
 Group 2 (aware)   .      T4-T5 Female - Male                          -0.21 1.670  36  -0.130  0.9010
 Group 2 (aware)   .      T5-T6 Female - Male                          -0.21 1.670  36  -0.130  0.9010

Degrees-of-freedom method: kenward-roger 
Show the code
cat("\n")
Show the code
cat("\n ... and confidence intervals ... ")

 ... and confidence intervals ... 
Show the code
cat("\n")
Show the code
emmeans::lsmeans(final, ~ visit|study_arm*sex, lmer.df = "k") |> 
  emmeans::contrast("consec", simple = "each", combine = TRUE, adjust = "none") |>
  confint(pairs, reverse = TRUE)
 study_arm         sex    visit contrast                            estimate    SE  df lower.CL upper.CL
 Group 1 (unaware) Male   .     (T1-T2) - (T0-T1)                       0.19 0.377 195    -0.55     0.93
 Group 1 (unaware) Male   .     (T2-T3) - (T1-T2)                      -0.35 0.377 195    -1.09     0.39
 Group 1 (unaware) Male   .     (T3-T4) - (T2-T3)                      -0.30 0.377 195    -1.04     0.44
 Group 1 (unaware) Male   .     (T4-T5) - (T3-T4)                      -0.33 0.377 195    -1.07     0.42
 Group 1 (unaware) Male   .     (T5-T6) - (T4-T5)                      -0.87 0.377 195    -1.61    -0.12
 Group 2 (aware)   Male   .     (T1-T2) - (T0-T1)                       0.19 0.377 195    -0.55     0.93
 Group 2 (aware)   Male   .     (T2-T3) - (T1-T2)                      -0.35 0.377 195    -1.09     0.39
 Group 2 (aware)   Male   .     (T3-T4) - (T2-T3)                      -0.30 0.377 195    -1.04     0.44
 Group 2 (aware)   Male   .     (T4-T5) - (T3-T4)                      -0.33 0.377 195    -1.07     0.42
 Group 2 (aware)   Male   .     (T5-T6) - (T4-T5)                      -0.87 0.377 195    -1.61    -0.12
 Group 1 (unaware) Female .     (T1-T2) - (T0-T1)                       0.19 0.377 195    -0.55     0.93
 Group 1 (unaware) Female .     (T2-T3) - (T1-T2)                      -0.35 0.377 195    -1.09     0.39
 Group 1 (unaware) Female .     (T3-T4) - (T2-T3)                      -0.30 0.377 195    -1.04     0.44
 Group 1 (unaware) Female .     (T4-T5) - (T3-T4)                      -0.33 0.377 195    -1.07     0.42
 Group 1 (unaware) Female .     (T5-T6) - (T4-T5)                      -0.87 0.377 195    -1.61    -0.12
 Group 2 (aware)   Female .     (T1-T2) - (T0-T1)                       0.19 0.377 195    -0.55     0.93
 Group 2 (aware)   Female .     (T2-T3) - (T1-T2)                      -0.35 0.377 195    -1.09     0.39
 Group 2 (aware)   Female .     (T3-T4) - (T2-T3)                      -0.30 0.377 195    -1.04     0.44
 Group 2 (aware)   Female .     (T4-T5) - (T3-T4)                      -0.33 0.377 195    -1.07     0.42
 Group 2 (aware)   Female .     (T5-T6) - (T4-T5)                      -0.87 0.377 195    -1.61    -0.12
 .                 Male   T0-T1 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36     2.94    11.41
 .                 Male   T1-T2 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36     2.94    11.41
 .                 Male   T2-T3 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36     2.94    11.41
 .                 Male   T3-T4 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36     2.94    11.41
 .                 Male   T4-T5 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36     2.94    11.41
 .                 Male   T5-T6 Group 2 (aware) - Group 1 (unaware)     7.17 2.090  36     2.94    11.41
 .                 Female T0-T1 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36    -1.11     4.38
 .                 Female T1-T2 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36    -1.11     4.38
 .                 Female T2-T3 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36    -1.11     4.38
 .                 Female T3-T4 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36    -1.11     4.38
 .                 Female T4-T5 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36    -1.11     4.38
 .                 Female T5-T6 Group 2 (aware) - Group 1 (unaware)     1.64 1.350  36    -1.11     4.38
 Group 1 (unaware) .      T0-T1 Female - Male                           5.33 1.840  36     1.59     9.06
 Group 1 (unaware) .      T1-T2 Female - Male                           5.33 1.840  36     1.59     9.06
 Group 1 (unaware) .      T2-T3 Female - Male                           5.33 1.840  36     1.59     9.06
 Group 1 (unaware) .      T3-T4 Female - Male                           5.33 1.840  36     1.59     9.06
 Group 1 (unaware) .      T4-T5 Female - Male                           5.33 1.840  36     1.59     9.06
 Group 1 (unaware) .      T5-T6 Female - Male                           5.33 1.840  36     1.59     9.06
 Group 2 (aware)   .      T0-T1 Female - Male                          -0.21 1.670  36    -3.60     3.18
 Group 2 (aware)   .      T1-T2 Female - Male                          -0.21 1.670  36    -3.60     3.18
 Group 2 (aware)   .      T2-T3 Female - Male                          -0.21 1.670  36    -3.60     3.18
 Group 2 (aware)   .      T3-T4 Female - Male                          -0.21 1.670  36    -3.60     3.18
 Group 2 (aware)   .      T4-T5 Female - Male                          -0.21 1.670  36    -3.60     3.18
 Group 2 (aware)   .      T5-T6 Female - Male                          -0.21 1.670  36    -3.60     3.18

Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 
Show the code
cat("\n")
Show the code
cat("******************** \n")
******************** 
Show the code
cat("\n")

4.2.4 Testing outliers and sensitivity

In Section 4.2.2.2 one observation (#145) was identified as potential outlier (Table 4.7). See also Figure 4.6 below.

Show the code
tbl_outliers <- theramon_long |>
  filter(row == 145) |>
  select(row, Id, study_arm, sex, visit, wear_time.visit) 

tbl_case2 <- theramon_long |>
  filter(Id == "2") |>
  select(row, Id, study_arm, sex, visit, wear_time.visit)
  
tbl_outliers_case2 <- full_join(tbl_outliers, tbl_case2, by = c("row", "Id", "study_arm", "sex", "visit", "wear_time.visit"))

tbl_outliers_case2 |>
  flextable() |> 
  colformat_num(digits = 3) |>
  colformat_double(digits = 2) |>
  bold(bold = TRUE, part = "header") |> 
  autofit()
case2.min <- theramon_long |> filter(Id == "2") |> select(wear_time.visit) |> min()
case2.max <- theramon_long |> filter(Id == "2") |> select(wear_time.visit) |> max()
Table 4.7: Observations identified as potential outliers or influental observations.

Observation number

Id

Study arm

Sex

Period

WT at visit (h)

145

3

Group 2 (aware)

Female

T3-T4

8.64

1

2

Group 1 (unaware)

Male

T0-T1

4.95

4

2

Group 1 (unaware)

Male

T1-T2

3.30

7

2

Group 1 (unaware)

Male

T2-T3

3.32

10

2

Group 1 (unaware)

Male

T3-T4

1.88

13

2

Group 1 (unaware)

Male

T4-T5

1.52

16

2

Group 1 (unaware)

Male

T5-T6

2.07

Additionally, subject/case #2 displayed very low wear times at each visit, ranging from 1.52 hours to 4.95 hours (Table 4.7). See also Figure 4.6 below. This case might also be influencing the model.

In this section, we evaluated possible effects of these observations on the linear mixed model in three steps:

  1. outlier observation removed from the data set
  2. influential case #2 removed from the data set
  3. outlier observation and potential influential case #2 removed from the data set

Each time, the model was run on the reduced dataset and the model parameter were then compared.

Show the code
fig.wear_time.Id_lm_outlier <- theramon_long |> 
  filter(Id == "2" | Id == "3") |>
  arrange(Id, visit) |>
  ggplot(aes(x = visit, y = wear_time.visit, group = 1, color = study_arm, label = row)) +
  geom_line() +
  geom_point(shape = 21, size = 2, fill = "white") +
  geom_label_repel(data = tbl_outliers_case2, aes(label = row), box.padding = 0.35, point.padding = 0.5, color = 'black', segment.color = 'black') +
  # geom_text_repel(aes(label = row), box.padding = 0.35, point.padding = 0.5, segment.color = 'black') +
  guides(shape = "none") + 
  labs(x = "Wear period", y = "Wear time (h)") +
  scale_y_continuous(limit = c(0, 30), breaks = seq(0, 30, by = 10), expand = c(0,0)) +
  scale_colour_discrete(name = "Study arm", labels = c("Group 1 (unaware)", "Group 2 (aware)")) +
  facet_wrap(facet = vars(Id), ncol = 5, labeller = case_names) +
  theme_bw(base_size = 14) +
  theme(legend.position = "bottom") +
  theme(panel.grid.major.y = element_line(color = "lightgrey", linetype = "dashed"), 
        panel.grid.minor.y = element_blank(), panel.grid.major.x = element_blank()) +
  theme(strip.text.x = element_text(size = 11, color = "black", face = "bold")) +
  theme(axis.text.x = element_text(angle = 30, vjust = 0.8, hjust = 0.8))

fig.wear_time.Id_lm_outlier
Figure 4.6: Potentially influenting case #2 and outlier observation from case #3.

4.2.4.1 Outlier

To evaluate, if potential outliers (Table 4.7) had an impact on model performance, the final model was updated by removing observation #145 (Id = 3, Group 2, female, Visit 3 = T3-T4) yielding model final.rowdel.

Show the code
set.seed(2)
options(width = 100)

# final.rowdel <- update(final, subset = -c(145))

theramon_long.rowdel <- theramon_long |>
  slice(-145)

final.rowdel <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 | Id), data = theramon_long.rowdel, REML = TRUE)

summary(final.rowdel, ddf = "Kenward-Roger")
Linear mixed model fit by REML. t-tests use Kenward-Roger's method ['lmerModLmerTest']
Formula: wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 |      Id)
   Data: theramon_long.rowdel

REML criterion at convergence: 1023

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-3.526 -0.420  0.026  0.471  3.111 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 12.26    3.5     
 Residual              2.56    1.6     
Number of obs: 239, groups:  Id, 40

Fixed effects:
                                   Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                          10.130      1.609  37.512    6.29  2.4e-07 ***
visitT1-T2                            0.191      0.357 194.000    0.53   0.5942    
visitT2-T3                           -0.158      0.357 194.000   -0.44   0.6595    
visitT3-T4                           -0.247      0.360 194.037   -0.69   0.4936    
visitT4-T5                           -0.784      0.357 194.000   -2.19   0.0294 *  
visitT5-T6                           -1.652      0.357 194.000   -4.62  6.9e-06 ***
study_armGroup 2 (aware)              7.174      2.085  35.987    3.44   0.0015 ** 
sexFemale                             5.328      1.839  35.987    2.90   0.0064 ** 
study_armGroup 2 (aware):sexFemale   -5.430      2.484  35.993   -2.19   0.0354 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 st_G2() sexFml
visitT1-T2  -0.111                                                  
visitT2-T3  -0.111  0.500                                           
visitT3-T4  -0.111  0.496  0.496                                    
visitT4-T5  -0.111  0.500  0.500  0.496                             
visitT5-T6  -0.111  0.500  0.500  0.496  0.500                      
stdy_rmG2() -0.756  0.000  0.000  0.000  0.000  0.000               
sexFemale   -0.857  0.000  0.000  0.000  0.000  0.000  0.661        
stdy_G2():F  0.635  0.000  0.000  0.001  0.000  0.000 -0.840  -0.740

4.2.4.2 Influential case

Additionally, the wear times of case #2 were very short in comparison to the other study participants (Table 4.7). What happens, if these were removed from the model? The final model was updated by deleting the observations related to case #2 from the model yielding model final.case2:

Show the code
set.seed(2)
options(width = 100)

# final.case2 <- update(final, subset = -c(1, 4, 7, 10, 13, 16))

theramon_long.case2 <- theramon_long |>
  filter(Id != "2")

final.case2 <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 | Id), data = theramon_long.case2, REML = TRUE)

summary(final.case2, ddf = "Kenward-Roger")
Linear mixed model fit by REML. t-tests use Kenward-Roger's method ['lmerModLmerTest']
Formula: wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 |      Id)
   Data: theramon_long.case2

REML criterion at convergence: 1020

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-4.081 -0.379  0.026  0.444  2.867 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 10.93    3.31    
 Residual              2.89    1.70    
Number of obs: 234, groups:  Id, 39

Fixed effects:
                                   Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                          11.835      1.707  36.527    6.93  3.7e-08 ***
visitT1-T2                            0.238      0.385 190.000    0.62    0.537    
visitT2-T3                           -0.120      0.385 190.000   -0.31    0.756    
visitT3-T4                           -0.391      0.385 190.000   -1.02    0.311    
visitT4-T5                           -0.717      0.385 190.000   -1.86    0.064 .  
visitT5-T6                           -1.621      0.385 190.000   -4.21  3.9e-05 ***
study_armGroup 2 (aware)              5.462      2.117  35.000    2.58    0.014 *  
sexFemale                             3.616      1.901  35.000    1.90    0.065 .  
study_armGroup 2 (aware):sexFemale   -3.826      2.474  35.000   -1.55    0.131    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 st_G2() sexFml
visitT1-T2  -0.113                                                  
visitT2-T3  -0.113  0.500                                           
visitT3-T4  -0.113  0.500  0.500                                    
visitT4-T5  -0.113  0.500  0.500  0.500                             
visitT5-T6  -0.113  0.500  0.500  0.500  0.500                      
stdy_rmG2() -0.789  0.000  0.000  0.000  0.000  0.000               
sexFemale   -0.879  0.000  0.000  0.000  0.000  0.000  0.709        
stdy_G2():F  0.675  0.000  0.000  0.000  0.000  0.000 -0.856  -0.768

4.2.4.3 Combination of outlier and influential case

What happens, if both, the outlier observation and the influential subject, were removed from the data frame? This yielded model final.reduced.

Show the code
# final.reduced <- update(final, subset = -c(1, 4, 7, 10, 13, 16, 145))

set.seed(2)
options(width = 100)

theramon_long.reduced <- theramon_long.rowdel |>
  filter(Id != "2")

final.reduced <- lmerTest::lmer(wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 | Id), data = theramon_long.reduced, REML = TRUE)

theramon.reduced_eff <- Effect(c("visit", "sex", "study_arm"),
                           final.reduced,
                           xlevels = list(visit=seq(1, 6, by=1)))

theramon.full_eff <- Effect(c("visit", "sex", "study_arm"),
                           final,
                           xlevels = list(visit=seq(1, 6, by=1)))

summary(final.reduced, ddf = "Kenward-Roger")
Linear mixed model fit by REML. t-tests use Kenward-Roger's method ['lmerModLmerTest']
Formula: wear_time.visit ~ visit + study_arm + sex + study_arm:sex + (1 |      Id)
   Data: theramon_long.reduced

REML criterion at convergence: 996

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-3.472 -0.432  0.015  0.473  3.048 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 10.94    3.31    
 Residual              2.59    1.61    
Number of obs: 233, groups:  Id, 39

Fixed effects:
                                   Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                          11.799      1.702  36.362    6.93  3.8e-08 ***
visitT1-T2                            0.238      0.365 189.000    0.65    0.515    
visitT2-T3                           -0.120      0.365 189.000   -0.33    0.742    
visitT3-T4                           -0.174      0.368 189.042   -0.47    0.637    
visitT4-T5                           -0.717      0.365 189.000   -1.97    0.051 .  
visitT5-T6                           -1.621      0.365 189.000   -4.44  1.5e-05 ***
study_armGroup 2 (aware)              5.462      2.114  34.986    2.58    0.014 *  
sexFemale                             3.616      1.898  34.986    1.91    0.065 .  
study_armGroup 2 (aware):sexFemale   -3.717      2.470  34.992   -1.50    0.141    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 st_G2() sexFml
visitT1-T2  -0.107                                                  
visitT2-T3  -0.107  0.500                                           
visitT3-T4  -0.107  0.496  0.496                                    
visitT4-T5  -0.107  0.500  0.500  0.496                             
visitT5-T6  -0.107  0.500  0.500  0.496  0.500                      
stdy_rmG2() -0.790  0.000  0.000  0.000  0.000  0.000               
sexFemale   -0.880  0.000  0.000  0.000  0.000  0.000  0.709        
stdy_G2():F  0.676  0.000  0.000  0.001  0.000  0.000 -0.856  -0.768

Check for outliers:

Show the code
check_outliers(final.reduced)
OK: No outliers detected.
- Based on the following method and threshold: cook (0.5).
- For variable: (Whole model)

4.2.4.4 Comparison

In Table 4.8 we compared the accepted model (final) with those after elemination of the potential outlier (final.rowdel), removal of the potentially influencing case 2 (final.case2), or both (final.reduced).

  • final.rowdel: The intercept increased, the estimates for visit(T1-T2) up to visit(T5-T6) increased, the same for sex(Female). The estimates for study_arm = Group 2 and for the interaction term study_arm(Group2):sex(Female) decreased.
  • final.case2: Slight changes in the estimates, sex(Female) and the interaction term study_arm(Group2):sex(Female) were not significant anymore and should be probably removed from the analysis?!
  • final.reduced: The number of observations was reduced from 240 to 233, and the number of groups dropped from 40 to 39. In comparison to the final model (complete data frame) deleting the outlier and the influential subject led to a better performance of the final.reduced model as indicated by the lower AIC and BIC. After adjusting for the other variables in the model, the estimates for each visit period slightly increased, and the estimate for study_arm was reduced. After adjusting for the other variables in the model, the estimate for female sex was reduced by 1.71, and was not significant anymore. After adjusting for the other variables in the model, the estimate for the interaction of study_arm:sex for female subjects increased by -1.82, and also was not significant anymore.
Show the code
sjPlot::tab_model(final, final.rowdel, final.case2, final.reduced, p.val = "kr", df.method = "kr",
                  show.reflvl = TRUE, collapse.ci = TRUE, # show.ngroups = TRUE, 
                  # show.se = TRUE, show.ngroups = TRUE, show.aic = TRUE, show.loglik = TRUE, auto.label = FALSE,
                  dv.labels = c("final", "final.rowdel", "final.case2", "final.reduced"))
Table 4.8: Comparision between the accpeted (final) and those after elimination of outlier and/or potentially influenting case #2.
  final final.rowdel final.case2 final.reduced
Predictors Estimates p Estimates p Estimates p Estimates p
(Intercept) 10.16
(6.90 – 13.43)
<0.001 10.13
(6.87 – 13.39)
<0.001 11.84
(8.37 – 15.30)
<0.001 11.80
(8.35 – 15.25)
<0.001
T0-T1 Reference Reference Reference Reference
T1-T2 0.19
(-0.55 – 0.93)
0.613 0.19
(-0.51 – 0.90)
0.594 0.24
(-0.52 – 1.00)
0.537 0.24
(-0.48 – 0.96)
0.515
T2-T3 -0.16
(-0.90 – 0.59)
0.676 -0.16
(-0.86 – 0.55)
0.659 -0.12
(-0.88 – 0.64)
0.756 -0.12
(-0.84 – 0.60)
0.742
T3-T4 -0.46
(-1.20 – 0.29)
0.226 -0.25
(-0.96 – 0.46)
0.494 -0.39
(-1.15 – 0.37)
0.311 -0.17
(-0.90 – 0.55)
0.637
study_armGroup 2 (aware):sexFemale -5.54
(-10.58 – -0.49)
0.032 -5.43
(-10.47 – -0.39)
0.035 -3.83
(-8.85 – 1.20)
0.131 -3.72
(-8.73 – 1.30)
0.141
T4-T5 -0.78
(-1.53 – -0.04)
0.039 -0.78
(-1.49 – -0.08)
0.029 -0.72
(-1.48 – 0.04)
0.064 -0.72
(-1.44 – 0.00)
0.051
T5-T6 -1.65
(-2.40 – -0.91)
<0.001 -1.65
(-2.36 – -0.95)
<0.001 -1.62
(-2.38 – -0.86)
<0.001 -1.62
(-2.34 – -0.90)
<0.001
Group 1 (unaware) Reference Reference Reference Reference
Group 2 (aware) 7.17
(2.94 – 11.41)
0.002 7.17
(2.94 – 11.40)
0.001 5.46
(1.16 – 9.76)
0.014 5.46
(1.17 – 9.75)
0.014
Male Reference Reference Reference Reference
Female 5.33
(1.59 – 9.06)
0.006 5.33
(1.60 – 9.06)
0.006 3.62
(-0.24 – 7.48)
0.065 3.62
(-0.24 – 7.47)
0.065
Random Effects
σ2 2.84 2.56 2.89 2.59
τ00 12.25 Id 12.26 Id 10.93 Id 10.94 Id
ICC 0.81 0.83 0.79 0.81
N 40 Id 40 Id 39 Id 39 Id
Observations 240 239 234 233
Marginal R2 / Conditional R2 0.263 / 0.861 0.271 / 0.874 0.177 / 0.828 0.185 / 0.844

4.2.5 Dealing with non-normality

Various transformations of the response variable wear_time.visit were tested, including log(), log10(), and sqrt() transformations (not shown). Additionally, cubed (wear_time.visit^3) and Box-Cox transformations were tested.

All tests were done with the model for the reduced data set (i.e., after removal of the outlier and the influential case; final.reduced) and its data set theramon_long.reduced.

Show the code
set.seed(2)
options(width = 100)

final.reduced_cubed <- lmerTest::lmer(I(wear_time.visit^3) ~ visit + study_arm + sex + study_arm:sex + (1 | Id), data = theramon_long.reduced, REML = TRUE)
summary(final.reduced_cubed, ddf = "Kenward-Roger")
Linear mixed model fit by REML. t-tests use Kenward-Roger's method ['lmerModLmerTest']
Formula: I(wear_time.visit^3) ~ visit + study_arm + sex + study_arm:sex +      (1 | Id)
   Data: theramon_long.reduced

REML criterion at convergence: 3908

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.8217 -0.4648 -0.0248  0.4821  2.8393 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 6005307  2451    
 Residual             1105312  1051    
Number of obs: 233, groups:  Id, 39

Fixed effects:
                                   Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                          2224.0     1253.4    36.1    1.77   0.0844 .  
visitT1-T2                            258.9      238.1   189.0    1.09   0.2782    
visitT2-T3                            124.8      238.1   189.0    0.52   0.6006    
visitT3-T4                            -54.3      239.9   189.0   -0.23   0.8212    
visitT4-T5                           -401.9      238.1   189.0   -1.69   0.0930 .  
visitT5-T6                           -943.6      238.1   189.0   -3.96   0.0001 ***
study_armGroup 2 (aware)             3544.0     1559.4    35.0    2.27   0.0293 *  
sexFemale                            1936.6     1400.0    35.0    1.38   0.1753    
study_armGroup 2 (aware):sexFemale  -2424.3     1822.2    35.0   -1.33   0.1920    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 st_G2() sexFml
visitT1-T2  -0.095                                                  
visitT2-T3  -0.095  0.500                                           
visitT3-T4  -0.095  0.496  0.496                                    
visitT4-T5  -0.095  0.500  0.500  0.496                             
visitT5-T6  -0.095  0.500  0.500  0.496  0.500                      
stdy_rmG2() -0.792  0.000  0.000  0.000  0.000  0.000               
sexFemale   -0.882  0.000  0.000  0.000  0.000  0.000  0.709        
stdy_G2():F  0.677  0.000  0.000  0.001  0.000  0.000 -0.856  -0.768
Show the code
theramon.reduced_cubed_eff <- Effect(c("visit", "sex", "study_arm"),
                                     final.reduced_cubed,
                                     xlevels = list(visit=seq(1, 6, by=1)),
                                     transformation = list(link=function(x) x^3,
                                                           inverse=function(x) x^(1/3)))

Finally, Box-Cox transformation was tested as implemented in powerTransform() of the “car” R package yielding \lambda = 2.7, \gamma = 22 (Fox and Weisberg 2019a). A Box-Cox transformation was applied to wear_time.visit in the theramon_long.reduced data frame accordingly.

Show the code
set.seed(2)
options(width = 100)

pwr.theramon <- car::powerTransform(final.reduced, family = "bcnPower")

cat("*** powerTransform*** \n")
*** powerTransform*** 
Show the code
summary(pwr.theramon)
bcn - Box-Cox Power transformation to Normality
allowing for negative values, lmer fit

Estimated power, lambda
     Est.Power Std.Err. Wald Lower Bound Wald Upper Bound
[1,]      2.67    0.842             1.02             4.32

Estimated location, gamma
     Est.gamma Std.Err. Wald Lower Bound Wald Upper Bound
[1,]      22.5       14                0             49.8

Likelihood ratio tests about transformation parameters
                       LRT df     pval
LR test, lambda = (0) 43.2  1 4.96e-11
LR test, lambda = (1) 16.9  1 3.90e-05
Show the code
# bcn - Box-Cox Power transformation to Normality
# allowing for negative values, lmer fit
# 
# Estimated power, lambda
#      Est.Power Std.Err. Wald Lower Bound Wald Upper Bound
# [1,]       2.7     0.84                1              4.3
# 
# Estimated location, gamma
#      Est.gamma Std.Err. Wald Lower Bound Wald Upper Bound
# [1,]        22       14                0               50
# 
# Likelihood ratio tests about transformation parameters
#                       LRT df    pval
# LR test, lambda = (0)  43  1 5.0e-11
# LR test, lambda = (1)  17  1 3.9e-05

cat("\n")
Show the code
theramon_long.reduced$wear_time.visit_tran <- car::bcnPower(theramon_long.reduced$wear_time.visit, lambda = 2.7, gamma = 22)

final.reduced_pwr <- lmerTest::lmer(wear_time.visit_tran ~ visit + study_arm + sex + study_arm:sex + (1 | Id), data = theramon_long.reduced, REML = TRUE)

cat("*** Box-Cox-transformed model*** \n")
*** Box-Cox-transformed model*** 
Show the code
summary(final.reduced_pwr, ddf = "Kenward-Roger")
Linear mixed model fit by REML. t-tests use Kenward-Roger's method ['lmerModLmerTest']
Formula: wear_time.visit_tran ~ visit + study_arm + sex + study_arm:sex +      (1 | Id)
   Data: theramon_long.reduced

REML criterion at convergence: 3181

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.1596 -0.4802 -0.0058  0.5129  2.6869 

Random effects:
 Groups   Name        Variance Std.Dev.
 Id       (Intercept) 220409   469     
 Residual              43588   209     
Number of obs: 233, groups:  Id, 39

Fixed effects:
                                   Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)                         1036.79     240.52   36.14    4.31  0.00012 ***
visitT1-T2                            43.74      47.28  189.00    0.93  0.35603    
visitT2-T3                             8.71      47.28  189.00    0.18  0.85404    
visitT3-T4                           -15.95      47.65  189.04   -0.33  0.73811    
visitT4-T5                           -87.17      47.28  189.00   -1.84  0.06678 .  
visitT5-T6                          -201.37      47.28  189.00   -4.26  3.2e-05 ***
study_armGroup 2 (aware)             717.61     299.07   34.99    2.40  0.02188 *  
sexFemale                            423.80     268.51   34.99    1.58  0.12349    
study_armGroup 2 (aware):sexFemale  -488.31     349.49   34.99   -1.40  0.17115    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) vT1-T2 vT2-T3 vT3-T4 vT4-T5 vT5-T6 st_G2() sexFml
visitT1-T2  -0.098                                                  
visitT2-T3  -0.098  0.500                                           
visitT3-T4  -0.098  0.496  0.496                                    
visitT4-T5  -0.098  0.500  0.500  0.496                             
visitT5-T6  -0.098  0.500  0.500  0.496  0.500                      
stdy_rmG2() -0.791  0.000  0.000  0.000  0.000  0.000               
sexFemale   -0.881  0.000  0.000  0.000  0.000  0.000  0.709        
stdy_G2():F  0.677  0.000  0.000  0.001  0.000  0.000 -0.856  -0.768
Show the code
theramon.reduced_pwr_eff <- Effect(c("visit", "sex", "study_arm"),
                                   final.reduced_pwr,
                                   xlevels = list(visit=seq(1, 6, by=1)),
                                   transformation = list(link=function(x) car::bcnPower(x, lambda = 2.7, gamma = 22),
                                                         inverse=function(x) car::bcnPowerInverse(x, lambda = 2.7, gamma = 22)))
Show the code
plot(check_normality(final.reduced_cubed))

plot(check_normality(final.reduced_pwr))
(a) Cubed transformation
(b) Box-Cox transformation
Figure 4.7: Normality plots of the models after (a) cubed, and (b) Box-Cox transformation
Show the code
plot(theramon.reduced_eff, axes = list(y=list(type="response"), x = list(rug = FALSE)),
     ylim = c(8, 20),
     lines = list(multiline=TRUE, lwd = 2),
     confit=list(style = "bands"),
     lattice=list(key.args=list(x=0.9, y = 0.2, corner = c(1,1), padding.text=1.25)),
     xlab = "Visit", ylab = "Wear time (h)", main = "")

plot(theramon.reduced_cubed_eff, axes = list(y=list(type="response"), x = list(rug = FALSE)),
     ylim = c(8, 20), 
     lines = list(multiline=TRUE, lwd = 2),
     confit=list(style = "bands"),
     lattice=list(key.args=list(x=0.9, y = 0.2, corner = c(1,1), padding.text=1.25)),
     xlab = "Visit", ylab = "Wear time (h)", main = "")

plot(theramon.reduced_pwr_eff, axes = list(y=list(type="response"), x = list(rug = FALSE)),
     ylim = c(8, 20), 
     lines = list(multiline=TRUE, lwd = 2),
     confit=list(style = "bands"),
     lattice=list(key.args=list(x=0.9, y = 0.2, corner = c(1,1), padding.text=1.25)),
     xlab = "Visit", ylab = "Wear time (h)", main = "")
(a) Not transformed
(b) Cubed transformation
(c) Box-Cox transformation
Figure 4.8: Effect plot for the interaction of sex and study_arm in the mixed-effect models fit to the reduced data set. Effect of transformations applied to response variable wear_time.visit.

4.3 final.reduced model description

Show the code
set.seed(2)
options(width = 110)

report(final.reduced, ci_method = "kenward")
We fitted a linear mixed model (estimated using REML and nloptwrap optimizer) to predict wear_time.visit with
visit, study_arm and sex (formula: wear_time.visit ~ visit + study_arm + sex + study_arm:sex). The model
included Id as random effect (formula: ~1 | Id). The model's total explanatory power is substantial
(conditional R2 = 0.84) and the part related to the fixed effects alone (marginal R2) is of 0.19. The model's
intercept, corresponding to visit = T0-T1, study_arm = Group 1 (unaware) and sex = Male, is at 11.80 (95% CI
[8.35, 15.25], t(36.36) = 6.93, p < .001). Within this model:

  - The effect of visit [T1-T2] is statistically non-significant and positive (beta = 0.24, 95% CI [-0.48,
0.96], t(189.00) = 0.65, p = 0.515; Std. beta = 0.06, 95% CI [-0.12, 0.24])
  - The effect of visit [T2-T3] is statistically non-significant and negative (beta = -0.12, 95% CI [-0.84,
0.60], t(189.00) = -0.33, p = 0.742; Std. beta = -0.03, 95% CI [-0.21, 0.15])
  - The effect of visit [T3-T4] is statistically non-significant and negative (beta = -0.17, 95% CI [-0.90,
0.55], t(189.04) = -0.47, p = 0.637; Std. beta = -0.04, 95% CI [-0.23, 0.14])
  - The effect of visit [T4-T5] is statistically non-significant and negative (beta = -0.72, 95% CI [-1.44,
2.76e-03], t(189.00) = -1.97, p = 0.051; Std. beta = -0.18, 95% CI [-0.37, 7.01e-04])
  - The effect of visit [T5-T6] is statistically significant and negative (beta = -1.62, 95% CI [-2.34, -0.90],
t(189.00) = -4.44, p < .001; Std. beta = -0.41, 95% CI [-0.59, -0.23])
  - The effect of study arm [Group 2 (aware)] is statistically significant and positive (beta = 5.46, 95% CI
[1.17, 9.75], t(34.99) = 2.58, p = 0.014; Std. beta = 1.39, 95% CI [0.30, 2.48])
  - The effect of sex [Female] is statistically non-significant and positive (beta = 3.62, 95% CI [-0.24,
7.47], t(34.99) = 1.91, p = 0.065; Std. beta = 0.92, 95% CI [-0.06, 1.90])
  - The effect of study arm [Group 2 (aware)] × sex [Female] is statistically non-significant and negative
(beta = -3.72, 95% CI [-8.73, 1.30], t(34.99) = -1.50, p = 0.141; Std. beta = -0.94, 95% CI [-2.22, 0.33])

Standardized parameters were obtained by fitting the model on a standardized version of the dataset. 95%
Confidence Intervals (CIs) and p-values were computed using a Wald t-distribution with Kenward-Roger
approximation.

Table 4.9 compares final and final.reduced models.

Show the code
set.seed(2)

sjPlot::tab_model(final, final.reduced, show.reflvl = TRUE, p.val = "kr", df.method = "kr",
                  # show.se = TRUE, show.ngroups = TRUE, show.aic = TRUE, show.loglik = TRUE, auto.label = FALSE,
                  dv.labels = c("Accepted model", "Reduced model"))
Table 4.9: Comparision of model summarys of the full final and the reduced final.reduced model using sjPlot::tab_model() (Kenward-Roger)
  Accepted model Reduced model
Predictors Estimates CI p Estimates CI p
(Intercept) 10.16 6.90 – 13.43 <0.001 11.80 8.35 – 15.25 <0.001
T0-T1 Reference Reference
T1-T2 0.19 -0.55 – 0.93 0.613 0.24 -0.48 – 0.96 0.515
T2-T3 -0.16 -0.90 – 0.59 0.676 -0.12 -0.84 – 0.60 0.742
T3-T4 -0.46 -1.20 – 0.29 0.226 -0.17 -0.90 – 0.55 0.637
study_armGroup 2 (aware):sexFemale -5.54 -10.58 – -0.49 0.032 -3.72 -8.73 – 1.30 0.141
T4-T5 -0.78 -1.53 – -0.04 0.039 -0.72 -1.44 – 0.00 0.051
T5-T6 -1.65 -2.40 – -0.91 <0.001 -1.62 -2.34 – -0.90 <0.001
Group 1 (unaware) Reference Reference
Group 2 (aware) 7.17 2.94 – 11.41 0.002 5.46 1.17 – 9.75 0.014
Male Reference Reference
Female 5.33 1.59 – 9.06 0.006 3.62 -0.24 – 7.47 0.065
Random Effects
σ2 2.84 2.59
τ00 12.25 Id 10.94 Id
ICC 0.81 0.81
N 40 Id 39 Id
Observations 240 233
Marginal R2 / Conditional R2 0.263 / 0.861 0.185 / 0.844

Figure 4.9 depicts the plots from the final.reduced model showing the random estimates and marginal effects next to each other.

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg") 

fig.final.reduced_random <- sjPlot::plot_model(final.reduced, type = "re", colors = "bw", title = "", ci_method = "kenward") + 
  theme_bw() + theme(legend.position = "bottom")
fig.final.reduced_interaction2 <- sjPlot::plot_model(final.reduced, type = "pred", terms = c("visit", "sex", "study_arm"), title = "", ci_method = "kenward") + 
  theme_bw() + theme(legend.position = "bottom")

grid5 <- grid::grid.draw(fig.final.reduced_random + fig.final.reduced_interaction2  + plot_layout(nrow = 1, width = c(1,2))  + plot_annotation(tag_levels = 'a'))

ggsave("Fig_6 panel_final-reduced_intersection.pdf", plot = grid5, device = cairo_pdf, units = "in", width = 10, height = 7, dpi = 300)
ggsave("Fig_6 panel_final-reduced_intersection.png", plot = grid5, device = png, units = "in", width = 10, height = 7, dpi = 300)
Figure 4.9: Plots from the final.reduced model. (a) Forest plot of random effects by subject’s Id. (b) Plot of the predicted values (marginal effects) for wear_time.visit by visit, study_arm and sex.

4.3.1 Multiple comparisons

Multiple comparisons of the final.reduced model factors was done as described above (see Section 4.2.3.3). The p-values are based on the t-distribution using degrees of freedom based on Kenward-Roger’s method. Adjustments for multiple comparisons were not applied, instead unadjusted p-values were reported.

Show the code
options(width = 100)
set.seed(2)

reduced.allsets <- emmeans::lsmeans(final.reduced, ".", lmer.df = "k")

cat("\n")
Show the code
cat("*** contrast(reduced.allsets, revpairwise, lmer.df = k, adjust = none) ***\n")
*** contrast(reduced.allsets, revpairwise, lmer.df = k, adjust = none) ***
Show the code
cat("\n")
Show the code
emmeans::contrast(reduced.allsets, "revpairwise", lmer.df = "k", adjust = "none")
$`contrasts of lsmeans of visit`
 contrast          estimate    SE  df t.ratio p.value
 (T1-T2) - (T0-T1)    0.238 0.365 189   0.650  0.5150
 (T2-T3) - (T0-T1)   -0.120 0.365 189  -0.330  0.7420
 (T2-T3) - (T1-T2)   -0.358 0.365 189  -0.980  0.3280
 (T3-T4) - (T0-T1)   -0.174 0.368 189  -0.470  0.6370
 (T3-T4) - (T1-T2)   -0.412 0.368 189  -1.120  0.2640
 (T3-T4) - (T2-T3)   -0.054 0.368 189  -0.150  0.8840
 (T4-T5) - (T0-T1)   -0.717 0.365 189  -1.970  0.0510
 (T4-T5) - (T1-T2)   -0.955 0.365 189  -2.620  0.0100
 (T4-T5) - (T2-T3)   -0.597 0.365 189  -1.640  0.1040
 (T4-T5) - (T3-T4)   -0.543 0.368 189  -1.480  0.1410
 (T5-T6) - (T0-T1)   -1.621 0.365 189  -4.440  <.0001
 (T5-T6) - (T1-T2)   -1.858 0.365 189  -5.100  <.0001
 (T5-T6) - (T2-T3)   -1.501 0.365 189  -4.110  <.0001
 (T5-T6) - (T3-T4)   -1.447 0.368 189  -3.940  <.0001
 (T5-T6) - (T4-T5)   -0.904 0.365 189  -2.480  0.0140

Results are averaged over the levels of: study_arm, sex 
Degrees-of-freedom method: kenward-roger 

$`contrasts of lsmeans of study_arm`
 contrast                            estimate   SE df t.ratio p.value
 Group 2 (aware) - Group 1 (unaware)      3.6 1.24 35   2.918  0.0061

Results are averaged over the levels of: visit, sex 
Degrees-of-freedom method: kenward-roger 

$`contrasts of lsmeans of sex`
 contrast      estimate   SE df t.ratio p.value
 Female - Male     1.76 1.24 35   1.423  0.1636

Results are averaged over the levels of: visit, study_arm 
Degrees-of-freedom method: kenward-roger 

$`contrasts of lsmeans of study_arm, sex`
 contrast                                          estimate   SE df t.ratio p.value
 Group 2 (aware) Male - Group 1 (unaware) Male         5.46 2.11 35   2.584  0.0140
 Group 1 (unaware) Female - Group 1 (unaware) Male     3.62 1.90 35   1.906  0.0650
 Group 1 (unaware) Female - Group 2 (aware) Male      -1.85 1.54 35  -1.196  0.2400
 Group 2 (aware) Female - Group 1 (unaware) Male       5.36 1.93 35   2.780  0.0090
 Group 2 (aware) Female - Group 2 (aware) Male        -0.10 1.58 35  -0.064  0.9490
 Group 2 (aware) Female - Group 1 (unaware) Female     1.74 1.28 35   1.365  0.1810

Results are averaged over the levels of: visit 
Degrees-of-freedom method: kenward-roger 
Show the code
cat("\n ... and confidence intervals ... ")

 ... and confidence intervals ... 
Show the code
cat("\n")
Show the code
confint(emmeans::contrast(reduced.allsets, "revpairwise", lmer.df = "k", adjust = "none"))
$`contrasts of lsmeans of visit`
 contrast          estimate    SE  df lower.CL upper.CL
 (T1-T2) - (T0-T1)    0.238 0.365 189   -0.481    0.957
 (T2-T3) - (T0-T1)   -0.120 0.365 189   -0.839    0.599
 (T2-T3) - (T1-T2)   -0.358 0.365 189   -1.077    0.361
 (T3-T4) - (T0-T1)   -0.174 0.368 189   -0.899    0.551
 (T3-T4) - (T1-T2)   -0.412 0.368 189   -1.137    0.313
 (T3-T4) - (T2-T3)   -0.054 0.368 189   -0.779    0.671
 (T4-T5) - (T0-T1)   -0.717 0.365 189   -1.436    0.003
 (T4-T5) - (T1-T2)   -0.955 0.365 189   -1.674   -0.235
 (T4-T5) - (T2-T3)   -0.597 0.365 189   -1.316    0.123
 (T4-T5) - (T3-T4)   -0.543 0.368 189   -1.268    0.182
 (T5-T6) - (T0-T1)   -1.621 0.365 189   -2.340   -0.901
 (T5-T6) - (T1-T2)   -1.858 0.365 189   -2.578   -1.139
 (T5-T6) - (T2-T3)   -1.501 0.365 189   -2.220   -0.781
 (T5-T6) - (T3-T4)   -1.447 0.368 189   -2.172   -0.722
 (T5-T6) - (T4-T5)   -0.904 0.365 189   -1.623   -0.184

Results are averaged over the levels of: study_arm, sex 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`contrasts of lsmeans of study_arm`
 contrast                            estimate   SE df lower.CL upper.CL
 Group 2 (aware) - Group 1 (unaware)      3.6 1.24 35      1.1     6.11

Results are averaged over the levels of: visit, sex 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`contrasts of lsmeans of sex`
 contrast      estimate   SE df lower.CL upper.CL
 Female - Male     1.76 1.24 35    -0.75     4.26

Results are averaged over the levels of: visit, study_arm 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`contrasts of lsmeans of study_arm, sex`
 contrast                                          estimate   SE df lower.CL upper.CL
 Group 2 (aware) Male - Group 1 (unaware) Male         5.46 2.11 35     1.17     9.75
 Group 1 (unaware) Female - Group 1 (unaware) Male     3.62 1.90 35    -0.24     7.47
 Group 1 (unaware) Female - Group 2 (aware) Male      -1.85 1.54 35    -4.98     1.29
 Group 2 (aware) Female - Group 1 (unaware) Male       5.36 1.93 35     1.45     9.28
 Group 2 (aware) Female - Group 2 (aware) Male        -0.10 1.58 35    -3.31     3.11
 Group 2 (aware) Female - Group 1 (unaware) Female     1.74 1.28 35    -0.85     4.34

Results are averaged over the levels of: visit 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 
Show the code
cat("******************** \n")
******************** 
Show the code
cat("\n")

The following summarized the contrasts extracted from the `final.reduced’ model:

Show the code
set.seed(2)
options(width = 150)

# emmeans(final, ~ visit|study_arm*sex) |> contrast(interaction = c("consec", "consec", "consec"), simple = "each", combine = TRUE, adjust = "none")
# emmeans(final, ~ visit|study_arm*sex) |> contrast(interaction = c("consec", "consec", "consec"), simple = "each", combine = TRUE) |> confint(pairs, reverse = TRUE)

cat("\n")
Show the code
cat("*** lsmeans(final.reduced, ~ visit|study_arm*sex) |> contrast(consec, simple = each, combine = TRUE) NOT adjusted! ***\n")
*** lsmeans(final.reduced, ~ visit|study_arm*sex) |> contrast(consec, simple = each, combine = TRUE) NOT adjusted! ***
Show the code
cat("\n")
Show the code
emmeans::lsmeans(final.reduced, ~ visit|study_arm*sex, lmer.df = "k") |> 
  emmeans::contrast("consec", simple = "each", combine = TRUE, adjust = "none")
 study_arm         sex    visit contrast                            estimate    SE  df t.ratio p.value
 Group 1 (unaware) Male   .     (T1-T2) - (T0-T1)                       0.24 0.365 189   0.652  0.5150
 Group 1 (unaware) Male   .     (T2-T3) - (T1-T2)                      -0.36 0.365 189  -0.981  0.3280
 Group 1 (unaware) Male   .     (T3-T4) - (T2-T3)                      -0.05 0.368 189  -0.146  0.8840
 Group 1 (unaware) Male   .     (T4-T5) - (T3-T4)                      -0.54 0.368 189  -1.477  0.1410
 Group 1 (unaware) Male   .     (T5-T6) - (T4-T5)                      -0.90 0.365 189  -2.478  0.0140
 Group 2 (aware)   Male   .     (T1-T2) - (T0-T1)                       0.24 0.365 189   0.652  0.5150
 Group 2 (aware)   Male   .     (T2-T3) - (T1-T2)                      -0.36 0.365 189  -0.981  0.3280
 Group 2 (aware)   Male   .     (T3-T4) - (T2-T3)                      -0.05 0.368 189  -0.146  0.8840
 Group 2 (aware)   Male   .     (T4-T5) - (T3-T4)                      -0.54 0.368 189  -1.477  0.1410
 Group 2 (aware)   Male   .     (T5-T6) - (T4-T5)                      -0.90 0.365 189  -2.478  0.0140
 Group 1 (unaware) Female .     (T1-T2) - (T0-T1)                       0.24 0.365 189   0.652  0.5150
 Group 1 (unaware) Female .     (T2-T3) - (T1-T2)                      -0.36 0.365 189  -0.981  0.3280
 Group 1 (unaware) Female .     (T3-T4) - (T2-T3)                      -0.05 0.368 189  -0.146  0.8840
 Group 1 (unaware) Female .     (T4-T5) - (T3-T4)                      -0.54 0.368 189  -1.477  0.1410
 Group 1 (unaware) Female .     (T5-T6) - (T4-T5)                      -0.90 0.365 189  -2.478  0.0140
 Group 2 (aware)   Female .     (T1-T2) - (T0-T1)                       0.24 0.365 189   0.652  0.5150
 Group 2 (aware)   Female .     (T2-T3) - (T1-T2)                      -0.36 0.365 189  -0.981  0.3280
 Group 2 (aware)   Female .     (T3-T4) - (T2-T3)                      -0.05 0.368 189  -0.146  0.8840
 Group 2 (aware)   Female .     (T4-T5) - (T3-T4)                      -0.54 0.368 189  -1.477  0.1410
 Group 2 (aware)   Female .     (T5-T6) - (T4-T5)                      -0.90 0.365 189  -2.478  0.0140
 .                 Male   T0-T1 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35   2.584  0.0140
 .                 Male   T1-T2 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35   2.584  0.0140
 .                 Male   T2-T3 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35   2.584  0.0140
 .                 Male   T3-T4 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35   2.584  0.0140
 .                 Male   T4-T5 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35   2.584  0.0140
 .                 Male   T5-T6 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35   2.584  0.0140
 .                 Female T0-T1 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35   1.365  0.1810
 .                 Female T1-T2 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35   1.365  0.1810
 .                 Female T2-T3 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35   1.365  0.1810
 .                 Female T3-T4 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35   1.365  0.1810
 .                 Female T4-T5 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35   1.365  0.1810
 .                 Female T5-T6 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35   1.365  0.1810
 Group 1 (unaware) .      T0-T1 Female - Male                           3.62 1.900  35   1.906  0.0650
 Group 1 (unaware) .      T1-T2 Female - Male                           3.62 1.900  35   1.906  0.0650
 Group 1 (unaware) .      T2-T3 Female - Male                           3.62 1.900  35   1.906  0.0650
 Group 1 (unaware) .      T3-T4 Female - Male                           3.62 1.900  35   1.906  0.0650
 Group 1 (unaware) .      T4-T5 Female - Male                           3.62 1.900  35   1.906  0.0650
 Group 1 (unaware) .      T5-T6 Female - Male                           3.62 1.900  35   1.906  0.0650
 Group 2 (aware)   .      T0-T1 Female - Male                          -0.10 1.580  35  -0.064  0.9490
 Group 2 (aware)   .      T1-T2 Female - Male                          -0.10 1.580  35  -0.064  0.9490
 Group 2 (aware)   .      T2-T3 Female - Male                          -0.10 1.580  35  -0.064  0.9490
 Group 2 (aware)   .      T3-T4 Female - Male                          -0.10 1.580  35  -0.064  0.9490
 Group 2 (aware)   .      T4-T5 Female - Male                          -0.10 1.580  35  -0.064  0.9490
 Group 2 (aware)   .      T5-T6 Female - Male                          -0.10 1.580  35  -0.064  0.9490

Degrees-of-freedom method: kenward-roger 
Show the code
cat("\n")
Show the code
cat("\n ... and confidence intervals ... ")

 ... and confidence intervals ... 
Show the code
cat("\n")
Show the code
emmeans::lsmeans(final.reduced, ~ visit|study_arm*sex, lmer.df = "k") |> 
  emmeans::contrast("consec", simple = "each", combine = TRUE, adjust = "none") |>
  confint(pairs, reverse = TRUE)
 study_arm         sex    visit contrast                            estimate    SE  df lower.CL upper.CL
 Group 1 (unaware) Male   .     (T1-T2) - (T0-T1)                       0.24 0.365 189    -0.48     0.96
 Group 1 (unaware) Male   .     (T2-T3) - (T1-T2)                      -0.36 0.365 189    -1.08     0.36
 Group 1 (unaware) Male   .     (T3-T4) - (T2-T3)                      -0.05 0.368 189    -0.78     0.67
 Group 1 (unaware) Male   .     (T4-T5) - (T3-T4)                      -0.54 0.368 189    -1.27     0.18
 Group 1 (unaware) Male   .     (T5-T6) - (T4-T5)                      -0.90 0.365 189    -1.62    -0.18
 Group 2 (aware)   Male   .     (T1-T2) - (T0-T1)                       0.24 0.365 189    -0.48     0.96
 Group 2 (aware)   Male   .     (T2-T3) - (T1-T2)                      -0.36 0.365 189    -1.08     0.36
 Group 2 (aware)   Male   .     (T3-T4) - (T2-T3)                      -0.05 0.368 189    -0.78     0.67
 Group 2 (aware)   Male   .     (T4-T5) - (T3-T4)                      -0.54 0.368 189    -1.27     0.18
 Group 2 (aware)   Male   .     (T5-T6) - (T4-T5)                      -0.90 0.365 189    -1.62    -0.18
 Group 1 (unaware) Female .     (T1-T2) - (T0-T1)                       0.24 0.365 189    -0.48     0.96
 Group 1 (unaware) Female .     (T2-T3) - (T1-T2)                      -0.36 0.365 189    -1.08     0.36
 Group 1 (unaware) Female .     (T3-T4) - (T2-T3)                      -0.05 0.368 189    -0.78     0.67
 Group 1 (unaware) Female .     (T4-T5) - (T3-T4)                      -0.54 0.368 189    -1.27     0.18
 Group 1 (unaware) Female .     (T5-T6) - (T4-T5)                      -0.90 0.365 189    -1.62    -0.18
 Group 2 (aware)   Female .     (T1-T2) - (T0-T1)                       0.24 0.365 189    -0.48     0.96
 Group 2 (aware)   Female .     (T2-T3) - (T1-T2)                      -0.36 0.365 189    -1.08     0.36
 Group 2 (aware)   Female .     (T3-T4) - (T2-T3)                      -0.05 0.368 189    -0.78     0.67
 Group 2 (aware)   Female .     (T4-T5) - (T3-T4)                      -0.54 0.368 189    -1.27     0.18
 Group 2 (aware)   Female .     (T5-T6) - (T4-T5)                      -0.90 0.365 189    -1.62    -0.18
 .                 Male   T0-T1 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35     1.17     9.75
 .                 Male   T1-T2 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35     1.17     9.75
 .                 Male   T2-T3 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35     1.17     9.75
 .                 Male   T3-T4 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35     1.17     9.75
 .                 Male   T4-T5 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35     1.17     9.75
 .                 Male   T5-T6 Group 2 (aware) - Group 1 (unaware)     5.46 2.110  35     1.17     9.75
 .                 Female T0-T1 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35    -0.85     4.34
 .                 Female T1-T2 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35    -0.85     4.34
 .                 Female T2-T3 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35    -0.85     4.34
 .                 Female T3-T4 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35    -0.85     4.34
 .                 Female T4-T5 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35    -0.85     4.34
 .                 Female T5-T6 Group 2 (aware) - Group 1 (unaware)     1.74 1.280  35    -0.85     4.34
 Group 1 (unaware) .      T0-T1 Female - Male                           3.62 1.900  35    -0.24     7.47
 Group 1 (unaware) .      T1-T2 Female - Male                           3.62 1.900  35    -0.24     7.47
 Group 1 (unaware) .      T2-T3 Female - Male                           3.62 1.900  35    -0.24     7.47
 Group 1 (unaware) .      T3-T4 Female - Male                           3.62 1.900  35    -0.24     7.47
 Group 1 (unaware) .      T4-T5 Female - Male                           3.62 1.900  35    -0.24     7.47
 Group 1 (unaware) .      T5-T6 Female - Male                           3.62 1.900  35    -0.24     7.47
 Group 2 (aware)   .      T0-T1 Female - Male                          -0.10 1.580  35    -3.31     3.11
 Group 2 (aware)   .      T1-T2 Female - Male                          -0.10 1.580  35    -3.31     3.11
 Group 2 (aware)   .      T2-T3 Female - Male                          -0.10 1.580  35    -3.31     3.11
 Group 2 (aware)   .      T3-T4 Female - Male                          -0.10 1.580  35    -3.31     3.11
 Group 2 (aware)   .      T4-T5 Female - Male                          -0.10 1.580  35    -3.31     3.11
 Group 2 (aware)   .      T5-T6 Female - Male                          -0.10 1.580  35    -3.31     3.11

Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 
Show the code
cat("\n")
Show the code
cat("******************** \n")
******************** 
Show the code
cat("\n")

4.3.2 Figures

Show the code
# tbl-cap: "Predictions of wear time related to visit, sex, and study_arm for the reduced model (Kenward-Roger)."

set.seed(2)

get_model_data(final.reduced, type = "pred", terms = c("visit", "sex", "study_arm"), ci_method = "kenward") |>
  as_data_frame() |>
  select(facet, group, x, predicted, std.error, conf.low, conf.high) |>
  rename(Sex = group,
         Group = facet,
         Visit = x,
         Predicted = predicted,
         "Std. error" = std.error,
         Conf.l = conf.low,
         Conf.h = conf.high) |>
  mutate(Group = recode(Group, 'Group 1 (unaware)' = 'Group 1', 'Group 2 (aware)' = 'Group 2')) |>
  flextable() |> 
  colformat_double(j = c("Predicted", "Std. error", "Conf.l", "Conf.h"), digits = 1) |>
  bold(bold = TRUE, part = "header") |> 
  autofit()

Fitting the final.reduced LMM to Figure 3.3 resulted in the following Figure 4.10:

Show the code
set.seed(2)
options(ggplot2.discrete.colour = "npg") 

theramon_long.reduced_lmer <- theramon_long.reduced |>
  mutate(final_reduced.fixef = predict(final.reduced, re.form = NA),   # exclude all random effects (cf. lme4::predict.merMod)
         final_reduced.ranef = predict(final.reduced, re.form =~(1|Id))) # include all random effects

theramon_long.joined_lmer <- left_join(theramon_long.lmer, theramon_long.reduced_lmer, by = c("Id", "study_arm", "visit", "wear_time.visit")) |>
  select(Id, study_arm, age.x, sex.x, visit, visit_n.x, wear_time.visit, row.x, cum_days.x, final.fixef, final.ranef, final_reduced.fixef, final_reduced.ranef) |>
  rename(age = age.x,
         sex = sex.x,
         visit_n = visit_n.x,
         row = row.x,
         cum_days = cum_days.x)

fig.wear_time.joined_Id_lmm <- theramon_long.joined_lmer |>
  ggplot(aes(x = visit, y = wear_time.visit, group = 1)) +
  geom_point(shape = 21, size = 2, fill = "white") +
  # geom_smooth(method = "lm", se = FALSE, aes(alpha = "OLS"), colour = "black", linewidth = 0.5) +
  geom_line(aes(y = final_reduced.fixef, alpha = "fixed effects only"), colour = "blue", linewidth = 0.7, linetype = 1) + 
  geom_line(aes(y = final_reduced.ranef, alpha = "fixed and random effects"), colour = "green", linewidth = 0.7, linetype = 1) +
  guides(shape = "none") +
  labs(x = "Wear period", y = "Wear time (h)") + 
  scale_y_continuous(limit = c(0, 30), breaks = seq(0, 30, by = 10), expand = c(0,0)) +
  scale_alpha_manual(name = NULL, values = c(1,1), breaks = c("fixed effects only", "fixed and random effects")) +
  facet_wrap(facet = vars(Id), ncol = 5, labeller = case_names) +
  theme_bw(base_size = 14) +
  theme(legend.position = "bottom") +
  theme(panel.grid.major.y = element_line(colour = "lightgrey", linetype = "dashed"),
        panel.grid.minor.y = element_blank(), panel.grid.major.x = element_blank()) +
  theme(strip.text.x = element_text(size = 11, color = "black", face = "bold")) +
  theme(axis.text.x = element_text(angle = 30, vjust = 0.8, hjust = 0.8))

fig.wear_time.joined_Id_lmm
Figure 4.10: Wear time of each individual case across the six follow-up appointments using the ‘reduced’ model: prediction using fixed effects only and including random effects.

5 Citations

Show the code
pkgs <- grateful::cite_packages(output = "table", out.dir = ".", cite.tidyverse = TRUE)
knitr::kable(pkgs)
Package Version Citation
base 4.4.3 R Core Team (2025)
broom.mixed 0.2.9.6 Bolker and Robinson (2024)
car 3.1.3 Fox and Weisberg (2019a)
easystats 0.7.5 Lüdecke et al. (2022)
effects 4.2.4 Fox (2003); Fox and Hong (2009); Fox and Weisberg (2018); Fox and Weisberg (2019b)
emmeans 1.11.2.8 Lenth (2025)
flextable 0.9.10 Gohel and Skintzos (2025)
gghighlight 0.5.0 Yutani (2025)
ggmosaic 0.3.3 Jeppson, Hofmann, and Cook (2021)
ggpmisc 0.6.2 Aphalo (2025)
ggpubr 0.6.1 Kassambara (2025)
ggrepel 0.9.6 Slowikowski (2024)
ggsci 3.2.0 Xiao (2024)
gtsummary 2.4.0 Sjoberg et al. (2021)
kableExtra 1.4.0 Zhu (2024)
knitr 1.50 Xie (2014); Xie (2015); Xie (2025)
labelled 2.14.1 Larmarange (2025)
lme4 1.1.37 Bates et al. (2015)
lmerTest 3.1.3 Kuznetsova, Brockhoff, and Christensen (2017)
patchwork 1.3.2 Pedersen (2025)
performance 0.15.1 Lüdecke et al. (2021)
qreport 1.0.2 Harrell (2025)
report 0.6.1 Makowski et al. (2023)
rmarkdown 2.29 Xie, Allaire, and Grolemund (2018); Xie, Dervieux, and Riederer (2020); Allaire et al. (2024)
rstatix 0.7.2 Kassambara (2023)
scales 1.4.0 Wickham, Pedersen, and Seidel (2025)
sjlabelled 1.2.0 Lüdecke (2022)
sjPlot 2.9.0 Lüdecke (2025)
texreg 1.39.4 Leifeld (2013)
tidyverse 2.0.0 Wickham et al. (2019)

6 Sessioninfo

R version 4.4.3 (2025-02-28)
Platform: aarch64-apple-darwin20
Running under: macOS Ventura 13.6.9

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/Berlin
tzcode source: internal

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] emmeans_1.11.2-8    ggrepel_0.9.6       sjPlot_2.9.0        effects_4.2-4       carData_3.0-5       see_0.11.0          report_0.6.1       
 [8] parameters_0.28.1   performance_0.15.1  modelbased_0.13.0   insight_1.4.2       effectsize_1.0.1    datawizard_1.2.0    correlation_0.8.8  
[15] bayestestR_0.17.0   easystats_0.7.5     texreg_1.39.4       broom.mixed_0.2.9.6 lmerTest_3.1-3      lme4_1.1-37         Matrix_1.7-3       
[22] grateful_0.3.0      ggmosaic_0.3.3      ggsci_3.2.0         qreport_1.0-2       data.table_1.17.8   Hmisc_5.2-3         flextable_0.9.10   
[29] gtsummary_2.4.0     scales_1.4.0        kableExtra_1.4.0    knitr_1.50          patchwork_1.3.2     gghighlight_0.5.0   rstatix_0.7.2      
[36] ggpmisc_0.6.2       ggpp_0.5.9          labelled_2.14.1     sjlabelled_1.2.0    ggpubr_0.6.1        broom_1.0.9         lubridate_1.9.4    
[43] forcats_1.0.0       stringr_1.5.2       dplyr_1.1.4         purrr_1.1.0         readr_2.1.5         tidyr_1.3.1         tibble_3.3.0       
[50] ggplot2_3.5.2       tidyverse_2.0.0    

loaded via a namespace (and not attached):
  [1] splines_4.4.3           polspline_1.1.25        bitops_1.0-9            rpart_4.1.24            lifecycle_1.0.4         Rdpack_2.6.4           
  [7] pbmcapply_1.5.1         doParallel_1.0.17       globals_0.18.0          lattice_0.22-7          MASS_7.3-65             backports_1.5.0        
 [13] survey_4.4-8            magrittr_2.0.3          plotly_4.11.0           rmarkdown_2.29          qqplotr_0.0.7           yaml_2.3.10            
 [19] qqconf_1.3.2            zip_2.3.3               askpass_1.2.1           DBI_1.2.3               minqa_1.2.8             RColorBrewer_1.1-3     
 [25] DHARMa_0.4.7            multcomp_1.4-28         abind_1.4-8             pracma_2.4.4            nnet_7.3-20             TH.data_1.1-4          
 [31] sandwich_3.1-1          gdtools_0.4.3           pbkrtest_0.5.5          listenv_0.9.1           cards_0.7.0             xslt_1.5.1             
 [37] MatrixModels_0.5-4      parallelly_1.45.1       svglite_2.2.1           codetools_0.2-20        xml2_1.4.0              tidyselect_1.2.1       
 [43] ggeffects_2.3.1         farver_2.1.2            viridis_0.6.5           base64enc_0.1-3         jsonlite_2.0.0          opdisDownsampling_1.0.1
 [49] Formula_1.2-5           iterators_1.0.14        survival_3.8-3          systemfonts_1.2.3       foreach_1.5.2           tools_4.4.3            
 [55] twosamples_2.0.1        ragg_1.5.0              Rcpp_1.1.0              glue_1.8.0              gridExtra_2.3           mgcv_1.9-3             
 [61] xfun_0.53               withr_3.0.2             numDeriv_2016.8-1.1     fastmap_1.2.0           mitools_2.4             boot_1.3-31            
 [67] SparseM_1.84-2          openssl_2.3.3           caTools_1.18.3          digest_0.6.37           timechange_0.3.0        R6_2.6.1               
 [73] estimability_1.5.1      textshaping_1.0.3       colorspace_2.1-1        dichromat_2.0-0.1       generics_0.1.4          renv_1.1.5             
 [79] fontLiberation_0.1.0    robustbase_0.99-6       httr_1.4.7              htmlwidgets_1.6.4       pkgconfig_2.0.3         gtable_0.3.6           
 [85] furrr_0.3.1             htmltools_0.5.8.1       fontBitstreamVera_0.1.1 snakecase_0.11.1        reformulas_0.4.1        rstudioapi_0.17.1      
 [91] tzdb_0.5.0              uuid_1.2-1              curl_7.0.0              coda_0.19-4.1           checkmate_2.3.3         nlme_3.1-168           
 [97] nloptr_2.2.1            zoo_1.8-14              parallel_4.4.3          foreign_0.8-90          pillar_1.11.0           vctrs_0.6.5            
[103] car_3.1-3               xtable_1.8-4            cluster_2.1.8.1         htmlTable_2.4.3         evaluate_1.0.5          mvtnorm_1.3-3          
[109] cli_3.6.5               compiler_4.4.3          rlang_1.1.6             rms_8.0-0               ggsignif_0.6.4          labeling_0.4.3         
[115] sjmisc_2.8.11           plyr_1.8.9              stringi_1.8.7           viridisLite_0.4.2       productplots_0.1.1      lazyeval_0.2.2         
[121] V8_7.0.0                quantreg_6.1            fontquiver_0.2.1        hms_1.1.3               future_1.67.0           haven_2.5.5            
[127] rbibutils_2.3           DEoptimR_1.1-4          katex_1.5.0             equatags_0.2.2          officer_0.7.0           polynom_1.4-1          

References

Allaire, JJ, Yihui Xie, Christophe Dervieux, Jonathan McPherson, Javier Luraschi, Kevin Ushey, Aron Atkins, et al. 2024. rmarkdown: Dynamic Documents for r. https://github.com/rstudio/rmarkdown.
Aphalo, Pedro J. 2025. ggpmisc: Miscellaneous Extensions to ggplot2. https://CRAN.R-project.org/package=ggpmisc.
Bates, Douglas, Martin Mächler, Ben Bolker, and Steve Walker. 2015. “Fitting Linear Mixed-Effects Models Using lme4.” Journal of Statistical Software 67 (1): 1–48. https://doi.org/10.18637/jss.v067.i01.
Bolker, Ben, and David Robinson. 2024. broom.mixed: Tidying Methods for Mixed Models. https://CRAN.R-project.org/package=broom.mixed.
Fox, John. 2003. “Effect Displays in R for Generalised Linear Models.” Journal of Statistical Software 8 (15): 1–27. https://doi.org/10.18637/jss.v008.i15.
Fox, John, and Jangman Hong. 2009. “Effect Displays in R for Multinomial and Proportional-Odds Logit Models: Extensions to the effects Package.” Journal of Statistical Software 32 (1): 1–24. https://doi.org/10.18637/jss.v032.i01.
Fox, John, and Sanford Weisberg. 2018. “Visualizing Fit and Lack of Fit in Complex Regression Models with Predictor Effect Plots and Partial Residuals.” Journal of Statistical Software 87 (9): 1–27. https://doi.org/10.18637/jss.v087.i09.
———. 2019a. An R Companion to Applied Regression. Third. Thousand Oaks CA: Sage. https://www.john-fox.ca/Companion/.
———. 2019b. An r Companion to Applied Regression. 3rd ed. Thousand Oaks CA: Sage. https://www.john-fox.ca/Companion/index.html.
Gohel, David, and Panagiotis Skintzos. 2025. flextable: Functions for Tabular Reporting. https://CRAN.R-project.org/package=flextable.
Harrell, Frank. 2025. qreport: Statistical Reporting with Quarto. https://CRAN.R-project.org/package=qreport.
Jeppson, Haley, Heike Hofmann, and Di Cook. 2021. ggmosaic: Mosaic Plots in the ggplot2 Framework. https://CRAN.R-project.org/package=ggmosaic.
Kassambara, Alboukadel. 2023. rstatix: Pipe-Friendly Framework for Basic Statistical Tests. https://CRAN.R-project.org/package=rstatix.
———. 2025. ggpubr: ggplot2 Based Publication Ready Plots. https://CRAN.R-project.org/package=ggpubr.
Kuznetsova, Alexandra, Per B. Brockhoff, and Rune H. B. Christensen. 2017. lmerTest Package: Tests in Linear Mixed Effects Models.” Journal of Statistical Software 82 (13): 1–26. https://doi.org/10.18637/jss.v082.i13.
Larmarange, Joseph. 2025. labelled: Manipulating Labelled Data. https://CRAN.R-project.org/package=labelled.
Leifeld, Philip. 2013. texreg: Conversion of Statistical Model Output in R to LaTeX and HTML Tables.” Journal of Statistical Software 55 (8): 1–24. https://doi.org/10.18637/jss.v055.i08.
Lenth, Russell V. 2025. emmeans: Estimated Marginal Means, Aka Least-Squares Means. https://CRAN.R-project.org/package=emmeans.
Lüdecke, Daniel. 2022. sjlabelled: Labelled Data Utility Functions (Version 1.2.0). https://doi.org/10.5281/zenodo.1249215.
———. 2025. sjPlot: Data Visualization for Statistics in Social Science. https://CRAN.R-project.org/package=sjPlot.
Lüdecke, Daniel, Mattan S. Ben-Shachar, Indrajeet Patil, Philip Waggoner, and Dominique Makowski. 2021. performance: An R Package for Assessment, Comparison and Testing of Statistical Models.” Journal of Open Source Software 6 (60): 3139. https://doi.org/10.21105/joss.03139.
Lüdecke, Daniel, Mattan S. Ben-Shachar, Indrajeet Patil, Brenton M. Wiernik, Etienne Bacher, Rémi Thériault, and Dominique Makowski. 2022. easystats: Framework for Easy Statistical Modeling, Visualization, and Reporting.” CRAN. https://doi.org/10.32614/CRAN.package.easystats.
Makowski, Dominique, Daniel Lüdecke, Indrajeet Patil, Rémi Thériault, Mattan S. Ben-Shachar, and Brenton M. Wiernik. 2023. “Automated Results Reporting as a Practical Tool to Improve Reproducibility and Methodological Best Practices Adoption.” CRAN. https://easystats.github.io/report/.
Pedersen, Thomas Lin. 2025. patchwork: The Composer of Plots. https://CRAN.R-project.org/package=patchwork.
R Core Team. 2025. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Sjoberg, Daniel D., Karissa Whiting, Michael Curry, Jessica A. Lavery, and Joseph Larmarange. 2021. “Reproducible Summary Tables with the Gtsummary Package.” The R Journal 13: 570–80. https://doi.org/10.32614/RJ-2021-053.
Slowikowski, Kamil. 2024. ggrepel: Automatically Position Non-Overlapping Text Labels with ggplot2. https://CRAN.R-project.org/package=ggrepel.
Wickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686. https://doi.org/10.21105/joss.01686.
Wickham, Hadley, Thomas Lin Pedersen, and Dana Seidel. 2025. scales: Scale Functions for Visualization. https://CRAN.R-project.org/package=scales.
Xiao, Nan. 2024. ggsci: Scientific Journal and Sci-Fi Themed Color Palettes for ggplot2. https://CRAN.R-project.org/package=ggsci.
Xie, Yihui. 2014. knitr: A Comprehensive Tool for Reproducible Research in R.” In Implementing Reproducible Computational Research, edited by Victoria Stodden, Friedrich Leisch, and Roger D. Peng. Chapman; Hall/CRC.
———. 2015. Dynamic Documents with R and Knitr. 2nd ed. Boca Raton, Florida: Chapman; Hall/CRC. https://yihui.org/knitr/.
———. 2025. knitr: A General-Purpose Package for Dynamic Report Generation in R. https://yihui.org/knitr/.
Xie, Yihui, J. J. Allaire, and Garrett Grolemund. 2018. R Markdown: The Definitive Guide. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown.
Xie, Yihui, Christophe Dervieux, and Emily Riederer. 2020. R Markdown Cookbook. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown-cookbook.
Yutani, Hiroaki. 2025. gghighlight: Highlight Lines and Points in ggplot2. https://CRAN.R-project.org/package=gghighlight.
Zhu, Hao. 2024. kableExtra: Construct Complex Table with kable and Pipe Syntax. https://CRAN.R-project.org/package=kableExtra.