# Nama : Dhea Fara Dhina
# NIM  : 2611018015
#=============================================================================
#  REPEATED MEASURE ANALYSIS DENGAN R
#  Contoh terapan: intervensi gaya hidup dan berat badan
#  pada subjek obesitas (DATA SIMULASI/MODIFIKASI)
#
#  Dasar modifikasi:
#  Bhutani S, Klempel MC, Kroeger CM, Trepanowski JF, Varady KA. (2013).
#  Alternate day fasting and endurance exercise combine to reduce body weight
#  and favorably alter plasma lipids in obese humans.
#  Obesity (Silver Spring), 21(7), 1370-1379.
#  DOI: 10.1002/oby.20353
#
#  Catatan:
#  Data yang digunakan adalah DATA SIMULASI yang dimodifikasi berdasarkan
#  desain penelitian dan pola perubahan berat badan dari artikel tersebut.
#  Nilai Bulan 1 dan Bulan 2 dibuat untuk kebutuhan latihan repeated measure,
#  bukan merupakan data bulanan asli dari artikel.
#
#  Isi:
#   0. Paket & pengaturan
#   1. Import data utama CSV + pembentukan data long
#   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 ke bulan 3)
#   5. Pembanding: Linear Mixed Model (LMM)
#   6. Menyimpan data & ringkasan hasil
# =============================================================================
# 0. PAKET & PENGATURAN
# Jalankan sekali bila paket belum terpasang:
# install.packages(c("dplyr", "tidyr", "ggplot2", "afex", "emmeans",
#                    "rstatix", "car", "effectsize", "lme4", "lmerTest",
#                    "performance", "ggpubr", "pbkrtest"))

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. IMPORT DATA
# Skenario penelitian. 64 subjek dengan obesitas dibagi ke empat kelompok:
#   - Kontrol        : kelompok kontrol
#   - ADF            : alternate day fasting
#   - Olahraga       : endurance exercise
#   - ADF + Olahraga : alternate day fasting + endurance exercise
# Berat badan diukur pada Bulan ke-0 (baseline), 1, 2, dan 3.

file_data <- "DATA_UTAMA_Obesitas_64.csv"

# Jika file tidak berada di working directory, pilih file secara manual:
if (!file.exists(file_data)) {
  file_data <- file.choose()
}

dat_wide_raw <- read.csv(
  file_data,
  stringsAsFactors = FALSE,
  check.names = FALSE
)

# Cek data awal
head(dat_wide_raw)
##     ID       Kelompok Usia JK BB_Bulan_0_kg BB_Bulan_1_kg BB_Bulan_2_kg
## 1 P001 ADF + Olahraga   56  P          83.3          80.6          77.4
## 2 P002 ADF + Olahraga   55  P          87.5          85.4          83.1
## 3 P003        Kontrol   46  P          88.7          88.8          88.5
## 4 P004        Kontrol   57  P          82.1          82.1          82.1
## 5 P005        Kontrol   35  P          95.1          95.0          95.0
## 6 P006       Olahraga   53  P          95.0          94.7          94.2
##   BB_Bulan_3_kg Perubahan_BB_3_Bulan
## 1          74.5                 -8.8
## 2          81.3                 -6.2
## 3          88.5                 -0.2
## 4          82.1                  0.0
## 5          95.2                  0.1
## 6          94.1                 -0.9
str(dat_wide_raw)
## 'data.frame':    64 obs. of  9 variables:
##  $ ID                  : chr  "P001" "P002" "P003" "P004" ...
##  $ Kelompok            : chr  "ADF + Olahraga" "ADF + Olahraga" "Kontrol" "Kontrol" ...
##  $ Usia                : int  56 55 46 57 35 53 59 49 53 54 ...
##  $ JK                  : chr  "P" "P" "P" "P" ...
##  $ BB_Bulan_0_kg       : num  83.3 87.5 88.7 82.1 95.1 ...
##  $ BB_Bulan_1_kg       : num  80.6 85.4 88.8 82.1 95 ...
##  $ BB_Bulan_2_kg       : num  77.4 83.1 88.5 82.1 95 ...
##  $ BB_Bulan_3_kg       : num  74.5 81.3 88.5 82.1 95.2 ...
##  $ Perubahan_BB_3_Bulan: num  -8.8 -6.2 -0.2 0 0.1 -0.9 -3.8 0.3 -2.9 -6.2 ...
dim(dat_wide_raw)
## [1] 64  9
# Menghapus kolom index jika ada
if ("index" %in% names(dat_wide_raw)) {
  dat_wide_raw <- dat_wide_raw |> select(-index)
}

names(dat_wide_raw)
## [1] "ID"                   "Kelompok"             "Usia"                
## [4] "JK"                   "BB_Bulan_0_kg"        "BB_Bulan_1_kg"       
## [7] "BB_Bulan_2_kg"        "BB_Bulan_3_kg"        "Perubahan_BB_3_Bulan"
# Faktor
kel_lab <- c("Kontrol", "ADF", "Olahraga", "ADF + Olahraga")
bulan   <- c(0, 1, 2, 3)

dat_wide <- dat_wide_raw |>
  mutate(
    id       = factor(ID),
    kelompok = factor(Kelompok, levels = kel_lab),
    usia     = Usia,
    jk       = factor(JK)
  ) |>
  select(
    id, kelompok, usia, jk,
    BB_Bulan_0_kg, BB_Bulan_1_kg, BB_Bulan_2_kg, BB_Bulan_3_kg,
    Perubahan_BB_3_Bulan
  )

# Format panjang (satu baris = satu pengukuran)
dat_long <- dat_wide |>
  pivot_longer(
    cols = starts_with("BB_Bulan_"),
    names_to = "waktu",
    values_to = "bb"
  ) |>
  mutate(
    bulan = as.numeric(
      sub("BB_Bulan_", "", sub("_kg", "", waktu))
    ),
    waktu = factor(
      waktu,
      levels = paste0("BB_Bulan_", bulan, "_kg"),
      labels = paste0("M", bulan)
    )
  ) |>
  arrange(id, bulan)

