# =============================================================================
#  REPEATED MEASURE ANALYSIS DENGAN R
#
# Nama: Aisyah
# NIM: 2611018038
#
#  Data   : dataset_biostatistika_3perlakuan_3pengukuran.xlsx (sheet Data_Wide)
#  Sumber : Cano-Montoya et al. (2025), J Cardiovasc Dev Dis 12(1):30
#           DOI 10.3390/jcdd12010030
#  Desain : 3 kelompok (Control, HIIT, RT; n = 13 per kelompok) x 3 waktu
#           (baseline, minggu 4, minggu 8); outcome = tekanan darah sistolik (TDS, mmHg)
#
#  CATATAN: nilai baseline (M0) dan minggu 8 (M8) berasal dari data individual
#  artikel (Table 5); nilai minggu 4 (M4) DISIMULASIKAN dari rerata/SD kelompok
#  (Table 2). Tuliskan hal ini dengan jelas di laporan.
#
#  Isi:
#   0. Paket & pengaturan
#   1. Impor data Excel (format lebar -> panjang)
#   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. Analisis sensitivitas hanya data asli (M0 dan M8)
#   7. Menyimpan output
# =============================================================================
# 0. PAKET & PENGATURAN
# Paket yang belum terpasang akan dipasang otomatis (butuh internet saat pertama kali).
paket <- c("readxl", "dplyr", "tidyr", "ggplot2", "afex", "emmeans", "rstatix",
           "car", "effectsize", "lme4", "lmerTest", "pbkrtest", "performance",
           "ggpubr")
baru <- paket[!paket %in% rownames(installed.packages())]
if (length(baru) > 0) install.packages(baru)

suppressPackageStartupMessages({
  library(readxl)      # membaca file Excel
  library(dplyr)       # manipulasi data
  library(tidyr)       # format panjang <-> lebar
  library(ggplot2)     # grafik
  library(afex)        # ANOVA within/mixed (tipe III, koreksi GG/HF, MANOVA)
  library(emmeans)     # rerata marginal, efek sederhana, post hoc, kontras
  library(rstatix)     # uji asumsi yang ramah pipe
  library(car)         # leveneTest, Anova
  library(effectsize)  # eta kuadrat parsial, omega kuadrat
  library(lme4)        # linear mixed model
  library(lmerTest)    # uji F/t dengan derajat bebas Kenward-Roger
})

options(contrasts = c("contr.sum", "contr.poly"))  # kontras jumlah-nol untuk SS tipe III
afex_options(emmeans_model = "multivariate")          # post hoc tahan terhadap non-sfierisitas
theme_set(theme_bw(base_size = 12))
# 1. IMPOR DATA EXCEL
# Letakkan file Excel di working directory (cek dengan getwd(); ubah dengan
# setwd("folder_anda")) atau isi file_data dengan path lengkap, mis.
# "C:/Users/nama/Documents/dataset_biostatistika_3perlakuan_3pengukuran.xlsx"
file_data <- "dataset_biostatistika_3perlakuan_3pengukuran.xlsx"
if (!file.exists(file_data)) {
  stop("File '", file_data, "' tidak ditemukan di: ", getwd(),
       "\nPindahkan file ke folder tersebut atau gunakan setwd().")
}

kel_lab <- c("Control", "HIIT", "RT")
minggu  <- c(0, 4, 8)                          # jarak waktu pengukuran (minggu)
kol_tds <- c("TDS_M0", "TDS_M4", "TDS_M8")     # nama kolom TDS di sheet Data_Wide

dat_wide <- read_excel(file_data, sheet = "Data_Wide") |> as.data.frame()

# Pemeriksaan struktur & data hilang
stopifnot(all(c("id", "kelompok", kol_tds) %in% names(dat_wide)))
print(colSums(is.na(dat_wide[, c("id", "kelompok", kol_tds)])))
##       id kelompok   TDS_M0   TDS_M4   TDS_M8 
##        0        0        0        0        0
dat_wide$kelompok <- factor(dat_wide$kelompok, levels = kel_lab)
stopifnot(!any(is.na(dat_wide$kelompok)))      # berhenti jika ada label kelompok tak cocok
dat_wide$id <- factor(dat_wide$id)
print(table(dat_wide$kelompok))
## 
## Control    HIIT      RT 
##      13      13      13
# Format panjang (satu baris = satu pengukuran), dibutuhkan afex/rstatix/lme4
dat_long <- dat_wide |>
  pivot_longer(all_of(kol_tds), names_to = "waktu", values_to = "tds") |>
  mutate(waktu  = factor(waktu, levels = kol_tds, labels = paste0("M", minggu)),
         minggu = minggu[as.integer(waktu)])

