# NAMA : DIMAS WISNU WARDHANA
# NIM : 2611018042
# MATA KULIAH : BIOSTATISTIKA INTERMEDIAT
# REPEATED MEASURE ANALYSIS DENGAN R

# Data simulasi berdasarkan:Algheshairy et al(2025).
# Dataset: 3 kelompok (CG, IG, IIG), pengukuran minggu 0, 4, 8, 12.
# Outcome: Systolic Blood Pressure (SBP; mmHg)

# 1. Paket yang diperlukan --------------------------------------------------
packages <- c("tidyverse", "rstatix", "car", "biotools")
not_installed <- packages[!vapply(packages, requireNamespace, logical(1), quietly = TRUE)]
if (length(not_installed) > 0) {
  stop(
    "Paket berikut belum terpasang: ", paste(not_installed, collapse = ", "),
    ". Pasang sekali melalui Console dengan: install.packages(c(",
    paste0('"', not_installed, '"', collapse = ", "), "))."
  )
}

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.3     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(rstatix)
## 
## Attaching package: 'rstatix'
## 
## The following object is masked from 'package:stats':
## 
##     filter
# 2. Impor dan siapkan data -------------------------------------------------
data_path <- file.choose()
raw_data <- readr::read_csv(data_path, show_col_types = FALSE)
names(raw_data) <- trimws(names(raw_data))

# Terima ID maupun id.
if (!"ID" %in% names(raw_data) && "id" %in% names(raw_data)) {
  raw_data <- dplyr::rename(raw_data, ID = id)
}
if (!all(c("ID", "group") %in% names(raw_data))) {
  stop("CSV harus memiliki kolom ID dan group.")
}

# Jika yang dipilih file wide, ubah empat kolom SBP menjadi format long.
wide_sbp <- c("sbp_mmhg_w0", "sbp_mmhg_w4", "sbp_mmhg_w8", "sbp_mmhg_w12")
if (all(c("week", "sbp_mmhg") %in% names(raw_data))) {
  data_long <- raw_data %>%
    dplyr::transmute(
      ID = as.character(ID),
      group = as.character(group),
      week_num = readr::parse_number(as.character(week)),
      sbp_mmhg = as.numeric(sbp_mmhg)
    )
} else if (all(wide_sbp %in% names(raw_data))) {
  data_long <- raw_data %>%
    dplyr::select(ID, group, dplyr::all_of(wide_sbp)) %>%
    dplyr::mutate(ID = as.character(ID), group = as.character(group)) %>%
    tidyr::pivot_longer(
      cols = dplyr::all_of(wide_sbp),
      names_to = "week_name",
      names_pattern = "sbp_mmhg_w([0-9]+)",
      values_to = "sbp_mmhg"
    ) %>%
    dplyr::mutate(
      week_num = as.numeric(week_name),
      sbp_mmhg = as.numeric(sbp_mmhg)
    ) %>%
    dplyr::select(ID, group, week_num, sbp_mmhg)
} else {
  stop("Kolom SBP tidak dikenali. Pilih CSV long atau wide yang disiapkan.")
}

if (anyNA(data_long$week_num)) stop("Kolom week berisi nilai yang tidak dapat dibaca sebagai angka.")
if (anyNA(data_long$sbp_mmhg)) warning("Ada nilai SBP kosong/non-numerik; subjek tidak lengkap tidak masuk RM ANOVA.")

# Urutan level mengikuti kelompok pada dataset dan waktu pengukuran.
group_levels <- c("CG", "IG", "IIG")
observed_groups <- unique(data_long$group)
group_levels <- c(group_levels[group_levels %in% observed_groups],
                  setdiff(observed_groups, group_levels))
week_levels <- sort(unique(data_long$week_num))
data_long <- data_long %>%
  dplyr::mutate(
    ID = factor(ID),
    group = factor(group, levels = group_levels),
    week = factor(week_num, levels = week_levels,
                  labels = paste0("Minggu ", week_levels))
  ) %>%
  dplyr::arrange(ID, week_num)