head(dat_wide)
##     id       kelompok usia jk BB_Bulan_0_kg BB_Bulan_1_kg BB_Bulan_2_kg
## 1 P001 ADF + Olahraga   56  P          83.3          80.6          77.4
## 2 P002 ADF + Olahraga   55  P          87.5          85.4          83.1
## 3 P003        Kontrol   46  P          88.7          88.8          88.5
## 4 P004        Kontrol   57  P          82.1          82.1          82.1
## 5 P005        Kontrol   35  P          95.1          95.0          95.0
## 6 P006       Olahraga   53  P          95.0          94.7          94.2
##   BB_Bulan_3_kg Perubahan_BB_3_Bulan
## 1          74.5                 -8.8
## 2          81.3                 -6.2
## 3          88.5                 -0.2
## 4          82.1                  0.0
## 5          95.2                  0.1
## 6          94.1                 -0.9
head(dat_long)
## # A tibble: 6 × 8
##   id    kelompok        usia jk    Perubahan_BB_3_Bulan waktu    bb bulan
##   <fct> <fct>          <int> <fct>                <dbl> <fct> <dbl> <dbl>
## 1 P001  ADF + Olahraga    56 P                     -8.8 M0     83.3     0
## 2 P001  ADF + Olahraga    56 P                     -8.8 M1     80.6     1
## 3 P001  ADF + Olahraga    56 P                     -8.8 M2     77.4     2
## 4 P001  ADF + Olahraga    56 P                     -8.8 M3     74.5     3
## 5 P002  ADF + Olahraga    55 P                     -6.2 M0     87.5     0
## 6 P002  ADF + Olahraga    55 P                     -6.2 M1     85.4     1
str(dat_long)
## tibble [256 × 8] (S3: tbl_df/tbl/data.frame)
##  $ id                  : Factor w/ 64 levels "P001","P002",..: 1 1 1 1 2 2 2 2 3 3 ...
##  $ kelompok            : Factor w/ 4 levels "Kontrol","ADF",..: 4 4 4 4 4 4 4 4 1 1 ...
##  $ usia                : int [1:256] 56 56 56 56 55 55 55 55 46 46 ...
##  $ jk                  : Factor w/ 2 levels "L","P": 2 2 2 2 2 2 2 2 2 2 ...
##  $ Perubahan_BB_3_Bulan: num [1:256] -8.8 -8.8 -8.8 -8.8 -6.2 -6.2 -6.2 -6.2 -0.2 -0.2 ...
##  $ waktu               : Factor w/ 4 levels "M0","M1","M2",..: 1 2 3 4 1 2 3 4 1 2 ...
##  $ bb                  : num [1:256] 83.3 80.6 77.4 74.5 87.5 85.4 83.1 81.3 88.7 88.8 ...
##  $ bulan               : num [1:256] 0 1 2 3 0 1 2 3 0 1 ...
# Opsional: simpan hasil format long ke CSV
write.csv(
  dat_long,
  "DATA_LONG_Obesitas_64.csv",
  row.names = FALSE
)
# 2. EKSPLORASI DATA
# Statistik deskriptif per kelompok dan waktu
desk <- dat_long |>
  group_by(kelompok, waktu) |>
  get_summary_stats(bb, type = "mean_sd")

desk
## # A tibble: 16 × 6
##    kelompok       waktu variable     n  mean    sd
##    <fct>          <fct> <fct>    <dbl> <dbl> <dbl>
##  1 Kontrol        M0    bb          16  94.2  8.35
##  2 Kontrol        M1    bb          16  94.1  8.36
##  3 Kontrol        M2    bb          16  94.1  8.43
##  4 Kontrol        M3    bb          16  94.1  8.42
##  5 ADF            M0    bb          16  94.8  7.40
##  6 ADF            M1    bb          16  93.7  7.44
##  7 ADF            M2    bb          16  92.8  7.46
##  8 ADF            M3    bb          16  91.8  7.50
##  9 Olahraga       M0    bb          16  94.1  6.39
## 10 Olahraga       M1    bb          16  93.8  6.39
## 11 Olahraga       M2    bb          16  93.4  6.38
## 12 Olahraga       M3    bb          16  93.2  6.33
## 13 ADF + Olahraga M0    bb          16  91.7  5.80
## 14 ADF + Olahraga M1    bb          16  89.8  5.86
## 15 ADF + Olahraga M2    bb          16  87.4  5.92
## 16 ADF + Olahraga M3    bb          16  85.4  6.05
# Matriks kovarians & korelasi antarwaktu
S <- cov(dat_wide[, paste0("BB_Bulan_", bulan, "_kg")])
R <- cor(dat_wide[, paste0("BB_Bulan_", bulan, "_kg")])

