# =============================================================================
# NAMA             : ANDINA OKTAVIANTY
# NIM              : 2611018012
# DOSEN PENGAMPU   : DR.M.FATHURAHMAN,S.SI.,M.SI
# MATA KULIAH      : BIOSTATISTIKA INTERMEDIATE
# =============================================================================

# =============================================================================
# ISI:
#   0. Paket & pengaturan
#   1. Simulasi data (format panjang & lebar)
#   2. Eksplorasi data: statistik deskriptif, profile plot, spaghetti plot
#   3. Repeated Measure ANOVA satu arah (within-subject: Waktu)
#        3a. Uji asumsi: outlier, normalitas, sfierisitas (Mauchly)
#        3b. ANOVA + koreksi Greenhouse-Geisser / Huynh-Feldt
#        3c. Pendekatan multivariat (MANOVA) sebagai pembanding
#        3d. Post hoc berpasangan & kontras polinomial (tren)
#        3e. Alternatif nonparametrik: uji Friedman
#   4. Mixed Design ANOVA (between: Kelompok x within: Waktu)
#        4a. Uji asumsi: outlier, normalitas, Levene, Box's M, Mauchly
#        4b. ANOVA campuran + ukuran efek
#        4c. Analisis efek sederhana (simple effects) & post hoc
#        4d. Kontras interaksi (perubahan dari baseline antarkelompok)
#   5. Pembanding: Linear Mixed Model (LMM)
#   6. Menyimpan data & ringkasan hasil
# =============================================================================

# =============================================================================
# REPEATED MEASURE ANALYSIS DENGAN R
# KASUS: PROGRAM PENATALAKSANAAN OBESITAS DAN INDEKS MASSA TUBUH (IMT/BMI)
# DATA SIMULASI
#
# Skenario:
# 120 orang dewasa dengan obesitas diacak menjadi 3 kelompok (n = 40/kelompok):
#   - Kontrol         : edukasi standar
#   - Diet            : intervensi diet rendah kalori
#   - Diet+Aktif      : intervensi diet rendah kalori + aktivitas fisik
#
# IMT (kg/m^2) diukur pada minggu ke-0, 4, 8, dan 12.
#
# Pertanyaan analisis:
#   1. Apakah IMT berubah dari waktu ke waktu?
#   2. Apakah pola perubahan IMT berbeda antar kelompok?
#
# Struktur analisis sengaja dibuat sama seperti latihan sebelumnya:
#   - Simulasi data wide & long
#   - Statistik deskriptif
#   - Profile plot & spaghetti plot
#   - Repeated Measure ANOVA satu arah
#   - Outlier, Shapiro-Wilk, Mauchly, Greenhouse-Geisser/Huynh-Feldt
#   - Pendekatan multivariat (MANOVA)
#   - Post hoc & kontras tren
#   - Alternatif nonparametrik Friedman
#   - Mixed Design ANOVA
#   - Simple effects & post hoc
#   - Linear Mixed Model (LMM)
#   - Simulasi data hilang
#   - Menyimpan data
# =============================================================================
# 0. PAKET & PENGATURAN
# Jalankan sekali bila paket belum terpasang:
# install.packages(c("tidyverse", "afex", "emmeans", "rstatix", "car",
#                    "effectsize", "lme4", "lmerTest", "performance", "ggpubr"))

suppressPackageStartupMessages({
  library(dplyr)
  library(tidyr)
  library(ggplot2)
  library(afex)
  library(emmeans)
  library(rstatix)
  library(car)
  library(effectsize)
  library(lme4)
  library(lmerTest)
})

options(contrasts = c("contr.sum", "contr.poly"))
afex_options(emmeans_model = "multivariate")
theme_set(theme_bw(base_size = 12))
# 1. SIMULASI DATA
set.seed(2026)

n_per   <- 40
kel_lab <- c("Kontrol", "Diet", "Diet+Aktif")
minggu  <- c(0, 4, 8, 12)

# Rerata populasi IMT (kg/m^2) per kelompok x waktu
# Kontrol      : perubahan kecil
# Diet         : penurunan sedang
# Diet+Aktif   : penurunan lebih besar
mu <- rbind(
  "Kontrol"    = c(31.5, 31.3, 31.1, 30.9),
  "Diet"       = c(31.5, 30.6, 29.8, 29.1),
  "Diet+Aktif" = c(31.5, 30.3, 29.2, 28.3)
)

# Komponen variasi antar individu dan galat pengukuran
sd_int   <- 1.7
sd_slope <- 0.07
sd_eps   <- 0.45

dat_wide <- lapply(seq_along(kel_lab), function(g) {

  id <- (g - 1) * n_per + seq_len(n_per)

  # Perbedaan IMT awal antar peserta
  b0 <- rnorm(n_per, 0, sd_int)

  # Perbedaan laju perubahan antar peserta
  b1 <- rnorm(n_per, 0, sd_slope)

  y <- sapply(seq_along(minggu), function(t)
    mu[g, t] +
      b0 +
      b1 * minggu[t] +
      rnorm(n_per, 0, sd_eps)
  )

  colnames(y) <- paste0("IMT_M", minggu)

  data.frame(
    id       = sprintf("O%03d", id),
    kelompok = kel_lab[g],
    usia     = round(runif(n_per, 25, 60)),
    jk       = sample(
      c("L", "P"),
      n_per,
      replace = TRUE,
      prob = c(.40, .60)
    ),
    round(y, 2)
  )

}) |> bind_rows()