if (nlevels(data_long$group) < 2 || nlevels(data_long$week) < 2) {
  stop("Analisis mixed ANOVA memerlukan minimal dua kelompok dan dua waktu.")
}

# Cek satu kelompok per subjek dan satu observasi per subjek-waktu.
if (data_long %>% dplyr::distinct(ID, group) %>% dplyr::count(ID) %>% dplyr::filter(n > 1) %>% nrow() > 0) {
  stop("Ada ID yang tercatat pada lebih dari satu kelompok.")
}
duplicates <- data_long %>% dplyr::count(ID, week) %>% dplyr::filter(n > 1)
if (nrow(duplicates) > 0) stop("Ada lebih dari satu baris untuk kombinasi ID dan week.")

# RM ANOVA klasik memerlukan semua waktu tersedia untuk setiap subjek.
complete_ids <- data_long %>%
  dplyr::group_by(ID) %>%
  dplyr::summarise(
    n_week = dplyr::n_distinct(week[!is.na(sbp_mmhg)]),
    n_valid = sum(!is.na(sbp_mmhg)),
    .groups = "drop"
  ) %>%
  dplyr::filter(n_week == nlevels(data_long$week), n_valid == nlevels(data_long$week)) %>%
  dplyr::pull(ID)
excluded_ids <- setdiff(levels(data_long$ID), as.character(complete_ids))
if (length(excluded_ids) > 0) {
  message("Subjek tidak lengkap yang dikeluarkan dari RM ANOVA: ", paste(excluded_ids, collapse = ", "))
  message("Jika banyak data hilang, pertimbangkan linear mixed model (LMM), bukan hanya complete-case RM ANOVA.")
}
analysis_data <- data_long %>%
  dplyr::filter(ID %in% complete_ids) %>%
  droplevels()
if (nrow(analysis_data) == 0) stop("Tidak ada subjek dengan pengukuran lengkap.")

cat("Jumlah subjek lengkap:", dplyr::n_distinct(analysis_data$ID), "\n")
## Jumlah subjek lengkap: 93
print(analysis_data %>% dplyr::count(group, name = "n_peserta"))
## # A tibble: 3 × 2
##   group n_peserta
##   <fct>     <int>
## 1 CG          128
## 2 IG          124
## 3 IIG         120
print(analysis_data %>% dplyr::count(week, name = "n_pengukuran"))
## # A tibble: 4 × 2
##   week      n_pengukuran
##   <fct>            <int>
## 1 Minggu 0            93
## 2 Minggu 4            93
## 3 Minggu 8            93
## 4 Minggu 12           93
# Folder keluaran berada di samping CSV yang dipilih.
results_dir <- file.path(
  dirname(data_path),
  paste0(tools::file_path_sans_ext(basename(data_path)), "_hasil_R")
)
dir.create(results_dir, showWarnings = FALSE, recursive = TRUE)

# 3. Statistik deskriptif ---------------------------------------------------
descriptives <- analysis_data %>%
  dplyr::group_by(group, week) %>%
  dplyr::summarise(
    n = sum(!is.na(sbp_mmhg)),
    mean_sbp = mean(sbp_mmhg, na.rm = TRUE),
    sd_sbp = sd(sbp_mmhg, na.rm = TRUE),
    se_sbp = sd_sbp / sqrt(n),
    .groups = "drop"
  )