print(head(dat_wide))
##           id kelompok TDS_M0 TDS_M4 TDS_M8
## 1 Control_01  Control    144  135.1    113
## 2 Control_02  Control    148  142.2    123
## 3 Control_03  Control    158  159.2    159
## 4 Control_04  Control    158  163.9    154
## 5 Control_05  Control    152  159.3    143
## 6 Control_06  Control    146  134.9    148
print(head(dat_long))
## # A tibble: 6 × 5
##   id         kelompok waktu   tds minggu
##   <fct>      <fct>    <fct> <dbl>  <dbl>
## 1 Control_01 Control  M0     144       0
## 2 Control_01 Control  M4     135.      4
## 3 Control_01 Control  M8     113       8
## 4 Control_02 Control  M0     148       0
## 5 Control_02 Control  M4     142.      4
## 6 Control_02 Control  M8     123       8
str(dat_long)
## tibble [117 × 5] (S3: tbl_df/tbl/data.frame)
##  $ id      : Factor w/ 39 levels "Control_01","Control_02",..: 1 1 1 2 2 2 3 3 3 4 ...
##  $ kelompok: Factor w/ 3 levels "Control","HIIT",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ waktu   : Factor w/ 3 levels "M0","M4","M8": 1 2 3 1 2 3 1 2 3 1 ...
##  $ tds     : num [1:117] 144 135 113 148 142 ...
##  $ minggu  : num [1:117] 0 4 8 0 4 8 0 4 8 0 ...
# 2. EKSPLORASI DATA
desk <- dat_long |>
  group_by(kelompok, waktu) |>
  get_summary_stats(tds, type = "mean_sd")