dat_wide$kelompok <- factor(dat_wide$kelompok, levels = kel_lab)
dat_wide$id       <- factor(dat_wide$id)


# Format panjang
dat_long <- dat_wide |>
  pivot_longer(
    starts_with("IMT_M"),
    names_to = "waktu",
    values_to = "imt"
  ) |>
  mutate(
    waktu = factor(
      waktu,
      levels = paste0("IMT_M", minggu),
      labels = paste0("M", minggu)
    ),
    minggu = as.numeric(sub("M", "", waktu))
  )

head(dat_wide)
##     id kelompok usia jk IMT_M0 IMT_M4 IMT_M8 IMT_M12
## 1 O001  Kontrol   46  L  31.86  32.72  31.97   30.62
## 2 O002  Kontrol   43  L  30.34  30.64  29.31   29.92
## 3 O003  Kontrol   44  L  31.22  31.30  30.27   30.02
## 4 O004  Kontrol   40  L  30.66  31.65  31.48   30.18
## 5 O005  Kontrol   56  P  30.34  29.15  29.32   28.94
## 6 O006  Kontrol   55  L  27.60  27.63  27.52   28.61
head(dat_long)
## # A tibble: 6 × 7
##   id    kelompok  usia jk    waktu   imt minggu
##   <fct> <fct>    <dbl> <chr> <fct> <dbl>  <dbl>
## 1 O001  Kontrol     46 L     M0     31.9      0
## 2 O001  Kontrol     46 L     M4     32.7      4
## 3 O001  Kontrol     46 L     M8     32.0      8
## 4 O001  Kontrol     46 L     M12    30.6     12
## 5 O002  Kontrol     43 L     M0     30.3      0
## 6 O002  Kontrol     43 L     M4     30.6      4
str(dat_long)
## tibble [480 × 7] (S3: tbl_df/tbl/data.frame)
##  $ id      : Factor w/ 120 levels "O001","O002",..: 1 1 1 1 2 2 2 2 3 3 ...
##  $ kelompok: Factor w/ 3 levels "Kontrol","Diet",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ usia    : num [1:480] 46 46 46 46 43 43 43 43 44 44 ...
##  $ jk      : chr [1:480] "L" "L" "L" "L" ...
##  $ waktu   : Factor w/ 4 levels "M0","M4","M8",..: 1 2 3 4 1 2 3 4 1 2 ...
##  $ imt     : num [1:480] 31.9 32.7 32 30.6 30.3 ...
##  $ minggu  : num [1:480] 0 4 8 12 0 4 8 12 0 4 ...
# 2. EKSPLORASI DATA
# Statistik deskriptif: mean dan SD
desk <- dat_long |>
  group_by(kelompok, waktu) |>
  get_summary_stats(imt, type = "mean_sd")

desk
## # A tibble: 12 × 6
##    kelompok   waktu variable     n  mean    sd
##    <fct>      <fct> <fct>    <dbl> <dbl> <dbl>
##  1 Kontrol    M0    imt         40  31.4  1.72
##  2 Kontrol    M4    imt         40  31.3  1.56
##  3 Kontrol    M8    imt         40  31.0  1.73
##  4 Kontrol    M12   imt         40  30.8  1.67
##  5 Diet       M0    imt         40  31.3  1.94
##  6 Diet       M4    imt         40  30.5  1.91
##  7 Diet       M8    imt         40  29.8  1.94
##  8 Diet       M12   imt         40  29.1  1.98
##  9 Diet+Aktif M0    imt         40  31.7  1.61
## 10 Diet+Aktif M4    imt         40  30.6  1.70
## 11 Diet+Aktif M8    imt         40  29.5  1.70
## 12 Diet+Aktif M12   imt         40  28.5  1.93
# Matriks kovarians
S <- cov(dat_wide[, paste0("IMT_M", minggu)])
round(S, 2)
##         IMT_M0 IMT_M4 IMT_M8 IMT_M12
## IMT_M0    3.09   2.76   2.70    2.76
## IMT_M4    2.76   3.07   3.07    3.23
## IMT_M8    2.70   3.07   3.57    3.68
## IMT_M12   2.76   3.23   3.68    4.34
# Matriks korelasi
R <- cor(dat_wide[, paste0("IMT_M", minggu)])
round(R, 2)
##         IMT_M0 IMT_M4 IMT_M8 IMT_M12
## IMT_M0    1.00   0.90   0.81    0.75
## IMT_M4    0.90   1.00   0.93    0.88
## IMT_M8    0.81   0.93   1.00    0.93
## IMT_M12   0.75   0.88   0.93    1.00
# Varians selisih antar pasangan waktu
pasangan <- combn(paste0("IMT_M", minggu), 2)

var_selisih <- apply(
  pasangan,
  2,
  function(p)
    var(dat_wide[[p[1]]] - dat_wide[[p[2]]])
)

names(var_selisih) <- apply(
  pasangan,
  2,
  paste,
  collapse = " - "
)