print(descriptives)
## # A tibble: 12 × 6
##    group week          n mean_sbp sd_sbp se_sbp
##    <fct> <fct>     <int>    <dbl>  <dbl>  <dbl>
##  1 CG    Minggu 0     32     146.   10.6   1.87
##  2 CG    Minggu 4     32     146.   11.3   2.00
##  3 CG    Minggu 8     32     146.   10.7   1.90
##  4 CG    Minggu 12    32     142.   11.5   2.03
##  5 IG    Minggu 0     31     142.   18.7   3.37
##  6 IG    Minggu 4     31     138.   18.4   3.30
##  7 IG    Minggu 8     31     135.   18.1   3.25
##  8 IG    Minggu 12    31     131.   19.2   3.44
##  9 IIG   Minggu 0     30     147.   17.7   3.24
## 10 IIG   Minggu 4     30     142.   19.3   3.52
## 11 IIG   Minggu 8     30     136.   19.0   3.47
## 12 IIG   Minggu 12    30     131.   18.0   3.29
readr::write_csv(descriptives, file.path(results_dir, "01_deskriptif.csv"))

# 4. Pemeriksaan outlier dan normalitas -----------------------------------
# Flag outlier saja; jangan menghapus nilai tanpa memeriksa sumber/kesalahan data.
outliers <- analysis_data %>%
  dplyr::group_by(group, week) %>%
  rstatix::identify_outliers(sbp_mmhg)
print(outliers)
## # A tibble: 7 × 7
##   group week      ID    week_num sbp_mmhg is.outlier is.extreme
##   <fct> <fct>     <fct>    <dbl>    <dbl> <lgl>      <lgl>     
## 1 IIG   Minggu 0  P035         0    111   TRUE       FALSE     
## 2 IIG   Minggu 0  P045         0    110.  TRUE       FALSE     
## 3 IIG   Minggu 4  P035         4    104.  TRUE       FALSE     
## 4 IIG   Minggu 4  P045         4    103.  TRUE       FALSE     
## 5 IIG   Minggu 8  P035         8     98.6 TRUE       FALSE     
## 6 IIG   Minggu 8  P045         8     99.8 TRUE       FALSE     
## 7 IIG   Minggu 12 P035        12     95.3 TRUE       FALSE
readr::write_csv(outliers, file.path(results_dir, "02_outlier.csv"))

normality <- analysis_data %>%
  dplyr::group_by(group, week) %>%
  rstatix::shapiro_test(sbp_mmhg)
print(normality)
## # A tibble: 12 × 5
##    group week      variable statistic      p
##    <fct> <fct>     <chr>        <dbl>  <dbl>
##  1 CG    Minggu 0  sbp_mmhg     0.987 0.964 
##  2 CG    Minggu 4  sbp_mmhg     0.942 0.0859
##  3 CG    Minggu 8  sbp_mmhg     0.963 0.335 
##  4 CG    Minggu 12 sbp_mmhg     0.975 0.649 
##  5 IG    Minggu 0  sbp_mmhg     0.977 0.739 
##  6 IG    Minggu 4  sbp_mmhg     0.977 0.712 
##  7 IG    Minggu 8  sbp_mmhg     0.979 0.792 
##  8 IG    Minggu 12 sbp_mmhg     0.979 0.777 
##  9 IIG   Minggu 0  sbp_mmhg     0.974 0.639 
## 10 IIG   Minggu 4  sbp_mmhg     0.972 0.605 
## 11 IIG   Minggu 8  sbp_mmhg     0.969 0.509 
## 12 IIG   Minggu 12 sbp_mmhg     0.965 0.403
readr::write_csv(normality, file.path(results_dir, "03_shapiro_per_kelompok_waktu.csv"))

p_box <- ggplot(analysis_data, aes(x = week, y = sbp_mmhg, fill = group)) +
  geom_boxplot(alpha = 0.75, outlier.shape = 21) +
  facet_wrap(~ group) +
  labs(x = "Waktu pengukuran", y = "Tekanan darah sistolik (mmHg)",
       title = "Sebaran tekanan sistolik per kelompok dan waktu") +
  theme_minimal() + theme(legend.position = "none")
ggsave(file.path(results_dir, "01_boxplot.png"), p_box, width = 9, height = 5, dpi = 300)