round(S, 2)
##               BB_Bulan_0_kg BB_Bulan_1_kg BB_Bulan_2_kg BB_Bulan_3_kg
## BB_Bulan_0_kg         48.85         49.60         50.66         51.39
## BB_Bulan_1_kg         49.60         50.96         52.71         54.06
## BB_Bulan_2_kg         50.66         52.71         55.35         57.44
## BB_Bulan_3_kg         51.39         54.06         57.44         60.20
round(R, 2)
##               BB_Bulan_0_kg BB_Bulan_1_kg BB_Bulan_2_kg BB_Bulan_3_kg
## BB_Bulan_0_kg          1.00          0.99          0.97          0.95
## BB_Bulan_1_kg          0.99          1.00          0.99          0.98
## BB_Bulan_2_kg          0.97          0.99          1.00          1.00
## BB_Bulan_3_kg          0.95          0.98          1.00          1.00
# Varians selisih antarpasangan waktu
pasangan <- combn(paste0("BB_Bulan_", bulan, "_kg"), 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)
## BB_Bulan_0_kg - BB_Bulan_1_kg BB_Bulan_0_kg - BB_Bulan_2_kg 
##                          0.61                          2.89 
## BB_Bulan_0_kg - BB_Bulan_3_kg BB_Bulan_1_kg - BB_Bulan_2_kg 
##                          6.27                          0.89 
## BB_Bulan_1_kg - BB_Bulan_3_kg BB_Bulan_2_kg - BB_Bulan_3_kg 
##                          3.04                          0.67
# Profile plot: rerata +/- 95% CI per kelompok
p_profil <- ggplot(
  dat_long,
  aes(bulan, bb, 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 = .08
  ) +
  scale_x_continuous(breaks = bulan) +
  labs(
    x = "Bulan ke-",
    y = "Berat badan (kg)",
    colour = "Kelompok",
    title = "Profil rerata berat badan (± 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.

# Spaghetti plot: lintasan tiap subjek
p_spag <- ggplot(
  dat_long,
  aes(bulan, bb, 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 = bulan) +
  labs(
    x = "Bulan ke-",
    y = "Berat badan (kg)",
    title = "Lintasan individu dan rerata kelompok"
  )

p_spag

# 3. REPEATED MEASURE ANOVA SATU ARAH
#    Pertanyaan:
#    apakah berat badan berubah selama 3 bulan pada kelompok ADF + Olahraga?
d1 <- droplevels(
  filter(dat_long, kelompok == "ADF + Olahraga")
)

d1w <- filter(
  dat_wide,
  kelompok == "ADF + Olahraga"
)


## 3a. Uji asumsi -------------------------------------------------------------

# (i) Outlier per waktu
d1 |>
  group_by(waktu) |>
  identify_outliers(bb)
##  [1] waktu                id                   kelompok            
##  [4] usia                 jk                   Perubahan_BB_3_Bulan
##  [7] bb                   bulan                is.outlier          
## [10] is.extreme          
## <0 rows> (or 0-length row.names)
# (ii) Normalitas per waktu (Shapiro-Wilk)
sw1 <- d1 |>
  group_by(waktu) |>
  shapiro_test(bb)

sw1
## # A tibble: 4 × 4
##   waktu variable statistic     p
##   <fct> <chr>        <dbl> <dbl>
## 1 M0    bb           0.936 0.298
## 2 M1    bb           0.935 0.296
## 3 M2    bb           0.953 0.544
## 4 M3    bb           0.958 0.630
# Q-Q plot
ggpubr::ggqqplot(
  d1,
  "bb",
  facet.by = "waktu"
)

# (iii) Sfierisitas: Mauchly
aov1_rs <- anova_test(
  data = d1,
  dv = bb,
  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  45 337.53 7.53e-31     * 0.957
## 
## $`Mauchly's Test for Sphericity`
##   Effect     W        p p<.05
## 1  waktu 0.002 8.48e-17     *
## 
## $`Sphericity Corrections`
##   Effect   GGe      DF[GG]   p[GG] p[GG]<.05   HFe      DF[HF]    p[HF]
## 1  waktu 0.345 1.04, 15.53 4.9e-12         * 0.348 1.04, 15.65 4.13e-12
##   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 1.04 15.53 337.53 4.9e-12     * 0.957
## 3b. ANOVA dengan afex -------------------------------------------------------

aov1 <- aov_ez(
  id = "id",
  dv = "bb",
  data = d1,
  within = "waktu",
  anova_table = list(
    es = c("ges", "pes"),
    correction = "GG"
  )
)

aov1
## Anova Table (Type 3 tests)
## 
## Response: bb
##   Effect          df  MSE          F  ges  pes p.value
## 1  waktu 1.04, 15.53 1.02 337.53 *** .145 .957   <.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) 502132      1  2078.48     15 3623.79 < 2.2e-16 ***
## waktu          356      3    15.83     45  337.53 < 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.0019453 8.4755e-17
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##        GG eps Pr(>F[GG])    
## waktu 0.34514  4.902e-12 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##          HF eps   Pr(>F[HF])
## waktu 0.3477097 4.132171e-12
# Ukuran efek tambahan
eta_squared(aov1, partial = TRUE)
## # Effect Size for ANOVA (Type III)
## 
## Parameter | Eta2 (partial) |       95% CI
## -----------------------------------------
## waktu     |           0.96 | [0.94, 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.14 | [0.00, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
## 3c. Pendekatan multivariat (MANOVA) ----------------------------------------

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.99588   3623.8      1     15 < 2.2e-16 ***
## waktu        1   0.95986    103.6      3     13 2.502e-09 ***
## ---
## 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      91.7 1.45 15     88.6     94.8
##  M1      89.8 1.47 15     86.7     92.9
##  M2      87.4 1.48 15     84.3     90.6
##  M3      85.4 1.51 15     82.2     88.6
## 
## Confidence level used: 0.95
# Semua pasangan waktu
pairs(
  em1,
  adjust = "bonferroni"
)
##  contrast estimate    SE df t.ratio p.value
##  M0 - M1      1.89 0.111 15  17.061 <0.0001
##  M0 - M2      4.24 0.235 15  18.030 <0.0001
##  M0 - M3      6.24 0.336 15  18.561 <0.0001
##  M1 - M2      2.35 0.133 15  17.722 <0.0001
##  M1 - M3      4.36 0.233 15  18.718 <0.0001
##  M2 - M3      2.01 0.107 15  18.813 <0.0001
## 
## P value adjustment: bonferroni method for 6 tests
# Setiap waktu dibandingkan dengan baseline
contrast(
  em1,
  "trt.vs.ctrl",
  ref = 1,
  adjust = "holm"
)
##  contrast estimate    SE df t.ratio p.value
##  M1 - M0     -1.89 0.111 15 -17.061 <0.0001
##  M2 - M0     -4.24 0.235 15 -18.030 <0.0001
##  M3 - M0     -6.24 0.336 15 -18.561 <0.0001
## 
## P value adjustment: holm method for 3 tests
# Tren linear, kuadratik, dan kubik
contrast(
  em1,
  "poly"
)
##  contrast  estimate     SE df t.ratio p.value
##  linear     -21.081 1.1400 15 -18.536 <0.0001
##  quadratic   -0.119 0.0476 15  -2.493  0.0248
##  cubic        0.806 0.1180 15   6.805 <0.0001
## 3e. Alternatif nonparametrik ----------------------------------------------

friedman_test(
  d1,
  bb ~ waktu | id
)
## # A tibble: 1 × 6
##   .y.       n statistic    df        p method       
## * <chr> <int>     <dbl> <dbl>    <dbl> <chr>        
## 1 bb       16        48     3 2.13e-10 Friedman test
friedman_effsize(
  d1,
  bb ~ waktu | id
)
## # A tibble: 1 × 5
##   .y.       n effsize method    magnitude
## * <chr> <int>   <dbl> <chr>     <ord>    
## 1 bb       16       1 Kendall W large
d1 |>
  wilcox_test(
    bb ~ 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 bb    M0     M1        16    16       136 0.0000305 0.000183 ***         
## 2 bb    M0     M2        16    16       136 0.0000305 0.000183 ***         
## 3 bb    M0     M3        16    16       136 0.0000305 0.000183 ***         
## 4 bb    M1     M2        16    16       136 0.0000305 0.000183 ***         
## 5 bb    M1     M3        16    16       136 0.0000305 0.000183 ***         
## 6 bb    M2     M3        16    16       136 0.0000305 0.000183 ***
# (Opsional) ANOVA robust berbasis trimmed mean -- paket WRS2
if (requireNamespace("WRS2", quietly = TRUE)) {
  print(
    WRS2::rmanova(
      d1$bb,
      d1$waktu,
      d1$id,
      tr = 0.2
    )
  )
}
## Call:
## WRS2::rmanova(y = d1$bb, groups = d1$waktu, blocks = d1$id, tr = 0.2)
## 
## Test statistic: F = 268.6431 
## Degrees of freedom 1: 1.1 
## Degrees of freedom 2: 9.87 
## p-value: 0
# 4. MIXED DESIGN ANOVA  (Kelompok [between] x Waktu [within])
## 4a. Uji asumsi -------------------------------------------------------------

# (i) Outlier per sel
dat_long |>
  group_by(kelompok, waktu) |>
  identify_outliers(bb)
## # A tibble: 8 × 10
##   kelompok waktu id     usia jk    Perubahan_BB_3_Bulan    bb bulan is.outlier
##   <fct>    <fct> <fct> <int> <fct>                <dbl> <dbl> <dbl> <lgl>     
## 1 ADF      M0    P041     25 P                     -2.9 111.      0 TRUE      
## 2 ADF      M0    P060     57 P                     -3.1  80.4     0 TRUE      
## 3 ADF      M1    P041     25 P                     -2.9 110.      1 TRUE      
## 4 ADF      M1    P060     57 P                     -3.1  79.2     1 TRUE      
## 5 ADF      M2    P041     25 P                     -2.9 109.      2 TRUE      
## 6 ADF      M2    P060     57 P                     -3.1  78.3     2 TRUE      
## 7 ADF      M3    P041     25 P                     -2.9 108.      3 TRUE      
## 8 ADF      M3    P060     57 P                     -3.1  77.3     3 TRUE      
## # ℹ 1 more variable: is.extreme <lgl>
# (ii) Normalitas per sel
dat_long |>
  group_by(kelompok, waktu) |>
  shapiro_test(bb)
## # A tibble: 16 × 5
##    kelompok       waktu variable statistic      p
##    <fct>          <fct> <chr>        <dbl>  <dbl>
##  1 Kontrol        M0    bb           0.959 0.636 
##  2 Kontrol        M1    bb           0.959 0.645 
##  3 Kontrol        M2    bb           0.957 0.616 
##  4 Kontrol        M3    bb           0.958 0.617 
##  5 ADF            M0    bb           0.963 0.717 
##  6 ADF            M1    bb           0.964 0.728 
##  7 ADF            M2    bb           0.968 0.811 
##  8 ADF            M3    bb           0.970 0.833 
##  9 Olahraga       M0    bb           0.899 0.0788
## 10 Olahraga       M1    bb           0.902 0.0862
## 11 Olahraga       M2    bb           0.896 0.0699
## 12 Olahraga       M3    bb           0.899 0.0778
## 13 ADF + Olahraga M0    bb           0.936 0.298 
## 14 ADF + Olahraga M1    bb           0.935 0.296 
## 15 ADF + Olahraga M2    bb           0.953 0.544 
## 16 ADF + Olahraga M3    bb           0.958 0.630
# Q-Q plot per kelompok dan waktu
ggpubr::ggqqplot(
  dat_long,
  "bb",
  ggtheme = theme_bw()
) +
  facet_grid(waktu ~ kelompok)

# (iii) Homogenitas varians antarkelompok pada tiap waktu
dat_long |>
  group_by(waktu) |>
  levene_test(bb ~ kelompok)
## # A tibble: 4 × 5
##   waktu   df1   df2 statistic     p
##   <fct> <int> <int>     <dbl> <dbl>
## 1 M0        3    60     0.652 0.585
## 2 M1        3    60     0.607 0.613
## 3 M2        3    60     0.580 0.630
## 4 M3        3    60     0.528 0.665
# (iv) Homogenitas matriks kovarians antarkelompok (Box's M)
box_m(
  dat_wide[, paste0("BB_Bulan_", bulan, "_kg")],
  dat_wide$kelompok
)
## # A tibble: 1 × 4
##   statistic     p.value parameter method                                        
##       <dbl>       <dbl>     <dbl> <chr>                                         
## 1      84.7 0.000000406        30 Box's M-test for Homogeneity of Covariance Ma…
## 4b. ANOVA campuran ---------------------------------------------------------

aov2 <- aov_ez(
  id = "id",
  dv = "bb",
  data = dat_long,
  between = "kelompok",
  within = "waktu",
  anova_table = list(
    es = c("ges", "pes"),
    correction = "GG"
  )
)

aov2
## Anova Table (Type 3 tests)
## 
## Response: bb
##           Effect          df    MSE          F  ges  pes p.value
## 1       kelompok       3, 60 201.17       2.11 .095 .095    .109
## 2          waktu 1.11, 66.39   0.28 756.83 *** .019 .927   <.001
## 3 kelompok:waktu 3.32, 66.39   0.28 219.61 *** .017 .917   <.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)    2185630      1  12070.2     60 10864.5716 <2e-16 ***
## kelompok          1271      3  12070.2     60     2.1053  0.109    
## waktu              238      3     18.9    180   756.8253 <2e-16 ***
## kelompok:waktu     207      9     18.9    180   219.6091 <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Mauchly Tests for Sphericity
## 
##                Test statistic    p-value
## waktu                0.015709 1.3786e-50
## kelompok:waktu       0.015709 1.3786e-50
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##                 GG eps Pr(>F[GG])    
## waktu          0.36883  < 2.2e-16 ***
## kelompok:waktu 0.36883  < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##                  HF eps   Pr(>F[HF])
## waktu          0.370703 1.991850e-39
## kelompok:waktu 0.370703 1.157069e-35
# Pendekatan multivariat
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.99451  10864.6      1     60 <2e-16 ***
## kelompok        3   0.09524      2.1      3     60  0.109    
## waktu           1   0.93162    263.4      3     58 <2e-16 ***
## kelompok:waktu  3   1.43814     18.4      9    180 <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Versi rstatix
aov2_rs <- anova_test(
  data = dat_long,
  dv = bb,
  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 3.00 60.00   2.105 1.09e-01       0.095
## 2          waktu 1.11 66.39 756.825 3.06e-39     * 0.927
## 3 kelompok:waktu 3.32 66.39 219.609 1.70e-35     * 0.917
# Ukuran efek
eta_squared(aov2, partial = TRUE)
## # Effect Size for ANOVA (Type III)
## 
## Parameter      | Eta2 (partial) |       95% CI
## ----------------------------------------------
## kelompok       |           0.10 | [0.00, 1.00]
## waktu          |           0.93 | [0.91, 1.00]
## kelompok:waktu |           0.92 | [0.90, 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.02 | [0.00, 1.00]
## kelompok:waktu |             0.02 | [0.00, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
# Plot interaksi
afex_plot(
  aov2,
  x = "waktu",
  trace = "kelompok",
  error = "within",
  mapping = c("colour", "shape", "linetype")
) +
  labs(
    y = "Berat badan (kg)",
    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"

## 4c. Efek sederhana & post hoc ---------------------------------------------

em2 <- emmeans(
  aov2,
  ~ waktu | kelompok
)

em2
## kelompok = Kontrol:
##  waktu emmean   SE df lower.CL upper.CL
##  M0      94.2 1.76 60     90.6     97.7
##  M1      94.1 1.77 60     90.6     97.7
##  M2      94.1 1.78 60     90.6     97.7
##  M3      94.1 1.78 60     90.5     97.7
## 
## kelompok = ADF:
##  waktu emmean   SE df lower.CL upper.CL
##  M0      94.8 1.76 60     91.3     98.4
##  M1      93.7 1.77 60     90.2     97.2
##  M2      92.8 1.78 60     89.2     96.4
##  M3      91.8 1.78 60     88.2     95.3
## 
## kelompok = Olahraga:
##  waktu emmean   SE df lower.CL upper.CL
##  M0      94.1 1.76 60     90.6     97.6
##  M1      93.8 1.77 60     90.2     97.3
##  M2      93.4 1.78 60     89.9     97.0
##  M3      93.2 1.78 60     89.6     96.7
## 
## kelompok = ADF + Olahraga:
##  waktu emmean   SE df lower.CL upper.CL
##  M0      91.7 1.76 60     88.1     95.2
##  M1      89.8 1.77 60     86.2     93.3
##  M2      87.4 1.78 60     83.9     91.0
##  M3      85.4 1.78 60     81.9     89.0
## 
## Confidence level used: 0.95
# Efek WAKTU di dalam masing-masing 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  60   0.053  0.9836
## 
## kelompok = ADF:
##  model term df1 df2 F.ratio p.value
##  waktu        3  60 118.045 <0.0001
## 
## kelompok = Olahraga:
##  model term df1 df2 F.ratio p.value
##  waktu        3  60   8.813 <0.0001
## 
## kelompok = ADF + Olahraga:
##  model term df1 df2 F.ratio p.value
##  waktu        3  60 398.003 <0.0001
# Efek KELOMPOK pada tiap waktu
joint_tests(
  aov2,
  by = "waktu"
)
## waktu = M0:
##  model term df1 df2 F.ratio p.value
##  kelompok     3  60   0.621  0.6041
## 
## waktu = M1:
##  model term df1 df2 F.ratio p.value
##  kelompok     3  60   1.347  0.2678
## 
## waktu = M2:
##  model term df1 df2 F.ratio p.value
##  kelompok     3  60   2.954  0.0396
## 
## waktu = M3:
##  model term df1 df2 F.ratio p.value
##  kelompok     3  60   4.800  0.0046
# Setiap waktu dibandingkan dengan baseline
contrast(
  em2,
  "trt.vs.ctrl",
  ref = 1,
  adjust = "holm"
)
## kelompok = Kontrol:
##  contrast estimate     SE df t.ratio p.value
##  M1 - M0   -0.0187 0.0623 60  -0.301  1.0000
##  M2 - M0   -0.0437 0.1270 60  -0.345  1.0000
##  M3 - M0   -0.0688 0.1810 60  -0.379  1.0000
## 
## kelompok = ADF:
##  contrast estimate     SE df t.ratio p.value
##  M1 - M0   -1.1500 0.0623 60 -18.446 <0.0001
##  M2 - M0   -2.0500 0.1270 60 -16.177 <0.0001
##  M3 - M0   -3.0688 0.1810 60 -16.938 <0.0001
## 
## kelompok = Olahraga:
##  contrast estimate     SE df t.ratio p.value
##  M1 - M0   -0.3063 0.0623 60  -4.912 <0.0001
##  M2 - M0   -0.6438 0.1270 60  -5.080 <0.0001
##  M3 - M0   -0.9187 0.1810 60  -5.071 <0.0001
## 
## kelompok = ADF + Olahraga:
##  contrast estimate     SE df t.ratio p.value
##  M1 - M0   -1.8875 0.0623 60 -30.276 <0.0001
##  M2 - M0   -4.2375 0.1270 60 -33.439 <0.0001
##  M3 - M0   -6.2438 0.1810 60 -34.462 <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 - ADF                -0.6813 2.49 60  -0.273  0.9928
##  Kontrol - Olahraga            0.0813 2.49 60   0.033  1.0000
##  Kontrol - (ADF + Olahraga)    2.4937 2.49 60   1.000  0.7499
##  ADF - Olahraga                0.7625 2.49 60   0.306  0.9900
##  ADF - (ADF + Olahraga)        3.1750 2.49 60   1.273  0.5833
##  Olahraga - (ADF + Olahraga)   2.4125 2.49 60   0.967  0.7683
## 
## waktu = M1:
##  contrast                    estimate   SE df t.ratio p.value
##  Kontrol - ADF                 0.4500 2.50 60   0.180  0.9979
##  Kontrol - Olahraga            0.3688 2.50 60   0.147  0.9988
##  Kontrol - (ADF + Olahraga)    4.3625 2.50 60   1.743  0.3111
##  ADF - Olahraga               -0.0813 2.50 60  -0.032  1.0000
##  ADF - (ADF + Olahraga)        3.9125 2.50 60   1.563  0.4073
##  Olahraga - (ADF + Olahraga)   3.9937 2.50 60   1.595  0.3889
## 
## waktu = M2:
##  contrast                    estimate   SE df t.ratio p.value
##  Kontrol - ADF                 1.3250 2.52 60   0.527  0.9523
##  Kontrol - Olahraga            0.6813 2.52 60   0.271  0.9930
##  Kontrol - (ADF + Olahraga)    6.6875 2.52 60   2.658  0.0481
##  ADF - Olahraga               -0.6438 2.52 60  -0.256  0.9941
##  ADF - (ADF + Olahraga)        5.3625 2.52 60   2.131  0.1550
##  Olahraga - (ADF + Olahraga)   6.0062 2.52 60   2.387  0.0905
## 
## waktu = M3:
##  contrast                    estimate   SE df t.ratio p.value
##  Kontrol - ADF                 2.3188 2.52 60   0.919  0.7950
##  Kontrol - Olahraga            0.9313 2.52 60   0.369  0.9827
##  Kontrol - (ADF + Olahraga)    8.6687 2.52 60   3.434  0.0058
##  ADF - Olahraga               -1.3875 2.52 60  -0.550  0.9463
##  ADF - (ADF + Olahraga)        6.3500 2.52 60   2.516  0.0676
##  Olahraga - (ADF + Olahraga)   7.7375 2.52 60   3.065  0.0167
## 
## P value adjustment: tukey method for comparing a family of 4 estimates
## 4d. Kontras interaksi -------------------------------------------------------

# Fokus: apakah perubahan dari Bulan 0 ke Bulan 3 berbeda antarkelompok?

em_full <- emmeans(
  aov2,
  ~ waktu * kelompok
)

change_m0_m3 <- contrast(
  em_full,
  interaction = c("revpairwise", "revpairwise"),
  adjust = "holm"
)

change_m0_m3
##  waktu_revpairwise kelompok_revpairwise        estimate     SE df t.ratio
##  M1 - M0           ADF - Kontrol                 -1.131 0.0882 60 -12.831
##  M2 - M0           ADF - Kontrol                 -2.006 0.1790 60 -11.195
##  M2 - M1           ADF - Kontrol                 -0.875 0.1050 60  -8.337
##  M3 - M0           ADF - Kontrol                 -3.000 0.2560 60 -11.708
##  M3 - M1           ADF - Kontrol                 -1.869 0.1800 60 -10.386
##  M3 - M2           ADF - Kontrol                 -0.994 0.0921 60 -10.787
##  M1 - M0           Olahraga - Kontrol            -0.287 0.0882 60  -3.261
##  M2 - M0           Olahraga - Kontrol            -0.600 0.1790 60  -3.348
##  M2 - M1           Olahraga - Kontrol            -0.312 0.1050 60  -2.977
##  M3 - M0           Olahraga - Kontrol            -0.850 0.2560 60  -3.317
##  M3 - M1           Olahraga - Kontrol            -0.562 0.1800 60  -3.126
##  M3 - M2           Olahraga - Kontrol            -0.250 0.0921 60  -2.714
##  M1 - M0           Olahraga - ADF                 0.844 0.0882 60   9.570
##  M2 - M0           Olahraga - ADF                 1.406 0.1790 60   7.847
##  M2 - M1           Olahraga - ADF                 0.562 0.1050 60   5.359
##  M3 - M0           Olahraga - ADF                 2.150 0.2560 60   8.391
##  M3 - M1           Olahraga - ADF                 1.306 0.1800 60   7.259
##  M3 - M2           Olahraga - ADF                 0.744 0.0921 60   8.073
##  M1 - M0           (ADF + Olahraga) - Kontrol    -1.869 0.0882 60 -21.196
##  M2 - M0           (ADF + Olahraga) - Kontrol    -4.194 0.1790 60 -23.401
##  M2 - M1           (ADF + Olahraga) - Kontrol    -2.325 0.1050 60 -22.152
##  M3 - M0           (ADF + Olahraga) - Kontrol    -6.175 0.2560 60 -24.100
##  M3 - M1           (ADF + Olahraga) - Kontrol    -4.306 0.1800 60 -23.932
##  M3 - M2           (ADF + Olahraga) - Kontrol    -1.981 0.0921 60 -21.506
##  M1 - M0           (ADF + Olahraga) - ADF        -0.738 0.0882 60  -8.365
##  M2 - M0           (ADF + Olahraga) - ADF        -2.188 0.1790 60 -12.206
##  M2 - M1           (ADF + Olahraga) - ADF        -1.450 0.1050 60 -13.815
##  M3 - M0           (ADF + Olahraga) - ADF        -3.175 0.2560 60 -12.391
##  M3 - M1           (ADF + Olahraga) - ADF        -2.438 0.1800 60 -13.546
##  M3 - M2           (ADF + Olahraga) - ADF        -0.988 0.0921 60 -10.719
##  M1 - M0           (ADF + Olahraga) - Olahraga   -1.581 0.0882 60 -17.935
##  M2 - M0           (ADF + Olahraga) - Olahraga   -3.594 0.1790 60 -20.053
##  M2 - M1           (ADF + Olahraga) - Olahraga   -2.013 0.1050 60 -19.175
##  M3 - M0           (ADF + Olahraga) - Olahraga   -5.325 0.2560 60 -20.783
##  M3 - M1           (ADF + Olahraga) - Olahraga   -3.744 0.1800 60 -20.806
##  M3 - M2           (ADF + Olahraga) - Olahraga   -1.731 0.0921 60 -18.792
##  p.value
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##   0.0085
##   0.0085
##   0.0085
##   0.0085
##   0.0085
##   0.0087
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
##  <0.0001
## 
## P value adjustment: holm method for 36 tests
# Alternatif: perubahan aktual tiap subjek dari baseline ke Bulan 3
change_data <- dat_wide |>
  mutate(
    perubahan_M3_M0 = BB_Bulan_3_kg - BB_Bulan_0_kg
  )

change_data |>
  group_by(kelompok) |>
  get_summary_stats(
    perubahan_M3_M0,
    type = "mean_sd"
  )
## # A tibble: 4 × 5
##   kelompok       variable            n   mean    sd
##   <fct>          <fct>           <dbl>  <dbl> <dbl>
## 1 Kontrol        perubahan_M3_M0    16 -0.069 0.166
## 2 ADF            perubahan_M3_M0    16 -3.07  0.436
## 3 Olahraga       perubahan_M3_M0    16 -0.919 0.269
## 4 ADF + Olahraga perubahan_M3_M0    16 -6.24  1.35
# Uji beda perubahan M3-M0 antar kelompok
anova_change <- aov(
  perubahan_M3_M0 ~ kelompok,
  data = change_data
)

summary(anova_change)
##             Df Sum Sq Mean Sq F value Pr(>F)    
## kelompok     3  363.6  121.22   230.8 <2e-16 ***
## Residuals   60   31.5    0.53                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Post hoc perubahan antar kelompok
TukeyHSD(anova_change)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = perubahan_M3_M0 ~ kelompok, data = change_data)
## 
## $kelompok
##                           diff       lwr        upr     p adj
## ADF-Kontrol             -3.000 -3.677079 -2.3229211 0.0000000
## Olahraga-Kontrol        -0.850 -1.527079 -0.1729211 0.0082036
## ADF + Olahraga-Kontrol  -6.175 -6.852079 -5.4979211 0.0000000
## Olahraga-ADF             2.150  1.472921  2.8270789 0.0000000
## ADF + Olahraga-ADF      -3.175 -3.852079 -2.4979211 0.0000000
## ADF + Olahraga-Olahraga -5.325 -6.002079 -4.6479211 0.0000000
# Tren linear per kelompok
tren_kelompok <- emmeans(
  aov2,
  ~ waktu | kelompok
)

contrast(
  tren_kelompok,
  "poly"
)
## kelompok = Kontrol:
##  contrast   estimate     SE df t.ratio p.value
##  linear     -0.23125 0.6110 60  -0.378  0.7064
##  quadratic  -0.00625 0.0452 60  -0.138  0.8905
##  cubic       0.00625 0.1000 60   0.062  0.9505
## 
## kelompok = ADF:
##  contrast   estimate     SE df t.ratio p.value
##  linear    -10.10625 0.6110 60 -16.541 <0.0001
##  quadratic   0.13125 0.0452 60   2.903  0.0052
##  cubic      -0.36875 0.1000 60  -3.679  0.0005
## 
## kelompok = Olahraga:
##  contrast   estimate     SE df t.ratio p.value
##  linear     -3.09375 0.6110 60  -5.064 <0.0001
##  quadratic   0.03125 0.0452 60   0.691  0.4921
##  cubic       0.09375 0.1000 60   0.935  0.3533
## 
## kelompok = ADF + Olahraga:
##  contrast   estimate     SE df t.ratio p.value
##  linear    -21.08125 0.6110 60 -34.504 <0.0001
##  quadratic  -0.11875 0.0452 60  -2.626  0.0109
##  cubic       0.80625 0.1000 60   8.045 <0.0001
# 5. PEMBANDING: LINEAR MIXED MODEL (LMM)
# Model dengan random intercept
lmm1 <- lmer(
  bb ~ kelompok * waktu + (1 | id),
  data = dat_long,
  REML = TRUE
)

summary(lmm1)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: bb ~ kelompok * waktu + (1 | id)
##    Data: dat_long
## 
## REML criterion at convergence: 660.1
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -4.0530 -0.2838  0.0157  0.2841  3.8672 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  id       (Intercept) 50.2663  7.090   
##  Residual              0.1049  0.324   
## Number of obs: 256, groups:  id, 64
## 
## Fixed effects:
##                   Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)       92.39922    0.88647  60.00000 104.233  < 2e-16 ***
## kelompok1          1.73047    1.53540  60.00000   1.127    0.264    
## kelompok2          0.87734    1.53540  60.00000   0.571    0.570    
## kelompok3          1.21484    1.53540  60.00000   0.791    0.432    
## waktu1             1.28984    0.03507 180.00000  36.780  < 2e-16 ***
## waktu2             0.44922    0.03507 180.00000  12.809  < 2e-16 ***
## waktu3            -0.45391    0.03507 180.00000 -12.943  < 2e-16 ***
## kelompok1:waktu1  -1.25703    0.06074 180.00000 -20.695  < 2e-16 ***
## kelompok2:waktu1   0.27734    0.06074 180.00000   4.566 9.19e-06 ***
## kelompok3:waktu1  -0.82266    0.06074 180.00000 -13.543  < 2e-16 ***
## kelompok1:waktu2  -0.43516    0.06074 180.00000  -7.164 1.94e-11 ***
## kelompok2:waktu2  -0.03203    0.06074 180.00000  -0.527    0.599    
## kelompok3:waktu2  -0.28828    0.06074 180.00000  -4.746 4.22e-06 ***
## kelompok1:waktu3   0.44297    0.06074 180.00000   7.293 9.31e-12 ***
## kelompok2:waktu3  -0.02891    0.06074 180.00000  -0.476    0.635    
## kelompok3:waktu3   0.27734    0.06074 180.00000   4.566 9.19e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation matrix not shown by default, as p = 16 > 12.
## Use print(x, correlation=TRUE)  or
##     vcov(x)        if you need it
anova(lmm1, 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         0.663   0.221     3    60   2.1053  0.109    
## waktu          238.282  79.427     3   180 756.8253 <2e-16 ***
## kelompok:waktu 207.428  23.048     9   180 219.6091 <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Model dengan random intercept + random slope waktu
lmm2 <- lmer(
  bb ~ kelompok * waktu + (1 + bulan | id),
  data = dat_long,
  REML = TRUE
)

summary(lmm2)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: bb ~ kelompok * waktu + (1 + bulan | id)
##    Data: dat_long
## 
## REML criterion at convergence: 414.7
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.15424 -0.45495  0.02092  0.42375  2.32736 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev. Corr 
##  id       (Intercept) 49.791513 7.05631       
##           bulan        0.058104 0.24105  0.07 
##  Residual              0.008106 0.09004       
## Number of obs: 256, groups:  id, 64
## 
## Fixed effects:
##                   Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)       92.39922    0.88645  60.00291 104.235  < 2e-16 ***
## kelompok1          1.73047    1.53538  60.00301   1.127 0.264202    
## kelompok2          0.87734    1.53538  60.00301   0.571 0.569849    
## kelompok3          1.21484    1.53538  60.00301   0.791 0.431923    
## waktu1             1.28984    0.04624  62.18323  27.897  < 2e-16 ***
## waktu2             0.44922    0.01794 106.57779  25.035  < 2e-16 ***
## waktu3            -0.45391    0.01794 106.57779 -25.297  < 2e-16 ***
## kelompok1:waktu1  -1.25703    0.08008  62.18323 -15.697  < 2e-16 ***
## kelompok2:waktu1   0.27734    0.08008  62.18323   3.463 0.000972 ***
## kelompok3:waktu1  -0.82266    0.08008  62.18323 -10.273 5.05e-15 ***
## kelompok1:waktu2  -0.43516    0.03108 106.57779 -14.002  < 2e-16 ***
## kelompok2:waktu2  -0.03203    0.03108 106.57779  -1.031 0.305041    
## kelompok3:waktu2  -0.28828    0.03108 106.57779  -9.276 2.29e-15 ***
## kelompok1:waktu3   0.44297    0.03108 106.57779  14.253  < 2e-16 ***
## kelompok2:waktu3  -0.02891    0.03108 106.57779  -0.930 0.354424    
## kelompok3:waktu3   0.27734    0.03108 106.57779   8.924 1.42e-14 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation matrix not shown by default, as p = 16 > 12.
## Use print(x, correlation=TRUE)  or
##     vcov(x)        if you need it
# Perbandingan struktur random effect
anova(
  lmm1,
  lmm2,
  refit = FALSE
)
## Data: dat_long
## Models:
## lmm1: bb ~ kelompok * waktu + (1 | id)
## lmm2: bb ~ kelompok * waktu + (1 + bulan | id)
##      npar    AIC    BIC  logLik -2*log(L)  Chisq Df Pr(>Chisq)    
## lmm1   18 696.11 759.92 -330.05    660.11                         
## lmm2   20 454.67 525.58 -207.34    414.67 245.44  2  < 2.2e-16 ***
## ---
## 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       0.0512 0.01707     3  60.00   2.1054  0.109    
## waktu          6.5260 2.17533     3 127.51 266.5624 <2e-16 ***
## kelompok:waktu 6.3177 0.70197     9 148.38  85.8264 <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.998
##   Unadjusted ICC: 0.880
# 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))


# Simulasi 30 nilai hilang (MCAR) untuk latihan LMM
set.seed(1)
dat_miss <- dat_long

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

lmm_miss <- lmer(
  bb ~ kelompok * waktu + (1 + bulan | 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       0.0511 0.01704     3  60.00   2.1112 0.1082    
## waktu          6.1274 2.04246     3 107.46 251.1404 <2e-16 ***
## kelompok:waktu 5.9547 0.66163     9 123.20  81.1580 <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Jumlah subjek yang memiliki setidaknya satu nilai hilang
n_distinct(
  dat_miss$id[is.na(dat_miss$bb)]
)
## [1] 25
# 6. MENYIMPAN DATA & SESSION INFO
write.csv(
  dat_wide,
  "data_obesitas_wide_RStudio.csv",
  row.names = FALSE
)

write.csv(
  dat_long,
  "data_obesitas_long_RStudio.csv",
  row.names = FALSE
)

write.csv(
  desk,
  "deskriptif_berat_badan.csv",
  row.names = FALSE
)

ringkasan_perubahan <- change_data |>
  group_by(kelompok) |>
  summarise(
    n = n(),
    mean_baseline = mean(BB_Bulan_0_kg, na.rm = TRUE),
    mean_bulan3 = mean(BB_Bulan_3_kg, na.rm = TRUE),
    mean_perubahan = mean(perubahan_M3_M0, na.rm = TRUE),
    sd_perubahan = sd(perubahan_M3_M0, na.rm = TRUE),
    .groups = "drop"
  )

ringkasan_perubahan
## # A tibble: 4 × 6
##   kelompok           n mean_baseline mean_bulan3 mean_perubahan sd_perubahan
##   <fct>          <int>         <dbl>       <dbl>          <dbl>        <dbl>
## 1 Kontrol           16          94.2        94.1        -0.0688        0.166
## 2 ADF               16          94.8        91.8        -3.07          0.436
## 3 Olahraga          16          94.1        93.2        -0.919         0.269
## 4 ADF + Olahraga    16          91.7        85.4        -6.24          1.35
write.csv(
  ringkasan_perubahan,
  "ringkasan_perubahan_berat_badan.csv",
  row.names = FALSE
)

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.60           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     WRS2_1.1-7          RColorBrewer_1.1-3 
## [19] S7_0.2.2            lifecycle_1.0.5     compiler_4.6.1     
## [22] farver_2.1.2        stringr_1.6.0       htmltools_0.5.9    
## [25] sass_0.4.10         yaml_2.3.12         Formula_1.2-6      
## [28] ggpubr_1.0.0        pillar_1.11.1       nloptr_2.2.1       
## [31] jquerylib_0.1.4     MASS_7.3-65         cachem_1.1.0       
## [34] reformulas_0.4.4    boot_1.3-32         abind_1.4-8        
## [37] nlme_3.1-169        tidyselect_1.2.1    digest_0.6.39      
## [40] performance_0.18.2  mvtnorm_1.4-2       stringi_1.8.9      
## [43] reshape2_1.4.5      purrr_1.2.2         labeling_0.4.3     
## [46] splines_4.6.1       fastmap_1.2.0       grid_4.6.1         
## [49] cli_3.6.6           magrittr_2.0.5      utf8_1.2.6         
## [52] broom_1.0.13        withr_3.0.3         scales_1.4.0       
## [55] backports_1.5.1     estimability_2.0.0  rmarkdown_2.31     
## [58] ggsignif_0.6.4      evaluate_1.0.5      knitr_1.51         
## [61] parameters_0.29.3   rbibutils_2.4.1     rlang_1.3.0        
## [64] Rcpp_1.1.2          glue_1.8.1          reshape_0.8.10     
## [67] rstudioapi_0.19.0   minqa_1.2.8         jsonlite_2.0.0     
## [70] R6_2.6.1            plyr_1.8.9