round(var_selisih, 2)
##  IMT_M0 - IMT_M4  IMT_M0 - IMT_M8 IMT_M0 - IMT_M12  IMT_M4 - IMT_M8 
##             0.64             1.25             1.90             0.50 
## IMT_M4 - IMT_M12 IMT_M8 - IMT_M12 
##             0.96             0.56
# 2a. PROFILE PLOT
p_profil <- ggplot(
  dat_long,
  aes(
    minggu,
    imt,
    colour = kelompok,
    group = kelompok
  )
) +
  stat_summary(
    fun = mean,
    geom = "line",
    linewidth = 1
  ) +
  stat_summary(
    fun = mean,
    geom = "point",
    size = 2.5
  ) +
  stat_summary(
    fun.data = mean_cl_normal,
    geom = "errorbar",
    width = .6
  ) +
  scale_x_continuous(
    breaks = minggu
  ) +
  labs(
    x = "Minggu ke-",
    y = "Indeks Massa Tubuh (kg/m²)",
    colour = "Kelompok",
    title = "Profil rerata IMT (± 95% CI)"
  ) +
  theme(
    legend.position = "bottom"
  )

p_profil
## Warning: Computation failed in `stat_summary()`.
## Caused by error in `fun.data()`:
## ! The package "Hmisc" is required.

# 2b. SPAGHETTI PLOT
p_spag <- ggplot(
  dat_long,
  aes(
    minggu,
    imt,
    group = id
  )
) +
  geom_line(alpha = .3) +
  stat_summary(
    aes(group = kelompok),
    fun = mean,
    geom = "line",
    colour = "firebrick",
    linewidth = 1.2
  ) +
  facet_wrap(~ kelompok) +
  scale_x_continuous(
    breaks = minggu
  ) +
  labs(
    x = "Minggu ke-",
    y = "IMT (kg/m²)",
    title = "Lintasan individu dan rerata kelompok"
  )

p_spag

# 3. REPEATED MEASURE ANOVA SATU ARAH
# Pertanyaan:
# Apakah IMT berubah selama 12 minggu pada kelompok Diet+Aktif?

d1  <- droplevels(
  filter(dat_long, kelompok == "Diet+Aktif")
)

d1w <- filter(
  dat_wide,
  kelompok == "Diet+Aktif"
)
# 3a. UJI ASUMSI
# (i) Outlier per waktu
d1 |>
  group_by(waktu) |>
  identify_outliers(imt)
## # A tibble: 5 × 9
##   waktu id    kelompok    usia jk      imt minggu is.outlier is.extreme
##   <fct> <fct> <fct>      <dbl> <chr> <dbl>  <dbl> <lgl>      <lgl>     
## 1 M0    O105  Diet+Aktif    60 P      36.0      0 TRUE       FALSE     
## 2 M4    O105  Diet+Aktif    60 P      35.4      4 TRUE       FALSE     
## 3 M8    O105  Diet+Aktif    60 P      34.4      8 TRUE       FALSE     
## 4 M12   O091  Diet+Aktif    37 P      33.1     12 TRUE       FALSE     
## 5 M12   O105  Diet+Aktif    60 P      33.6     12 TRUE       FALSE
# (ii) Normalitas per waktu
d1 |>
  group_by(waktu) |>
  shapiro_test(imt)
## # A tibble: 4 × 4
##   waktu variable statistic     p
##   <fct> <chr>        <dbl> <dbl>
## 1 M0    imt          0.978 0.599
## 2 M4    imt          0.962 0.196
## 3 M8    imt          0.966 0.264
## 4 M12   imt          0.970 0.371
# Q-Q plot
ggpubr::ggqqplot(
  d1,
  "imt",
  facet.by = "waktu"
)

# (iii) Sphericity: Mauchly
aov1_rs <- anova_test(
  data = d1,
  dv = imt,
  wid = id,
  within = waktu,
  effect.size = "pes"
)

aov1_rs
## ANOVA Table (type III tests)
## 
## $ANOVA
##   Effect DFn DFd       F        p p<.05 pes
## 1  waktu   3 117 349.407 3.31e-58     * 0.9
## 
## $`Mauchly's Test for Sphericity`
##   Effect    W     p p<.05
## 1  waktu 0.71 0.024     *
## 
## $`Sphericity Corrections`
##   Effect GGe     DF[GG]    p[GG] p[GG]<.05   HFe       DF[HF]    p[HF]
## 1  waktu 0.8 2.4, 93.59 4.48e-47         * 0.856 2.57, 100.15 3.39e-50
##   p[HF]<.05
## 1         *
get_anova_table(
  aov1_rs,
  correction = "auto"
)
## ANOVA Table (type III tests)
## 
##   Effect DFn   DFd       F        p p<.05 pes
## 1  waktu 2.4 93.59 349.407 4.48e-47     * 0.9
# 3b. REPEATED MEASURE ANOVA DENGAN AFEX
aov1 <- aov_ez(
  id = "id",
  dv = "imt",
  data = d1,
  within = "waktu",
  anova_table = list(
    es = c("ges", "pes"),
    correction = "GG"
  )
)