p_qq <- ggplot(analysis_data, aes(sample = sbp_mmhg)) +
  stat_qq() + stat_qq_line() +
  facet_grid(group ~ week) +
  labs(title = "Q-Q plot tekanan sistolik per kelompok dan waktu") +
  theme_minimal()
ggsave(file.path(results_dir, "02_qqplot.png"), p_qq, width = 10, height = 7, dpi = 300)

# 5. Homogenitas varians dan matriks kovarians -----------------------------
# Levene berbasis median pada setiap waktu, sesuai konsep materi.
levene_results <- analysis_data %>%
  dplyr::group_by(week) %>%
  rstatix::levene_test(sbp_mmhg ~ group, center = median)
print(levene_results)
## # A tibble: 4 × 5
##   week        df1   df2 statistic      p
##   <fct>     <int> <int>     <dbl>  <dbl>
## 1 Minggu 0      2    90      3.80 0.0260
## 2 Minggu 4      2    90      2.98 0.0557
## 3 Minggu 8      2    90      3.40 0.0376
## 4 Minggu 12     2    90      2.71 0.0723
readr::write_csv(levene_results, file.path(results_dir, "04_levene_per_waktu.csv"))

# Box's M pada data wide; gunakan alpha 0,001 karena uji ini sensitif.
box_data <- analysis_data %>%
  dplyr::select(ID, group, week_num, sbp_mmhg) %>%
  tidyr::pivot_wider(names_from = week_num, values_from = sbp_mmhg,
                     names_prefix = "W") %>%
  tidyr::drop_na()
box_vars <- paste0("W", week_levels)
boxm_result <- biotools::boxM(
  data = as.data.frame(box_data %>% dplyr::select(dplyr::all_of(box_vars))),
  grouping = box_data$group
)
print(boxm_result)
## 
##  Box's M-test for Homogeneity of Covariance Matrices
## 
## data:  as.data.frame(box_data %>% dplyr::select(dplyr::all_of(box_vars)))
## Chi-Sq (approx.) = 26.309, df = 20, p-value = 0.1558
boxm_table <- tibble::tibble(
  statistic = unname(boxm_result$statistic),
  df = unname(boxm_result$parameter),
  p_value = boxm_result$p.value,
  alpha = 0.001
)
readr::write_csv(boxm_table, file.path(results_dir, "05_box_m.csv"))

# 6. One-way repeated-measures ANOVA (efek waktu saja) ---------------------
# Analisis ini mengabaikan kelompok; hasilnya pelengkap, bukan model utama.
rm_one_way <- rstatix::anova_test(
  data = analysis_data,
  dv = sbp_mmhg,
  wid = ID,
  within = week,
  type = 3,
  effect.size = "pes",
  ci = 0.95
)
cat("\nHASIL RM ANOVA SATU ARAH: tabel Mauchly dan epsilon disertakan\n")
## 
## HASIL RM ANOVA SATU ARAH: tabel Mauchly dan epsilon disertakan
print(rm_one_way)
## ANOVA Table (type III tests)
## 
## $ANOVA
##   Effect DFn DFd       F        p p<.05  pes conf.low conf.high
## 1   week   3 276 150.162 1.04e-57     * 0.62    0.554     0.673
## 
## $`Mauchly's Test for Sphericity`
##   Effect     W        p p<.05
## 1   week 0.488 1.11e-12     *
## 
## $`Sphericity Corrections`
##   Effect   GGe       DF[GG]    p[GG] p[GG]<.05   HFe       DF[HF]    p[HF]
## 1   week 0.672 2.02, 185.55 1.05e-39         * 0.687 2.06, 189.73 1.55e-40
##   p[HF]<.05
## 1         *
rm_one_way_gg <- rstatix::get_anova_table(rm_one_way, correction = "GG")
print(rm_one_way_gg)
## ANOVA Table (type III tests)
## 
##   Effect  DFn    DFd       F        p p<.05  pes conf.low conf.high
## 1   week 2.02 185.55 150.162 1.05e-39     * 0.62    0.554     0.673
readr::write_csv(rm_one_way_gg, file.path(results_dir, "06_rm_anova_GG.csv"))