print(desk)
## # A tibble: 9 × 6
##   kelompok waktu variable     n  mean    sd
##   <fct>    <fct> <fct>    <dbl> <dbl> <dbl>
## 1 Control  M0    tds         13  137.  17.1
## 2 Control  M4    tds         13  138   16.0
## 3 Control  M8    tds         13  137.  13.8
## 4 HIIT     M0    tds         13  141.  14.4
## 5 HIIT     M4    tds         13  134   17.0
## 6 HIIT     M8    tds         13  129.  15.5
## 7 RT       M0    tds         13  135.  13.0
## 8 RT       M4    tds         13  128   11.0
## 9 RT       M8    tds         13  122.  10.4
# Matriks kovarians & korelasi antarwaktu (seluruh subjek)
S <- cov(dat_wide[, kol_tds])
R <- cor(dat_wide[, kol_tds])
print(round(S, 1)); print(round(R, 2))
##        TDS_M0 TDS_M4 TDS_M8
## TDS_M0  217.8  143.5  103.8
## TDS_M4  143.5  227.8  112.5
## TDS_M8  103.8  112.5  205.6
##        TDS_M0 TDS_M4 TDS_M8
## TDS_M0   1.00   0.64   0.49
## TDS_M4   0.64   1.00   0.52
## TDS_M8   0.49   0.52   1.00
# Varians selisih antarpasangan waktu (inti asumsi sfierisitas)
pasangan <- combn(kol_tds, 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 = " - ")
print(round(var_selisih, 1))
## TDS_M0 - TDS_M4 TDS_M0 - TDS_M8 TDS_M4 - TDS_M8 
##           158.6           215.7           208.5
# Profile plot: rerata +/- 95% CI per kelompok
p_profil <- ggplot(dat_long, aes(minggu, tds, 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 = .4) +
  scale_x_continuous(breaks = minggu) +
  labs(x = "Minggu ke-", y = "Tekanan darah sistolik (mmHg)", colour = "Kelompok",
       title = "Profil rerata TDS (± 95% CI)") +
  theme(legend.position = "bottom")
print(p_profil)

# Spaghetti plot: lintasan tiap peserta
p_spag <- ggplot(dat_long, aes(minggu, tds, 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 = "TDS (mmHg)", title = "Lintasan individu dan rerata kelompok")
print(p_spag)

# 3. REPEATED MEASURE ANOVA SATU ARAH
#    Pertanyaan: apakah TDS berubah selama 8 minggu pada kelompok RT?
#    (ganti "RT" dengan "HIIT" atau "Control" untuk kelompok lain)
d1  <- droplevels(filter(dat_long, kelompok == "RT"))
d1w <- filter(dat_wide, kelompok == "RT")

## 3a. Uji asumsi -------------------------------------------------------------
# (i) Outlier per waktu (ekstrem = di luar Q1-3IQR / Q3+3IQR)
print(d1 |> group_by(waktu) |> identify_outliers(tds))
## # A tibble: 2 × 7
##   waktu id    kelompok   tds minggu is.outlier is.extreme
##   <fct> <fct> <fct>    <dbl>  <dbl> <lgl>      <lgl>     
## 1 M0    RT_01 RT         169      0 TRUE       FALSE     
## 2 M8    RT_11 RT         145      8 TRUE       FALSE
# (ii) Normalitas per waktu (Shapiro-Wilk) dan Q-Q plot
print(d1 |> group_by(waktu) |> shapiro_test(tds))
## # A tibble: 3 × 4
##   waktu variable statistic      p
##   <fct> <chr>        <dbl>  <dbl>
## 1 M0    tds          0.881 0.0731
## 2 M4    tds          0.956 0.687 
## 3 M8    tds          0.965 0.825
print(ggpubr::ggqqplot(d1, "tds", facet.by = "waktu"))

# (iii) Sfierisitas: Mauchly (dilaporkan otomatis oleh anova_test & afex)
aov1_rs <- anova_test(data = d1, dv = tds, wid = id, within = waktu,
                      effect.size = "pes")
print(aov1_rs)                                     # ANOVA, Mauchly, koreksi GG & HF
## ANOVA Table (type III tests)
## 
## $ANOVA
##   Effect DFn DFd     F     p p<.05   pes
## 1  waktu   2  24 5.706 0.009     * 0.322
## 
## $`Mauchly's Test for Sphericity`
##   Effect     W     p p<.05
## 1  waktu 0.821 0.339      
## 
## $`Sphericity Corrections`
##   Effect   GGe     DF[GG] p[GG] p[GG]<.05   HFe      DF[HF] p[HF] p[HF]<.05
## 1  waktu 0.848 1.7, 20.36 0.014         * 0.974 1.95, 23.36  0.01         *
print(get_anova_table(aov1_rs, correction = "auto"))  # GG dipakai jika Mauchly p < .05
## ANOVA Table (type III tests)
## 
##   Effect DFn DFd     F     p p<.05   pes
## 1  waktu   2  24 5.706 0.009     * 0.322
## 3b. ANOVA dengan afex (sumber utama laporan) -------------------------------
aov1 <- aov_ez(id = "id", dv = "tds", data = d1, within = "waktu",
               anova_table = list(es = c("ges", "pes"), correction = "GG"))
print(aov1)
## Anova Table (Type 3 tests)
## 
## Response: tds
##   Effect          df    MSE      F  ges  pes p.value
## 1  waktu 1.70, 20.36 108.61 5.71 * .180 .322    .014
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
## 
## Sphericity correction method: GG
print(summary(aov1))       # univariat tanpa koreksi + Mauchly + epsilon GG & HF
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##             Sum Sq num Df Error SS den Df   F value    Pr(>F)    
## (Intercept) 643849      1   2568.9     12 3007.5831 8.901e-16 ***
## waktu         1052      2   2211.8     24    5.7062   0.00939 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Mauchly Tests for Sphericity
## 
##       Test statistic p-value
## waktu        0.82144 0.33897
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##        GG eps Pr(>F[GG])  
## waktu 0.84849    0.01385 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##          HF eps Pr(>F[HF])
## waktu 0.9735391 0.01004706
# Ukuran efek tambahan
print(eta_squared(aov1, partial = TRUE))
## # Effect Size for ANOVA (Type III)
## 
## Parameter | Eta2 (partial) |       95% CI
## -----------------------------------------
## waktu     |           0.32 | [0.06, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
print(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 (tidak memerlukan sfierisitas) ------------------
print(aov1$Anova)          # Pillai, Wilks, Hotelling-Lawley, Roy
## 
## Type III Repeated Measures MANOVA Tests: Pillai test statistic
##             Df test stat approx F num Df den Df    Pr(>F)    
## (Intercept)  1   0.99603  3007.58      1     12 8.901e-16 ***
## waktu        1   0.41986     3.98      2     11   0.05005 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 3d. Post hoc & kontras tren ------------------------------------------------
em1 <- emmeans(aov1, ~ waktu)
print(em1)
##  waktu emmean   SE df lower.CL upper.CL
##  M0       135 3.61 12      127      143
##  M4       128 3.06 12      121      135
##  M8       122 2.88 12      116      129
## 
## Confidence level used: 0.95
print(pairs(em1, adjust = "bonferroni"))                       # semua pasangan waktu (3)
##  contrast estimate   SE df t.ratio p.value
##  M0 - M4      7.08 3.10 12   2.284  0.1241
##  M0 - M8     12.69 4.45 12   2.851  0.0437
##  M4 - M8      5.62 3.62 12   1.550  0.4413
## 
## P value adjustment: bonferroni method for 3 tests
print(contrast(em1, "trt.vs.ctrl", ref = 1, adjust = "holm"))  # tiap waktu vs baseline
##  contrast estimate   SE df t.ratio p.value
##  M4 - M0     -7.08 3.10 12  -2.284  0.0414
##  M8 - M0    -12.69 4.45 12  -2.851  0.0292
## 
## P value adjustment: holm method for 2 tests
print(contrast(em1, "poly"))                                   # tren linear & kuadratik
##  contrast  estimate   SE df t.ratio p.value
##  linear      -12.69 4.45 12  -2.851  0.0146
##  quadratic     1.46 5.06 12   0.289  0.7777
## 3e. Alternatif nonparametrik ------------------------------------------------
print(friedman_test(d1, tds ~ waktu | id))
## # A tibble: 1 × 6
##   .y.       n statistic    df     p method       
## * <chr> <int>     <dbl> <dbl> <dbl> <chr>        
## 1 tds      13      2.46     2 0.292 Friedman test
print(friedman_effsize(d1, tds ~ waktu | id))                  # Kendall's W
## # A tibble: 1 × 5
##   .y.       n effsize method    magnitude
## * <chr> <int>   <dbl> <chr>     <ord>    
## 1 tds      13  0.0947 Kendall W small
print(d1 |> wilcox_test(tds ~ waktu, paired = TRUE, p.adjust.method = "bonferroni"))
## # A tibble: 3 × 9
##   .y.   group1 group2    n1    n2 statistic      p  p.adj p.adj.signif
## * <chr> <chr>  <chr>  <int> <int>     <dbl>  <dbl>  <dbl> <chr>       
## 1 tds   M0     M4        13    13        73 0.0574 0.172  ns          
## 2 tds   M0     M8        13    13        78 0.0215 0.0645 ns          
## 3 tds   M4     M8        13    13        66 0.168  0.503  ns
# (Opsional) ANOVA robust berbasis trimmed mean -- paket WRS2
if (requireNamespace("WRS2", quietly = TRUE)) {
  print(WRS2::rmanova(d1$tds, d1$waktu, d1$id, tr = 0.2))
}
## Call:
## WRS2::rmanova(y = d1$tds, groups = d1$waktu, blocks = d1$id, 
##     tr = 0.2)
## 
## Test statistic: F = 6.8734 
## Degrees of freedom 1: 2 
## Degrees of freedom 2: 16 
## p-value: 0.00701
# 4. MIXED DESIGN ANOVA  (Kelompok [between] x Waktu [within])
#    Pertanyaan: apakah pola perubahan TDS berbeda antarkelompok?
## 4a. Uji asumsi -------------------------------------------------------------
# (i) Outlier per sel
print(dat_long |> group_by(kelompok, waktu) |> identify_outliers(tds))
## # A tibble: 8 × 7
##   kelompok waktu id           tds minggu is.outlier is.extreme
##   <fct>    <fct> <fct>      <dbl>  <dbl> <lgl>      <lgl>     
## 1 Control  M4    Control_03  159.      4 TRUE       FALSE     
## 2 Control  M4    Control_04  164.      4 TRUE       FALSE     
## 3 Control  M4    Control_05  159.      4 TRUE       FALSE     
## 4 Control  M4    Control_10  108.      4 TRUE       FALSE     
## 5 HIIT     M8    HIIT_08     167       8 TRUE       TRUE      
## 6 HIIT     M8    HIIT_13     102       8 TRUE       FALSE     
## 7 RT       M0    RT_01       169       0 TRUE       FALSE     
## 8 RT       M8    RT_11       145       8 TRUE       FALSE
# (ii) Normalitas per sel (3 x 3 = 9 sel) dan Q-Q plot
print(dat_long |> group_by(kelompok, waktu) |> shapiro_test(tds))
## # A tibble: 9 × 5
##   kelompok waktu variable statistic      p
##   <fct>    <fct> <chr>        <dbl>  <dbl>
## 1 Control  M0    tds          0.948 0.562 
## 2 Control  M4    tds          0.954 0.656 
## 3 Control  M8    tds          0.965 0.825 
## 4 HIIT     M0    tds          0.975 0.944 
## 5 HIIT     M4    tds          0.973 0.927 
## 6 HIIT     M8    tds          0.918 0.233 
## 7 RT       M0    tds          0.881 0.0731
## 8 RT       M4    tds          0.956 0.687 
## 9 RT       M8    tds          0.965 0.825
print(ggpubr::ggqqplot(dat_long, "tds", ggtheme = theme_bw()) +
        facet_grid(waktu ~ kelompok))

# (iii) Homogenitas varians antarkelompok pada TIAP waktu (Levene)
print(dat_long |> group_by(waktu) |> levene_test(tds ~ kelompok))
## # A tibble: 3 × 5
##   waktu   df1   df2 statistic     p
##   <fct> <int> <int>     <dbl> <dbl>
## 1 M0        2    36     0.772 0.469
## 2 M4        2    36     0.873 0.426
## 3 M8        2    36     0.759 0.476
# (iv) Homogenitas matriks kovarians antarkelompok (Box's M; uji pada alpha = .001)
print(box_m(dat_wide[, kol_tds], dat_wide$kelompok))
## # A tibble: 1 × 4
##   statistic p.value parameter method                                            
##       <dbl>   <dbl>     <dbl> <chr>                                             
## 1      9.15   0.690        12 Box's M-test for Homogeneity of Covariance Matric…
# (v) Sfierisitas: Mauchly (dari summary model di bawah)

## 4b. ANOVA campuran ---------------------------------------------------------
aov2 <- aov_ez(id = "id", dv = "tds", data = dat_long,
               between = "kelompok", within = "waktu",
               anova_table = list(es = c("ges", "pes"), correction = "GG"))
print(aov2)
## Anova Table (Type 3 tests)
## 
## Response: tds
##           Effect          df    MSE       F  ges  pes p.value
## 1       kelompok       2, 36 439.53    1.75 .064 .089    .188
## 2          waktu 1.92, 69.11  96.36 7.41 ** .057 .171    .001
## 3 kelompok:waktu 3.84, 69.11  96.36    1.95 .031 .098    .114
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
## 
## Sphericity correction method: GG
print(summary(aov2))       # Mauchly, epsilon GG/HF, p terkoreksi
## Warning in summary.Anova.mlm(object$Anova, multivariate = FALSE): HF eps > 1
## treated as 1
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                 Sum Sq num Df Error SS den Df   F value    Pr(>F)    
## (Intercept)    2081867      1  15823.2     36 4736.5538 < 2.2e-16 ***
## kelompok          1541      2  15823.2     36    1.7535  0.187641    
## waktu             1371      2   6659.6     72    7.4118  0.001183 ** 
## kelompok:waktu     722      4   6659.6     72    1.9520  0.111083    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Mauchly Tests for Sphericity
## 
##                Test statistic p-value
## waktu                 0.95821 0.47378
## kelompok:waktu        0.95821 0.47378
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##                 GG eps Pr(>F[GG])   
## waktu          0.95989   0.001401 **
## kelompok:waktu 0.95989   0.114221   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##                  HF eps Pr(>F[HF])
## waktu          1.012783  0.0011831
## kelompok:waktu 1.012783  0.1110832
print(aov2$Anova)          # uji multivariat untuk efek within & interaksi
## 
## Type III Repeated Measures MANOVA Tests: Pillai test statistic
##                Df test stat approx F num Df den Df  Pr(>F)    
## (Intercept)     1   0.99246   4736.6      1     36 < 2e-16 ***
## kelompok        2   0.08877      1.8      2     36 0.18764    
## waktu           1   0.29714      7.4      2     35 0.00209 ** 
## kelompok:waktu  2   0.19248      1.9      4     72 0.11687    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Versi rstatix (hasil identik; format ringkas untuk laporan)
aov2_rs <- anova_test(data = dat_long, dv = tds, wid = id,
                      between = kelompok, within = waktu, effect.size = "pes",
                      type = 3)
print(get_anova_table(aov2_rs, correction = "GG"))
## ANOVA Table (type III tests)
## 
##           Effect  DFn   DFd     F     p p<.05   pes
## 1       kelompok 2.00 36.00 1.753 0.188       0.089
## 2          waktu 1.92 69.11 7.412 0.001     * 0.171
## 3 kelompok:waktu 3.84 69.11 1.952 0.114       0.098
# Ukuran efek
print(eta_squared(aov2, partial = TRUE))
## # Effect Size for ANOVA (Type III)
## 
## Parameter      | Eta2 (partial) |       95% CI
## ----------------------------------------------
## kelompok       |           0.09 | [0.00, 1.00]
## waktu          |           0.17 | [0.05, 1.00]
## kelompok:waktu |           0.10 | [0.00, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
print(omega_squared(aov2, partial = TRUE))
## # Effect Size for ANOVA (Type III)
## 
## Parameter      | Omega2 (partial) |       95% CI
## ------------------------------------------------
## kelompok       |             0.04 | [0.00, 1.00]
## waktu          |             0.05 | [0.00, 1.00]
## kelompok:waktu |             0.01 | [0.00, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
# Plot interaksi dari model
print(afex_plot(aov2, x = "waktu", trace = "kelompok", error = "within",
                mapping = c("colour", "shape", "linetype")) +
        labs(y = "TDS (mmHg)", 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 (bila interaksi signifikan) -----------------------------
em2 <- emmeans(aov2, ~ waktu | kelompok)

# Efek WAKTU di dalam tiap kelompok (uji F gabungan per kelompok)
print(joint_tests(aov2, by = "kelompok"))
## kelompok = Control:
##  model term df1 df2 F.ratio p.value
##  waktu        2  36   0.082  0.9211
## 
## kelompok = HIIT:
##  model term df1 df2 F.ratio p.value
##  waktu        2  36   5.850  0.0063
## 
## kelompok = RT:
##  model term df1 df2 F.ratio p.value
##  waktu        2  36   5.968  0.0058
# Efek KELOMPOK pada tiap waktu
print(joint_tests(aov2, by = "waktu"))
## waktu = M0:
##  model term df1 df2 F.ratio p.value
##  kelompok     2  36   0.562  0.5749
## 
## waktu = M4:
##  model term df1 df2 F.ratio p.value
##  kelompok     2  36   1.482  0.2407
## 
## waktu = M8:
##  model term df1 df2 F.ratio p.value
##  kelompok     2  36   3.774  0.0325
# Post hoc: tiap waktu vs baseline di dalam tiap kelompok
print(contrast(em2, "trt.vs.ctrl", ref = 1, adjust = "holm"))
## kelompok = Control:
##  contrast estimate   SE df t.ratio p.value
##  M4 - M0    1.3077 3.40 36   0.384  1.0000
##  M8 - M0    0.0769 3.81 36   0.020  1.0000
## 
## kelompok = HIIT:
##  contrast estimate   SE df t.ratio p.value
##  M4 - M0   -7.0769 3.40 36  -2.080  0.0447
##  M8 - M0  -12.5385 3.81 36  -3.289  0.0045
## 
## kelompok = RT:
##  contrast estimate   SE df t.ratio p.value
##  M4 - M0   -7.0769 3.40 36  -2.080  0.0447
##  M8 - M0  -12.6923 3.81 36  -3.330  0.0040
## 
## P value adjustment: holm method for 2 tests
# Post hoc: perbandingan antarkelompok pada tiap waktu
em2b <- emmeans(aov2, ~ kelompok | waktu)
print(pairs(em2b, adjust = "tukey"))
## waktu = M0:
##  contrast       estimate   SE df t.ratio p.value
##  Control - HIIT    -4.38 5.86 36  -0.749  0.7363
##  Control - RT       1.62 5.86 36   0.276  0.9590
##  HIIT - RT          6.00 5.86 36   1.025  0.5664
## 
## waktu = M4:
##  contrast       estimate   SE df t.ratio p.value
##  Control - HIIT     4.00 5.85 36   0.684  0.7742
##  Control - RT      10.00 5.85 36   1.710  0.2152
##  HIIT - RT          6.00 5.85 36   1.026  0.5654
## 
## waktu = M8:
##  contrast       estimate   SE df t.ratio p.value
##  Control - HIIT     8.23 5.25 36   1.567  0.2729
##  Control - RT      14.38 5.25 36   2.738  0.0253
##  HIIT - RT          6.15 5.25 36   1.171  0.4776
## 
## P value adjustment: tukey method for comparing a family of 3 estimates
## 4d. Kontras interaksi -------------------------------------------------------
# Apakah penurunan (M8 - M0) berbeda antarkelompok?
em_full <- emmeans(aov2, ~ waktu * kelompok)
print(contrast(em_full, interaction = list(waktu = list("M8-M0" = c(-1, 0, 1)),
                                           kelompok = "pairwise"),
               adjust = "holm"))
##  waktu_custom kelompok_pairwise estimate   SE df t.ratio p.value
##  M8-M0        Control - HIIT      12.615 5.39 36   2.340  0.0700
##  M8-M0        Control - RT        12.769 5.39 36   2.369  0.0700
##  M8-M0        HIIT - RT            0.154 5.39 36   0.029  0.9774
## 
## P value adjustment: holm method for 3 tests
# Tren linear per kelompok (dengan 3 waktu: baris linear = 1, 3, 5) dan perbandingannya
print(contrast(em2, "poly")[c(1, 3, 5)])
##  contrast kelompok estimate   SE df t.ratio p.value
##  linear   Control    0.0769 3.81 36   0.020  0.9840
##  linear   HIIT     -12.5385 3.81 36  -3.289  0.0023
##  linear   RT       -12.6923 3.81 36  -3.330  0.0020
tren_int <- summary(contrast(em_full, interaction = c(waktu = "poly", kelompok = "pairwise"),
                             adjust = "none"))
tren_lin <- subset(tren_int, waktu_poly == "linear")   # apakah laju perubahan linear berbeda?
tren_lin$p.holm <- p.adjust(tren_lin$p.value, "holm")  # koreksi Holm untuk 3 perbandingan
print(tren_lin)
##   waktu_poly kelompok_pairwise   estimate       SE df    t.ratio    p.value
## 1     linear    Control - HIIT 12.6153846 5.391083 36 2.34004653 0.02494305
## 3     linear      Control - RT 12.7692308 5.391083 36 2.36858368 0.02334418
## 5     linear         HIIT - RT  0.1538462 5.391083 36 0.02853715 0.97739135
##       p.holm
## 1 0.07003253
## 3 0.07003253
## 5 0.97739135
# 5. PEMBANDING: LINEAR MIXED MODEL (LMM)
#    Tidak mensyaratkan sfierisitas dan menampung data hilang (MAR).
#    Dengan hanya 3 pengukuran per peserta, model intersep acak (lmm1) lebih
#    stabil; model slope acak (lmm2) dapat menghasilkan peringatan singular fit.
lmm1 <- lmer(tds ~ kelompok * waktu + (1 | id), data = dat_long, REML = TRUE)
print(anova(lmm1, ddf = "Kenward-Roger"))      # uji F tipe III efek tetap
## Type III Analysis of Variance Table with Kenward-Roger's method
##                 Sum Sq Mean Sq NumDF DenDF F value   Pr(>F)   
## kelompok        324.37  162.19     2    36  1.7535 0.187641   
## waktu          1371.09  685.55     2    72  7.4118 0.001183 **
## kelompok:waktu  722.19  180.55     4    72  1.9520 0.111083   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
print(summary(lmm1))
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: tds ~ kelompok * waktu + (1 | id)
##    Data: dat_long
## 
## REML criterion at convergence: 887.8
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.63822 -0.49859  0.04162  0.47457  1.90342 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  id       (Intercept) 115.68   10.755  
##  Residual              92.49    9.617  
## Number of obs: 117, groups:  id, 39
## 
## Fixed effects:
##                   Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)      133.39316    1.93822  36.00000  68.823  < 2e-16 ***
## kelompok1          3.76068    2.74105  36.00000   1.372  0.17856    
## kelompok2          1.14530    2.74105  36.00000   0.418  0.67855    
## waktu1             4.22222    1.25742  72.00000   3.358  0.00126 ** 
## waktu2            -0.05983    1.25742  72.00000  -0.048  0.96218    
## kelompok1:waktu1  -4.68376    1.77826  72.00000  -2.634  0.01033 *  
## kelompok2:waktu1   2.31624    1.77826  72.00000   1.303  0.19689    
## kelompok1:waktu2   0.90598    1.77826  72.00000   0.509  0.61198    
## kelompok2:waktu2  -0.47863    1.77826  72.00000  -0.269  0.78858    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) klmpk1 klmpk2 waktu1 waktu2 klm1:1 klm2:1 klm1:2
## kelompok1    0.000                                                 
## kelompok2    0.000 -0.500                                          
## waktu1       0.000  0.000  0.000                                   
## waktu2       0.000  0.000  0.000 -0.500                            
## klmpk1:wkt1  0.000  0.000  0.000  0.000  0.000                     
## klmpk2:wkt1  0.000  0.000  0.000  0.000  0.000 -0.500              
## klmpk1:wkt2  0.000  0.000  0.000  0.000  0.000 -0.500  0.250       
## klmpk2:wkt2  0.000  0.000  0.000  0.000  0.000  0.250 -0.500 -0.500
print(performance::icc(lmm1))                  # korelasi intrakelas
## # Intraclass Correlation Coefficient
## 
##     Adjusted ICC: 0.556
##   Unadjusted ICC: 0.483
lmm2 <- lmer(tds ~ kelompok * waktu + (1 + minggu | id), data = dat_long, REML = TRUE,
             control = lmerControl(optimizer = "bobyqa"))
## boundary (singular) fit: see help('isSingular')
print(anova(lmm1, lmm2, refit = FALSE))        # uji rasio kemungkinan struktur acak
## Data: dat_long
## Models:
## lmm1: tds ~ kelompok * waktu + (1 | id)
## lmm2: tds ~ kelompok * waktu + (1 + minggu | id)
##      npar    AIC    BIC  logLik -2*log(L) Chisq Df Pr(>Chisq)
## lmm1   11 909.80 940.18 -443.90    887.80                    
## lmm2   13 912.37 948.28 -443.19    886.37 1.426  2     0.4902
# Diagnostik residual LMM (normalitas & homogenitas)
par(mfrow = c(1, 2))
qqnorm(resid(lmm1), main = "Q-Q residual"); qqline(resid(lmm1))
plot(fitted(lmm1), resid(lmm1), xlab = "Nilai prediksi", ylab = "Residual",
     main = "Residual vs prediksi"); abline(h = 0, lty = 2)

par(mfrow = c(1, 1))
# 6. ANALISIS SENSITIVITAS: HANYA DATA ASLI ARTIKEL (M0 DAN M8)
#    Karena M4 disimulasikan, hasil utama sebaiknya didukung analisis tanpa M4.
dat_asli <- dat_long |> filter(waktu %in% c("M0", "M8")) |> droplevels()

aov3 <- aov_ez(id = "id", dv = "tds", data = dat_asli,
               between = "kelompok", within = "waktu",
               anova_table = list(es = c("ges", "pes")))
print(aov3)                                                    # mixed ANOVA 3 x 2
## Anova Table (Type 3 tests)
## 
## Response: tds
##           Effect    df    MSE         F  ges  pes p.value
## 1       kelompok 2, 36 307.85      1.47 .059 .076    .243
## 2          waktu 1, 36  94.46 14.51 *** .086 .287   <.001
## 3 kelompok:waktu 2, 36  94.46    3.70 * .046 .170    .035
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
print(contrast(emmeans(aov3, ~ waktu | kelompok), "revpairwise", adjust = "holm"))
## kelompok = Control:
##  contrast estimate   SE df t.ratio p.value
##  M8 - M0    0.0769 3.81 36   0.020  0.9840
## 
## kelompok = HIIT:
##  contrast estimate   SE df t.ratio p.value
##  M8 - M0  -12.5385 3.81 36  -3.289  0.0023
## 
## kelompok = RT:
##  contrast estimate   SE df t.ratio p.value
##  M8 - M0  -12.6923 3.81 36  -3.330  0.0020
# ANCOVA: TDS minggu 8 dengan baseline sebagai kovariat
m_ancova <- lm(TDS_M8 ~ TDS_M0 + kelompok, data = dat_wide)
print(car::Anova(m_ancova, type = 3))
## Anova Table (Type III tests)
## 
## Response: TDS_M8
##             Sum Sq Df F value    Pr(>F)    
## (Intercept) 1682.7  1 12.7477 0.0010597 ** 
## TDS_M0      1838.7  1 13.9293 0.0006723 ***
## kelompok    1311.8  2  4.9691 0.0126010 *  
## Residuals   4620.0 35                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
print(pairs(emmeans(m_ancova, ~ kelompok), adjust = "tukey"))
##  contrast       estimate   SE df t.ratio p.value
##  Control - HIIT    10.33 4.54 35   2.275  0.0728
##  Control - RT      13.61 4.51 35   3.017  0.0128
##  HIIT - RT          3.28 4.57 35   0.718  0.7546
## 
## P value adjustment: tukey method for comparing a family of 3 estimates
# 7. SIMPAN OUTPUT & SESSION INFO
write.csv(desk, "Ringkasan_Deskriptif_TDS.csv", row.names = FALSE)
write.csv(dat_long, "data_tds_long.csv", row.names = FALSE)
ggsave("Profil_TDS.png", p_profil, width = 7, height = 4.5, dpi = 300)
ggsave("Spaghetti_TDS.png", p_spag, width = 9, height = 4.5, dpi = 300)
message("Selesai. Output disimpan di: ", getwd())
## Selesai. Output disimpan di: C:/Users/dianw/Downloads
print(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_United States.utf8 
## [2] LC_CTYPE=English_United States.utf8   
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.utf8    
## 
## time zone: Asia/Singapore
## 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     
## [13] readxl_1.5.0    
## 
## loaded via a namespace (and not attached):
##  [1] tidyselect_1.2.1    farver_2.1.2        S7_0.2.2           
##  [4] fastmap_1.2.0       reshape_0.8.10      bayestestR_0.19.0  
##  [7] digest_0.6.39       rpart_4.1.27        estimability_2.0.0 
## [10] lifecycle_1.0.5     cluster_2.1.8.2     magrittr_2.0.5     
## [13] compiler_4.6.1      rlang_1.3.0         Hmisc_5.3-0        
## [16] sass_0.4.10         tools_4.6.1         utf8_1.2.6         
## [19] yaml_2.3.12         data.table_1.18.6.1 ggsignif_0.6.4     
## [22] knitr_1.51          labeling_0.4.3      htmlwidgets_1.6.4  
## [25] plyr_1.8.9          RColorBrewer_1.1-3  abind_1.4-8        
## [28] withr_3.0.3         foreign_0.8-91      purrr_1.2.2        
## [31] numDeriv_2016.8-1.1 nnet_7.3-20         grid_4.6.1         
## [34] datawizard_1.4.0    ggpubr_1.0.0        colorspace_2.1-3   
## [37] scales_1.4.0        MASS_7.3-65         insight_1.5.4      
## [40] cli_3.6.6           mvtnorm_1.4-2       rmarkdown_2.31     
## [43] reformulas_0.4.4    generics_0.1.4      performance_0.18.2 
## [46] rstudioapi_0.19.0   reshape2_1.4.5      parameters_0.29.3  
## [49] minqa_1.2.8         cachem_1.1.0        stringr_1.6.0      
## [52] splines_4.6.1       parallel_4.6.1      WRS2_1.1-7         
## [55] cellranger_1.1.0    base64enc_0.1-6     vctrs_0.7.3        
## [58] boot_1.3-32         jsonlite_2.0.0      pbkrtest_0.5.5     
## [61] Formula_1.2-6       htmlTable_2.5.0     jquerylib_0.1.4    
## [64] glue_1.8.1          nloptr_2.2.1        stringi_1.8.9      
## [67] gtable_0.3.6        tibble_3.3.1        pillar_1.11.1      
## [70] htmltools_0.5.9     R6_2.6.1            Rdpack_2.6.6       
## [73] evaluate_1.0.5      lattice_0.22-9      rbibutils_2.4.1    
## [76] backports_1.5.1     broom_1.0.13        bslib_0.12.0       
## [79] Rcpp_1.1.2          gridExtra_2.3.1     nlme_3.1-169       
## [82] checkmate_2.3.4     xfun_0.60           pkgconfig_2.0.3