aov1
## Anova Table (Type 3 tests)
## 
## Response: imt
##   Effect          df  MSE          F  ges  pes p.value
## 1  waktu 2.40, 93.59 0.27 349.41 *** .327 .900   <.001
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
## 
## Sphericity correction method: GG
summary(aov1)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##             Sum Sq num Df Error SS den Df  F value    Pr(>F)    
## (Intercept) 144717      1   447.04     39 12625.30 < 2.2e-16 ***
## waktu          229      3    25.58    117   349.41 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Mauchly Tests for Sphericity
## 
##       Test statistic  p-value
## waktu        0.71039 0.024391
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##        GG eps Pr(>F[GG])    
## waktu 0.79991  < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##          HF eps   Pr(>F[HF])
## waktu 0.8560008 3.389893e-50
# Ukuran efek
eta_squared(
  aov1,
  partial = TRUE
)
## # Effect Size for ANOVA (Type III)
## 
## Parameter | Eta2 (partial) |       95% CI
## -----------------------------------------
## waktu     |           0.90 | [0.87, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
omega_squared(
  aov1,
  partial = TRUE
)
## # Effect Size for ANOVA (Type III)
## 
## Parameter | Omega2 (partial) |       95% CI
## -------------------------------------------
## waktu     |             0.32 | [0.20, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
# 3c. PENDEKATAN MULTIVARIAT
aov1$Anova
## 
## Type III Repeated Measures MANOVA Tests: Pillai test statistic
##             Df test stat approx F num Df den Df    Pr(>F)    
## (Intercept)  1   0.99692  12625.3      1     39 < 2.2e-16 ***
## waktu        1   0.94116    197.3      3     37 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# 3d. POST HOC & KONTRAS TREN
em1 <- emmeans(
  aov1,
  ~ waktu
)

em1
##  waktu emmean    SE df lower.CL upper.CL
##  M0      31.7 0.255 39     31.2     32.2
##  M4      30.6 0.268 39     30.1     31.2
##  M8      29.5 0.269 39     29.0     30.0
##  M12     28.5 0.306 39     27.9     29.1
## 
## Confidence level used: 0.95
# Semua pasangan waktu
pairs(
  em1,
  adjust = "bonferroni"
)
##  contrast estimate     SE df t.ratio p.value
##  M0 - M4      1.07 0.0868 39  12.378 <0.0001
##  M0 - M8      2.19 0.1070 39  20.429 <0.0001
##  M0 - M12     3.20 0.1300 39  24.514 <0.0001
##  M4 - M8      1.11 0.0901 39  12.336 <0.0001
##  M4 - M12     2.12 0.1130 39  18.750 <0.0001
##  M8 - M12     1.01 0.0931 39  10.864 <0.0001
## 
## P value adjustment: bonferroni method for 6 tests
# Tiap waktu dibandingkan baseline M0
contrast(
  em1,
  "trt.vs.ctrl",
  ref = 1,
  adjust = "holm"
)
##  contrast estimate     SE df t.ratio p.value
##  M4 - M0     -1.07 0.0868 39 -12.378 <0.0001
##  M8 - M0     -2.19 0.1070 39 -20.429 <0.0001
##  M12 - M0    -3.20 0.1300 39 -24.514 <0.0001
## 
## P value adjustment: holm method for 3 tests
# Tren linear, kuadratik, kubik
contrast(
  em1,
  "poly"
)
##  contrast  estimate    SE df t.ratio p.value
##  linear    -10.7037 0.431 39 -24.855 <0.0001
##  quadratic   0.0633 0.124 39   0.511  0.6123
##  cubic       0.1388 0.257 39   0.540  0.5919
# 3e. ALTERNATIF NONPARAMETRIK
friedman_test(
  d1,
  imt ~ waktu | id
)
## # A tibble: 1 × 6
##   .y.       n statistic    df        p method       
## * <chr> <int>     <dbl> <dbl>    <dbl> <chr>        
## 1 imt      40      115.     3 7.86e-25 Friedman test
friedman_effsize(
  d1,
  imt ~ waktu | id
)
## # A tibble: 1 × 5
##   .y.       n effsize method    magnitude
## * <chr> <int>   <dbl> <chr>     <ord>    
## 1 imt      40   0.961 Kendall W large
d1 |>
  wilcox_test(
    imt ~ waktu,
    paired = TRUE,
    p.adjust.method = "bonferroni"
  )
## # A tibble: 6 × 9
##   .y.   group1 group2    n1    n2 statistic        p    p.adj p.adj.signif
## * <chr> <chr>  <chr>  <int> <int>     <dbl>    <dbl>    <dbl> <chr>       
## 1 imt   M0     M4        40    40       820 1.82e-12 1.09e-11 ****        
## 2 imt   M0     M8        40    40       820 1.82e-12 1.09e-11 ****        
## 3 imt   M0     M12       40    40       820 1.82e-12 1.09e-11 ****        
## 4 imt   M4     M8        40    40       817 9.09e-12 5.46e-11 ****        
## 5 imt   M4     M12       40    40       820 1.82e-12 1.09e-11 ****        
## 6 imt   M8     M12       40    40       816 1.27e-11 7.64e-11 ****
# 4. MIXED DESIGN ANOVA
#    BETWEEN = KELOMPOK
#    WITHIN  = WAKTU
# Pertanyaan:
# Apakah pola perubahan IMT berbeda antar kelompok?
# 4a. UJI ASUMSI
# (i) Outlier per sel
dat_long |>
  group_by(kelompok, waktu) |>
  identify_outliers(imt)