# 7. Mixed design ANOVA: kelompok x waktu ----------------------------------
mixed_anova <- rstatix::anova_test(
  data = analysis_data,
  dv = sbp_mmhg,
  wid = ID,
  between = group,
  within = week,
  type = 3,
  effect.size = "pes",
  ci = 0.95
)
cat("\nHASIL MIXED ANOVA: tabel Mauchly dan epsilon GG/HF disertakan\n")
## 
## HASIL MIXED ANOVA: tabel Mauchly dan epsilon GG/HF disertakan
print(mixed_anova)
## ANOVA Table (type III tests)
## 
## $ANOVA
##       Effect DFn DFd       F        p p<.05   pes conf.low conf.high
## 1      group   2  90   2.248 1.11e-01       0.048    0.000     0.146
## 2       week   3 270 323.514 4.60e-89     * 0.782    0.742     0.814
## 3 group:week   6 270  51.477 5.19e-42     * 0.534    0.453     0.594
## 
## $`Mauchly's Test for Sphericity`
##       Effect     W     p p<.05
## 1       week 0.925 0.224      
## 2 group:week 0.925 0.224      
## 
## $`Sphericity Corrections`
##       Effect  GGe      DF[GG]    p[GG] p[GG]<.05   HFe       DF[HF]    p[HF]
## 1       week 0.95 2.85, 256.4 1.00e-84         * 0.984 2.95, 265.66 1.11e-87
## 2 group:week 0.95  5.7, 256.4 5.04e-40         * 0.984  5.9, 265.66 2.24e-41
##   p[HF]<.05
## 1         *
## 2         *
# Tabel auto menerapkan GG untuk faktor within yang melanggar sphericity.
# Lihat epsilon GG pada output di atas: materi konsep menganjurkan GG bila
# epsilon < 0,75 dan HF bila epsilon >= 0,75. Tabel GG dan HF juga disimpan
# agar koreksi yang sesuai dapat dipilih untuk masing-masing efek within.
mixed_auto <- rstatix::get_anova_table(mixed_anova, correction = "auto")
mixed_gg <- rstatix::get_anova_table(mixed_anova, correction = "GG")
mixed_hf <- rstatix::get_anova_table(mixed_anova, correction = "HF")
cat("\nTabel mixed ANOVA dengan koreksi otomatis:\n")
## 
## Tabel mixed ANOVA dengan koreksi otomatis:
print(mixed_auto)
## ANOVA Table (type III tests)
## 
##       Effect DFn DFd       F        p p<.05   pes conf.low conf.high
## 1      group   2  90   2.248 1.11e-01       0.048    0.000     0.146
## 2       week   3 270 323.514 4.60e-89     * 0.782    0.742     0.814
## 3 group:week   6 270  51.477 5.19e-42     * 0.534    0.453     0.594
cat("\nTabel mixed ANOVA Greenhouse-Geisser:\n")
## 
## Tabel mixed ANOVA Greenhouse-Geisser:
print(mixed_gg)
## ANOVA Table (type III tests)
## 
##       Effect  DFn   DFd       F        p p<.05   pes conf.low conf.high
## 1      group 2.00  90.0   2.248 1.11e-01       0.048    0.000     0.146
## 2       week 2.85 256.4 323.514 1.00e-84     * 0.782    0.742     0.814
## 3 group:week 5.70 256.4  51.477 5.04e-40     * 0.534    0.453     0.594
cat("\nTabel mixed ANOVA Huynh-Feldt:\n")
## 
## Tabel mixed ANOVA Huynh-Feldt:
print(mixed_hf)
## ANOVA Table (type III tests)
## 
##       Effect  DFn    DFd       F        p p<.05   pes conf.low conf.high
## 1      group 2.00  90.00   2.248 1.11e-01       0.048    0.000     0.146
## 2       week 2.95 265.66 323.514 1.11e-87     * 0.782    0.742     0.814
## 3 group:week 5.90 265.66  51.477 2.24e-41     * 0.534    0.453     0.594
readr::write_csv(mixed_auto, file.path(results_dir, "07_mixed_anova_auto.csv"))
readr::write_csv(mixed_gg, file.path(results_dir, "08_mixed_anova_GG.csv"))
readr::write_csv(mixed_hf, file.path(results_dir, "09_mixed_anova_HF.csv"))

# Simpan ringkasan penuh termasuk Mauchly dan sphericity corrections.
capture.output(
  {
    cat("ONE-WAY REPEATED-MEASURES ANOVA\n")
    print(rm_one_way)
    cat("\nMIXED DESIGN ANOVA\n")
    print(mixed_anova)
  },
  file = file.path(results_dir, "10_ringkasan_anova.txt")
)

# 8. Uji lanjut / efek sederhana dengan koreksi Holm -----------------------
# Pada interaksi signifikan, fokuskan interpretasi pada dua tabel simple effects:
# (a) beda kelompok pada tiap waktu dan (b) beda waktu di dalam tiap kelompok.
# Bila interaksi tidak signifikan, prioritaskan efek utama; jangan menyimpulkan
# intervensi berbeda hanya dari satu perbandingan simple effect.
posthoc_group_by_week <- analysis_data %>%
  dplyr::group_by(week) %>%
  rstatix::pairwise_t_test(
    sbp_mmhg ~ group,
    p.adjust.method = "holm",
    pool.sd = FALSE
  )
posthoc_week_by_group <- analysis_data %>%
  dplyr::group_by(group) %>%
  rstatix::pairwise_t_test(
    sbp_mmhg ~ week,
    paired = TRUE,
    id = "ID",
    p.adjust.method = "holm"
  )