## # A tibble: 15 × 9
##    kelompok   waktu id     usia jk      imt minggu is.outlier is.extreme
##    <fct>      <fct> <fct> <dbl> <chr> <dbl>  <dbl> <lgl>      <lgl>     
##  1 Kontrol    M0    O015     30 L      26.4      0 TRUE       FALSE     
##  2 Kontrol    M4    O006     55 L      27.6      4 TRUE       FALSE     
##  3 Kontrol    M4    O015     30 L      27.0      4 TRUE       FALSE     
##  4 Kontrol    M8    O006     55 L      27.5      8 TRUE       FALSE     
##  5 Kontrol    M8    O015     30 L      26.4      8 TRUE       FALSE     
##  6 Kontrol    M8    O026     27 P      34.5      8 TRUE       FALSE     
##  7 Kontrol    M12   O015     30 L      25.9     12 TRUE       FALSE     
##  8 Diet       M4    O076     41 P      25.6      4 TRUE       FALSE     
##  9 Diet       M8    O075     60 P      24.7      8 TRUE       FALSE     
## 10 Diet       M12   O076     41 P      24.5     12 TRUE       FALSE     
## 11 Diet+Aktif M0    O105     60 P      36.0      0 TRUE       FALSE     
## 12 Diet+Aktif M4    O105     60 P      35.4      4 TRUE       FALSE     
## 13 Diet+Aktif M8    O105     60 P      34.4      8 TRUE       FALSE     
## 14 Diet+Aktif M12   O091     37 P      33.1     12 TRUE       FALSE     
## 15 Diet+Aktif M12   O105     60 P      33.6     12 TRUE       FALSE
# (ii) Normalitas per sel
dat_long |>
  group_by(kelompok, waktu) |>
  shapiro_test(imt)
## # A tibble: 12 × 5
##    kelompok   waktu variable statistic     p
##    <fct>      <fct> <chr>        <dbl> <dbl>
##  1 Kontrol    M0    imt          0.975 0.505
##  2 Kontrol    M4    imt          0.967 0.285
##  3 Kontrol    M8    imt          0.979 0.640
##  4 Kontrol    M12   imt          0.981 0.714
##  5 Diet       M0    imt          0.961 0.179
##  6 Diet       M4    imt          0.967 0.278
##  7 Diet       M8    imt          0.963 0.218
##  8 Diet       M12   imt          0.979 0.645
##  9 Diet+Aktif M0    imt          0.978 0.599
## 10 Diet+Aktif M4    imt          0.962 0.196
## 11 Diet+Aktif M8    imt          0.966 0.264
## 12 Diet+Aktif M12   imt          0.970 0.371
# Q-Q plot per kelompok dan waktu
ggpubr::ggqqplot(
  dat_long,
  "imt",
  ggtheme = theme_bw()
) +
  facet_grid(waktu ~ kelompok)

# (iii) Homogenitas varians antarkelompok pada tiap waktu
dat_long |>
  group_by(waktu) |>
  levene_test(imt ~ kelompok)
## # A tibble: 4 × 5
##   waktu   df1   df2 statistic     p
##   <fct> <int> <int>     <dbl> <dbl>
## 1 M0        2   117     0.898 0.410
## 2 M4        2   117     0.753 0.473
## 3 M8        2   117     0.466 0.629
## 4 M12       2   117     0.687 0.505
# (iv) Homogenitas matriks kovarians
box_m(
  dat_wide[, paste0("IMT_M", minggu)],
  dat_wide$kelompok
)
## # A tibble: 1 × 4
##   statistic p.value parameter method                                            
##       <dbl>   <dbl>     <dbl> <chr>                                             
## 1      33.1  0.0329        20 Box's M-test for Homogeneity of Covariance Matric…
# (v) Sphericity diperiksa dari summary model
# 4b. MIXED DESIGN ANOVA
aov2 <- aov_ez(
  id = "id",
  dv = "imt",
  data = dat_long,
  between = "kelompok",
  within = "waktu",
  anova_table = list(
    es = c("ges", "pes"),
    correction = "GG"
  )
)

aov2
## Anova Table (Type 3 tests)
## 
## Response: imt
##           Effect           df   MSE          F  ges  pes p.value
## 1       kelompok       2, 117 11.96     4.28 * .064 .068    .016
## 2          waktu 2.61, 305.91  0.32 322.21 *** .153 .734   <.001
## 3 kelompok:waktu 5.23, 305.91  0.32  44.35 *** .047 .431   <.001
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
## 
## Sphericity correction method: GG
summary(aov2)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                Sum Sq num Df Error SS den Df    F value  Pr(>F)    
## (Intercept)    445364      1  1398.75    117 37252.9424 < 2e-16 ***
## kelompok          102      2  1398.75    117     4.2837 0.01602 *  
## waktu             271      3    98.36    351   322.2149 < 2e-16 ***
## kelompok:waktu     75      6    98.36    351    44.3468 < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Mauchly Tests for Sphericity
## 
##                Test statistic    p-value
## waktu                 0.80121 0.00010448
## kelompok:waktu        0.80121 0.00010448
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##                 GG eps Pr(>F[GG])    
## waktu          0.87153  < 2.2e-16 ***
## kelompok:waktu 0.87153  < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##                   HF eps   Pr(>F[HF])
## waktu          0.8932393 4.915785e-90
## kelompok:waktu 0.8932393 3.101891e-36
aov2$Anova
## 
## Type III Repeated Measures MANOVA Tests: Pillai test statistic
##                Df test stat approx F num Df den Df    Pr(>F)    
## (Intercept)     1   0.99687    37253      1    117 < 2.2e-16 ***
## kelompok        2   0.06823        4      2    117   0.01602 *  
## waktu           1   0.84888      215      3    115 < 2.2e-16 ***
## kelompok:waktu  2   0.61410       17      6    232 2.247e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Versi rstatix
aov2_rs <- anova_test(
  data = dat_long,
  dv = imt,
  wid = id,
  between = kelompok,
  within = waktu,
  effect.size = "pes",
  type = 3
)

get_anova_table(
  aov2_rs,
  correction = "GG"
)
## ANOVA Table (type III tests)
## 
##           Effect  DFn    DFd       F        p p<.05   pes
## 1       kelompok 2.00 117.00   4.284 1.60e-02     * 0.068
## 2          waktu 2.61 305.91 322.215 6.43e-88     * 0.734
## 3 kelompok:waktu 5.23 305.91  44.347 2.04e-35     * 0.431
# Ukuran efek
eta_squared(
  aov2,
  partial = TRUE
)
## # Effect Size for ANOVA (Type III)
## 
## Parameter      | Eta2 (partial) |       95% CI
## ----------------------------------------------
## kelompok       |           0.07 | [0.01, 1.00]
## waktu          |           0.73 | [0.70, 1.00]
## kelompok:waktu |           0.43 | [0.36, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
omega_squared(
  aov2,
  partial = TRUE
)
## # Effect Size for ANOVA (Type III)
## 
## Parameter      | Omega2 (partial) |       95% CI
## ------------------------------------------------
## kelompok       |             0.05 | [0.00, 1.00]
## waktu          |             0.15 | [0.09, 1.00]
## kelompok:waktu |             0.05 | [0.01, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
# 4c. PLOT INTERAKSI
afex_plot(
  aov2,
  x = "waktu",
  trace = "kelompok",
  error = "within",
  mapping = c("colour", "shape", "linetype")
) +
  labs(
    y = "IMT (kg/m²)",
    x = "Waktu"
  )
## Warning: Panel(s) show a mixed within-between-design.
## Error bars do not allow comparisons across all means.
## Suppress error bars with: error = "none"

# 4d. EFEK SEDERHANA
em2 <- emmeans(
  aov2,
  ~ waktu | kelompok
)


# Efek WAKTU dalam tiap kelompok
joint_tests(
  aov2,
  by = "kelompok"
)
## Warning in pf(conf$F.ratio, conf$df1, conf$df2, lower.tail = FALSE): NaNs
## produced
## kelompok = Kontrol:
##  model term df1 df2 F.ratio p.value
##  waktu        3 117   8.957 <0.0001
## 
## kelompok = Diet:
##  model term df1 df2 F.ratio p.value
##  waktu        3 117  85.698 <0.0001
## 
## kelompok = Diet+Aktif:
##  model term df1 df2 F.ratio p.value
##  waktu        3 117 184.390 <0.0001
# Efek KELOMPOK pada tiap waktu
joint_tests(
  aov2,
  by = "waktu"
)
## waktu = M0:
##  model term df1 df2 F.ratio p.value
##  kelompok     2 117   0.544  0.5819
## 
## waktu = M4:
##  model term df1 df2 F.ratio p.value
##  kelompok     2 117   2.523  0.0846
## 
## waktu = M8:
##  model term df1 df2 F.ratio p.value
##  kelompok     2 117   7.617  0.0008
## 
## waktu = M12:
##  model term df1 df2 F.ratio p.value
##  kelompok     2 117  15.746 <0.0001
# Post hoc: setiap waktu vs baseline
contrast(
  em2,
  "trt.vs.ctrl",
  ref = 1,
  adjust = "holm"
)
## kelompok = Kontrol:
##  contrast estimate    SE  df t.ratio p.value
##  M4 - M0   -0.0432 0.107 117  -0.402  0.6881
##  M8 - M0   -0.3730 0.133 117  -2.810  0.0116
##  M12 - M0  -0.6110 0.139 117  -4.400 <0.0001
## 
## kelompok = Diet:
##  contrast estimate    SE  df t.ratio p.value
##  M4 - M0   -0.7718 0.107 117  -7.180 <0.0001
##  M8 - M0   -1.4690 0.133 117 -11.067 <0.0001
##  M12 - M0  -2.1963 0.139 117 -15.815 <0.0001
## 
## kelompok = Diet+Aktif:
##  contrast estimate    SE  df t.ratio p.value
##  M4 - M0   -1.0742 0.107 117  -9.994 <0.0001
##  M8 - M0   -2.1862 0.133 117 -16.471 <0.0001
##  M12 - M0  -3.1972 0.139 117 -23.023 <0.0001
## 
## P value adjustment: holm method for 3 tests
# Perbandingan antarkelompok pada tiap waktu
em2b <- emmeans(
  aov2,
  ~ kelompok | waktu
)