print(posthoc_group_by_week)
## # A tibble: 12 × 11
##    week      .y.      group1 group2    n1    n2 statistic    df       p   p.adj
##  * <fct>     <chr>    <chr>  <chr>  <int> <int>     <dbl> <dbl>   <dbl>   <dbl>
##  1 Minggu 0  sbp_mmhg CG     IG        32    31    1.03    47.1 0.310   0.673  
##  2 Minggu 0  sbp_mmhg CG     IIG       32    30   -0.477   46.8 0.635   0.673  
##  3 Minggu 0  sbp_mmhg IG     IIG       31    30   -1.23    59.0 0.224   0.673  
##  4 Minggu 4  sbp_mmhg CG     IG        32    31    1.98    49.6 0.0529  0.159  
##  5 Minggu 4  sbp_mmhg CG     IIG       32    30    0.828   46.3 0.412   0.753  
##  6 Minggu 4  sbp_mmhg IG     IIG       31    30   -0.891   58.6 0.376   0.753  
##  7 Minggu 8  sbp_mmhg CG     IG        32    31    3.11    48.4 0.00314 0.00942
##  8 Minggu 8  sbp_mmhg CG     IIG       32    30    2.48    45.2 0.0168  0.0336 
##  9 Minggu 8  sbp_mmhg IG     IIG       31    30   -0.397   58.6 0.693   0.693  
## 10 Minggu 12 sbp_mmhg CG     IG        32    31    2.72    48.8 0.00906 0.0227 
## 11 Minggu 12 sbp_mmhg CG     IIG       32    30    2.79    48.8 0.00758 0.0227 
## 12 Minggu 12 sbp_mmhg IG     IIG       31    30   -0.0209  58.9 0.983   0.983  
## # ℹ 1 more variable: p.adj.signif <chr>
print(posthoc_week_by_group)
## # A tibble: 18 × 11
##    group .y.      group1   group2     n1    n2 statistic    df        p    p.adj
##  * <fct> <chr>    <chr>    <chr>   <int> <int>     <dbl> <dbl>    <dbl>    <dbl>
##  1 CG    sbp_mmhg Minggu 0 Minggu…    32    32    -0.326    31 7.47e- 1 7.47e- 1
##  2 CG    sbp_mmhg Minggu 0 Minggu…    32    32    -1.20     31 2.38e- 1 7.14e- 1
##  3 CG    sbp_mmhg Minggu 0 Minggu…    32    32     6.08     31 9.71e- 7 4.86e- 6
##  4 CG    sbp_mmhg Minggu 4 Minggu…    32    32    -0.936    31 3.56e- 1 7.14e- 1
##  5 CG    sbp_mmhg Minggu 4 Minggu…    32    32     6.05     31 1.05e- 6 4.86e- 6
##  6 CG    sbp_mmhg Minggu 8 Minggu…    32    32     7.20     31 4.30e- 8 2.58e- 7
##  7 IG    sbp_mmhg Minggu 0 Minggu…    31    31     6.26     30 6.74e- 7 1.35e- 6
##  8 IG    sbp_mmhg Minggu 0 Minggu…    31    31    11.3      30 2.22e-12 8.86e-12
##  9 IG    sbp_mmhg Minggu 0 Minggu…    31    31    16.7      30 1.05e-16 6.31e-16
## 10 IG    sbp_mmhg Minggu 4 Minggu…    31    31     6.41     30 4.41e- 7 1.32e- 6
## 11 IG    sbp_mmhg Minggu 4 Minggu…    31    31    12.5      30 1.84e-13 9.21e-13
## 12 IG    sbp_mmhg Minggu 8 Minggu…    31    31     4.71     30 5.28e- 5 5.28e- 5
## 13 IIG   sbp_mmhg Minggu 0 Minggu…    30    30     8.14     29 5.58e- 9 5.58e- 9
## 14 IIG   sbp_mmhg Minggu 0 Minggu…    30    30    20.2      29 1.25e-18 6.27e-18
## 15 IIG   sbp_mmhg Minggu 0 Minggu…    30    30    31.7      29 4.53e-24 2.72e-23
## 16 IIG   sbp_mmhg Minggu 4 Minggu…    30    30    12.8      29 1.85e-13 5.56e-13
## 17 IIG   sbp_mmhg Minggu 4 Minggu…    30    30    16.8      29 1.77e-16 7.08e-16
## 18 IIG   sbp_mmhg Minggu 8 Minggu…    30    30     8.73     29 1.30e- 9 2.61e- 9
## # ℹ 1 more variable: p.adj.signif <chr>
readr::write_csv(posthoc_group_by_week, file.path(results_dir, "11_posthoc_kelompok_pada_waktu.csv"))
readr::write_csv(posthoc_week_by_group, file.path(results_dir, "12_posthoc_waktu_dalam_kelompok.csv"))

# 9. Plot interaksi dengan rerata +/- SE -----------------------------------
p_interaction <- ggplot(
  descriptives,
  aes(x = week, y = mean_sbp, group = group, color = group)
) +
  geom_line(linewidth = 0.9) +
  geom_point(size = 2.5) +
  geom_errorbar(aes(ymin = mean_sbp - se_sbp, ymax = mean_sbp + se_sbp),
                width = 0.12) +
  labs(
    title = "Perubahan tekanan darah sistolik menurut kelompok",
    x = "Waktu pengukuran",
    y = "Rerata tekanan sistolik (mmHg)",
    color = "Kelompok"
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")
print(p_interaction)

ggsave(file.path(results_dir, "03_plot_interaksi.png"),
       p_interaction, width = 8, height = 5, dpi = 300)

cat("\nSelesai. Tabel dan grafik disimpan di:\n", normalizePath(results_dir), "\n")
## 
## Selesai. Tabel dan grafik disimpan di:
##  C:\Users\masdi\OneDrive\Desktop\New Biostat\Data_Biostatistika_Wide_hasil_R