pairs(
  em2b,
  adjust = "tukey"
)
## waktu = M0:
##  contrast               estimate    SE  df t.ratio p.value
##  Kontrol - Diet           0.0605 0.395 117   0.153  0.9871
##  Kontrol - (Diet+Aktif)  -0.3222 0.395 117  -0.817  0.6934
##  Diet - (Diet+Aktif)     -0.3827 0.395 117  -0.970  0.5972
## 
## waktu = M4:
##  contrast               estimate    SE  df t.ratio p.value
##  Kontrol - Diet           0.7890 0.387 117   2.041  0.1071
##  Kontrol - (Diet+Aktif)   0.7087 0.387 117   1.833  0.1633
##  Diet - (Diet+Aktif)     -0.0803 0.387 117  -0.208  0.9765
## 
## waktu = M8:
##  contrast               estimate    SE  df t.ratio p.value
##  Kontrol - Diet           1.1565 0.401 117   2.885  0.0129
##  Kontrol - (Diet+Aktif)   1.4910 0.401 117   3.719  0.0009
##  Diet - (Diet+Aktif)      0.3345 0.401 117   0.834  0.6825
## 
## waktu = M12:
##  contrast               estimate    SE  df t.ratio p.value
##  Kontrol - Diet           1.6458 0.417 117   3.946  0.0004
##  Kontrol - (Diet+Aktif)   2.2640 0.417 117   5.429 <0.0001
##  Diet - (Diet+Aktif)      0.6182 0.417 117   1.482  0.3031
## 
## P value adjustment: tukey method for comparing a family of 3 estimates
# 4e. KONTRAS INTERAKSI
# Apakah perubahan IMT M12 - M0 berbeda antar kelompok?
em_full <- emmeans(
  aov2,
  ~ waktu * kelompok
)

contrast(
  em_full,
  interaction = list(
    waktu = list(
      "M12-M0" = c(-1, 0, 0, 1)
    ),
    kelompok = "pairwise"
  ),
  adjust = "holm"
)
##  waktu_custom kelompok_pairwise      estimate    SE  df t.ratio p.value
##  M12-M0       Kontrol - Diet             1.59 0.196 117   8.072 <0.0001
##  M12-M0       Kontrol - (Diet+Aktif)     2.59 0.196 117  13.168 <0.0001
##  M12-M0       Diet - (Diet+Aktif)        1.00 0.196 117   5.097 <0.0001
## 
## P value adjustment: holm method for 3 tests
# 4f. TREN LINEAR ANTARKELOMPOK
contrast(
  em2,
  "poly"
)[c(1, 4, 7)]
##  contrast kelompok   estimate    SE  df t.ratio p.value
##  linear   Kontrol       -2.16 0.457 117  -4.735 <0.0001
##  linear   Diet          -7.29 0.457 117 -15.952 <0.0001
##  linear   Diet+Aktif   -10.70 0.457 117 -23.434 <0.0001
tren_int <- summary(
  contrast(
    em_full,
    interaction = c(
      waktu = "poly",
      kelompok = "pairwise"
    ),
    adjust = "none"
  )
)

tren_lin <- subset(
  tren_int,
  waktu_poly == "linear"
)

tren_lin$p.holm <- p.adjust(
  tren_lin$p.value,
  "holm"
)

tren_lin
##   waktu_poly      kelompok_pairwise estimate        SE  df   t.ratio
## 1     linear         Kontrol - Diet  5.12325 0.6459466 117  7.931383
## 4     linear Kontrol - (Diet+Aktif)  8.54100 0.6459466 117 13.222455
## 7     linear    Diet - (Diet+Aktif)  3.41775 0.6459466 117  5.291072
##        p.value       p.holm
## 1 1.435931e-12 2.871862e-12
## 4 5.678700e-25 1.703610e-24
## 7 5.748809e-07 5.748809e-07
# 5. PEMBANDING: LINEAR MIXED MODEL (LMM)
lmm1 <- lmer(
  imt ~ kelompok * waktu + (1 | id),
  data = dat_long,
  REML = TRUE
)


lmm2 <- lmer(
  imt ~ kelompok * waktu + (1 + minggu | id),
  data = dat_long,
  REML = TRUE
)


# Perbandingan struktur efek acak
anova(
  lmm1,
  lmm2,
  refit = FALSE
)
## Data: dat_long
## Models:
## lmm1: imt ~ kelompok * waktu + (1 | id)
## lmm2: imt ~ kelompok * waktu + (1 + minggu | id)
##      npar    AIC    BIC  logLik -2*log(L)  Chisq Df Pr(>Chisq)    
## lmm1   14 1261.3 1319.7 -616.64    1233.3                         
## lmm2   16 1244.0 1310.7 -605.98    1212.0 21.316  2  2.351e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Uji efek tetap
anova(
  lmm2,
  ddf = "Kenward-Roger"
)
## Type III Analysis of Variance Table with Kenward-Roger's method
##                 Sum Sq Mean Sq NumDF  DenDF  F value  Pr(>F)    
## kelompok         1.814   0.907     2 117.00   4.2836 0.01602 *  
## waktu          137.527  45.842     3 249.65 215.7770 < 2e-16 ***
## kelompok:waktu  38.156   6.359     6 278.39  29.9079 < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Intraclass correlation
performance::icc(lmm1)
## # Intraclass Correlation Coefficient
## 
##     Adjusted ICC: 0.912
##   Unadjusted ICC: 0.706
# 5a. DIAGNOSTIK RESIDUAL LMM
par(mfrow = c(1, 3))

qqnorm(
  resid(lmm2),
  main = "Q-Q residual"
)
qqline(
  resid(lmm2)
)

qqnorm(
  ranef(lmm2)$id[, 1],
  main = "Q-Q intersep acak"
)
qqline(
  ranef(lmm2)$id[, 1]
)

plot(
  fitted(lmm2),
  resid(lmm2),
  xlab = "Nilai prediksi",
  ylab = "Residual",
  main = "Residual vs prediksi"
)

abline(
  h = 0,
  lty = 2
)

par(mfrow = c(1, 1))
# 5b. SIMULASI DATA HILANG
set.seed(1)

dat_miss <- dat_long

dat_miss$imt[
  sample(
    which(dat_miss$waktu != "M0"),
    30
  )
] <- NA


lmm_miss <- lmer(
  imt ~ kelompok * waktu + (1 + minggu | id),
  data = dat_miss,
  control = lmerControl(
    optimizer = "bobyqa"
  )
)


anova(
  lmm_miss,
  ddf = "Kenward-Roger"
)
## Type III Analysis of Variance Table with Kenward-Roger's method
##                 Sum Sq Mean Sq NumDF  DenDF  F value  Pr(>F)    
## kelompok         1.842   0.921     2 116.99   4.2967 0.01582 *  
## waktu          136.381  45.460     3 232.06 211.3945 < 2e-16 ***
## kelompok:waktu  37.861   6.310     6 257.42  29.3180 < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Jumlah ID yang memiliki minimal satu data hilang
n_distinct(
  dat_miss$id[
    is.na(dat_miss$imt)
  ]
)
## [1] 27
# 6. SIMPAN DATA
write.csv(
  dat_wide,
  "data_imt_obesitas_wide.csv",
  row.names = FALSE
)

write.csv(
  dat_long,
  "data_imt_obesitas_long.csv",
  row.names = FALSE
)
# 7. SESSION INFO
sessionInfo()
## R version 4.6.1 (2026-06-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=English_Indonesia.utf8  LC_CTYPE=English_Indonesia.utf8   
## [3] LC_MONETARY=English_Indonesia.utf8 LC_NUMERIC=C                      
## [5] LC_TIME=English_Indonesia.utf8    
## 
## time zone: Asia/Makassar
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] lmerTest_3.2-1   effectsize_1.0.3 car_3.1-5        carData_3.0-6   
##  [5] rstatix_1.1.0    emmeans_2.0.4    afex_1.5-1       lme4_2.0-6      
##  [9] Matrix_1.7-5     ggplot2_4.0.3    tidyr_1.3.2      dplyr_1.2.1     
## 
## loaded via a namespace (and not attached):
##  [1] gtable_0.3.6        xfun_0.61           bslib_0.12.0       
##  [4] bayestestR_0.19.0   insight_1.5.4       lattice_0.22-9     
##  [7] numDeriv_2016.8-1.1 vctrs_0.7.3         tools_4.6.1        
## [10] Rdpack_2.6.6        generics_0.1.4      pbkrtest_0.5.5     
## [13] parallel_4.6.1      datawizard_1.4.0    tibble_3.3.1       
## [16] pkgconfig_2.0.3     RColorBrewer_1.1-3  S7_0.2.2           
## [19] lifecycle_1.0.5     compiler_4.6.1      farver_2.1.2       
## [22] stringr_1.6.0       htmltools_0.5.9     sass_0.4.10        
## [25] yaml_2.3.12         Formula_1.2-6       ggpubr_1.0.0       
## [28] pillar_1.11.1       nloptr_2.2.1        jquerylib_0.1.4    
## [31] MASS_7.3-65         cachem_1.1.0        reformulas_0.4.4   
## [34] boot_1.3-32         abind_1.4-8         nlme_3.1-169       
## [37] tidyselect_1.2.1    digest_0.6.39       performance_0.18.2 
## [40] mvtnorm_1.4-2       stringi_1.8.9       reshape2_1.4.5     
## [43] purrr_1.2.2         labeling_0.4.3      splines_4.6.1      
## [46] fastmap_1.2.0       grid_4.6.1          cli_3.6.6          
## [49] magrittr_2.0.5      utf8_1.2.6          broom_1.0.13       
## [52] withr_3.0.3         scales_1.4.0        backports_1.5.1    
## [55] estimability_2.0.0  rmarkdown_2.32      ggsignif_0.6.4     
## [58] evaluate_1.0.5      knitr_1.52          parameters_0.29.3  
## [61] rbibutils_2.4.1     rlang_1.3.0         Rcpp_1.1.2         
## [64] glue_1.8.1          minqa_1.2.8         jsonlite_2.0.0     
## [67] R6_2.6.1            plyr_1.8.9