# NAMA : SILVIA ANDRYANI
# NIM : 261108045
# TUGAS : BIOSTATIK INTERMEDIATE 5
# DOSEN : Dr. M. FATHURAHMAN, S.Si., M.Si.
# =============================================================================
# REPEATED MEASURE ANALYSIS DENGAN R
# Contoh terapan: eksperimen diabetes, gula darah puasa (GDP)
# Data menggunakan format long dari file CSV
#
# Isi:
# 0. Paket & pengaturan
# 1. Membaca data CSV dan menyiapkan format panjang & lebar
# 2. Eksplorasi data: statistik deskriptif, profile plot, spaghetti plot
# 3. Repeated Measure ANOVA satu arah (within-subject: Waktu)
# 3a. Uji asumsi: outlier, normalitas, sfierisitas (Mauchly)
# 3b. ANOVA + koreksi Greenhouse-Geisser / Huynh-Feldt
# 3c. Pendekatan multivariat (MANOVA) sebagai pembanding
# 3d. Post hoc berpasangan & kontras polinomial (tren)
# 3e. Alternatif nonparametrik: uji Friedman
# 4. Mixed Design ANOVA (between: Kelompok x within: Waktu)
# 4a. Uji asumsi: outlier, normalitas, Levene, Box's M, Mauchly
# 4b. ANOVA campuran + ukuran efek
# 4c. Analisis efek sederhana (simple effects) & post hoc
# 4d. Kontras interaksi (perubahan dari baseline antarkelompok)
# 5. Pembanding: Linear Mixed Model (LMM)
# 6. Menyimpan data & ringkasan hasil
# =============================================================================
# 0. PAKET & PENGATURAN
# Jalankan sekali bila paket belum terpasang:
# install.packages(c("tidyverse", "afex", "emmeans", "rstatix", "car",
# "effectsize", "lme4", "lmerTest", "performance",
# "ggpubr", "Hmisc"))
suppressPackageStartupMessages({
library(dplyr) # manipulasi data
library(tidyr) # format panjang <-> lebar
library(ggplot2) # grafik
library(afex) # ANOVA within/mixed, koreksi GG/HF, MANOVA
library(emmeans) # rerata marginal, simple effects, post hoc, kontras
library(rstatix) # uji asumsi: outlier, Shapiro, Levene, Box's M
library(car) # leveneTest, Anova
library(effectsize) # eta kuadrat parsial, omega kuadrat
library(lme4) # linear mixed model
library(lmerTest) # uji F/t dengan Satterthwaite / Kenward-Roger
library(performance) # diagnostik model
library(ggpubr) # Q-Q plot
})
options(contrasts = c("contr.sum", "contr.poly"))
afex_options(emmeans_model = "multivariate")
theme_set(theme_bw(base_size = 12))
# 1. MEMBACA DATA CSV DAN MENYIAPKAN DATA
# Data sudah tersedia, sehingga bagian simulasi pada contoh diganti menjadi
# membaca file CSV. Struktur data:
# - id : identitas subjek
# - kelompok : kelompok perlakuan
# - usia : usia subjek
# - jk : jenis kelamin
# - waktu : M0, M4, M8, M12
# - gdp : gula darah puasa
# - minggu : 0, 4, 8, 12
file_csv <- "D:/Documents/S2 KESMAS UNMUL/MATERI S2 KESMAS/BIOSTATISTIK/BIOSTATIK 5/MATERI DAN TUGAS BIOSTATISTIK 5/DATA BUATAN/data_sintetis_diabetes_gdp_long_60_format_contoh.csv"
dat_long <- read.csv(file_csv, stringsAsFactors = FALSE)
dat_long <- dat_long |>
mutate(
id = factor(id),
kelompok = factor(kelompok,
levels = c("Standar",
"Standar_Diet",
"Standar_Diet_Aktivitas")),
usia = as.numeric(usia),
jk = factor(jk, levels = c("L", "P")),
waktu = factor(waktu, levels = c("M0", "M4", "M8", "M12")),
gdp = as.numeric(gdp),
minggu = as.numeric(minggu)
) |>
arrange(kelompok, id, minggu)
head(dat_long)
## id kelompok usia jk waktu gdp minggu
## 1 D001 Standar 48 L M0 168.9 0
## 2 D001 Standar 48 L M4 163.6 4
## 3 D001 Standar 48 L M8 159.8 8
## 4 D001 Standar 48 L M12 147.3 12
## 5 D002 Standar 43 P M0 154.2 0
## 6 D002 Standar 43 P M4 143.3 4
str(dat_long)
## 'data.frame': 240 obs. of 7 variables:
## $ id : Factor w/ 60 levels "D001","D002",..: 1 1 1 1 2 2 2 2 3 3 ...
## $ kelompok: Factor w/ 3 levels "Standar","Standar_Diet",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ usia : num 48 48 48 48 43 43 43 43 55 55 ...
## $ jk : Factor w/ 2 levels "L","P": 1 1 1 1 2 2 2 2 1 1 ...
## $ waktu : Factor w/ 4 levels "M0","M4","M8",..: 1 2 3 4 1 2 3 4 1 2 ...
## $ gdp : num 169 164 160 147 154 ...
## $ minggu : num 0 4 8 12 0 4 8 12 0 4 ...
# Cek kelengkapan data
nrow(dat_long)
## [1] 240
n_distinct(dat_long$id)
## [1] 60
table(dat_long$kelompok)
##
## Standar Standar_Diet Standar_Diet_Aktivitas
## 80 80 80
table(dat_long$waktu)
##
## M0 M4 M8 M12
## 60 60 60 60
table(dat_long$kelompok, dat_long$waktu)
##
## M0 M4 M8 M12
## Standar 20 20 20 20
## Standar_Diet 20 20 20 20
## Standar_Diet_Aktivitas 20 20 20 20
colSums(is.na(dat_long))
## id kelompok usia jk waktu gdp minggu
## 0 0 0 0 0 0 0
# Cek apakah setiap subjek punya 4 kali pengukuran
dat_long |>
count(id, name = "jumlah_pengukuran") |>
count(jumlah_pengukuran)
## jumlah_pengukuran n
## 1 4 60
# Format lebar (satu baris = satu subjek)
dat_wide <- dat_long |>
pivot_wider(
id_cols = c(id, kelompok, usia, jk),
names_from = waktu,
values_from = gdp,
names_prefix = "GDP_"
) |>
arrange(kelompok, id)
head(dat_wide)
## # A tibble: 6 × 8
## id kelompok usia jk GDP_M0 GDP_M4 GDP_M8 GDP_M12
## <fct> <fct> <dbl> <fct> <dbl> <dbl> <dbl> <dbl>
## 1 D001 Standar 48 L 169. 164. 160. 147.
## 2 D002 Standar 43 P 154. 143. 128. 118.
## 3 D003 Standar 55 L 135. 136. 129. 133.
## 4 D004 Standar 47 L 203. 190. 197. 190.
## 5 D005 Standar 44 L 169. 165. 169. 164
## 6 D006 Standar 56 L 150. 138. 134. 122.
str(dat_wide)
## tibble [60 × 8] (S3: tbl_df/tbl/data.frame)
## $ id : Factor w/ 60 levels "D001","D002",..: 1 2 3 4 5 6 7 8 9 10 ...
## $ kelompok: Factor w/ 3 levels "Standar","Standar_Diet",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ usia : num [1:60] 48 43 55 47 44 56 62 38 41 70 ...
## $ jk : Factor w/ 2 levels "L","P": 1 2 1 1 1 1 1 2 2 2 ...
## $ GDP_M0 : num [1:60] 169 154 135 203 169 ...
## $ GDP_M4 : num [1:60] 164 143 136 190 165 ...
## $ GDP_M8 : num [1:60] 160 128 129 197 169 ...
## $ GDP_M12 : num [1:60] 147 118 133 190 164 ...
# 2. EKSPLORASI DATA
desk <- dat_long |>
group_by(kelompok, waktu) |>
get_summary_stats(gdp, type = "mean_sd")
desk
## # A tibble: 12 × 6
## kelompok waktu variable n mean sd
## <fct> <fct> <fct> <dbl> <dbl> <dbl>
## 1 Standar M0 gdp 20 177. 20.2
## 2 Standar M4 gdp 20 173. 21.1
## 3 Standar M8 gdp 20 168. 22.3
## 4 Standar M12 gdp 20 166. 25.6
## 5 Standar_Diet M0 gdp 20 177. 15.4
## 6 Standar_Diet M4 gdp 20 164. 15.9
## 7 Standar_Diet M8 gdp 20 156. 17.5
## 8 Standar_Diet M12 gdp 20 142. 18.8
## 9 Standar_Diet_Aktivitas M0 gdp 20 171. 23.1
## 10 Standar_Diet_Aktivitas M4 gdp 20 156. 22.9
## 11 Standar_Diet_Aktivitas M8 gdp 20 142. 25.3
## 12 Standar_Diet_Aktivitas M12 gdp 20 128. 25.7
# Matriks kovarians & korelasi antarwaktu
minggu <- c(0, 4, 8, 12)
kolom_gdp <- paste0("GDP_M", minggu)
S <- cov(dat_wide[, kolom_gdp])
R <- cor(dat_wide[, kolom_gdp])
round(S, 1)
## GDP_M0 GDP_M4 GDP_M8 GDP_M12
## GDP_M0 387.4 368.6 386.8 398.7
## GDP_M4 368.6 440.4 473.7 521.7
## GDP_M8 386.8 473.7 578.4 638.1
## GDP_M12 398.7 521.7 638.1 784.4
round(R, 2)
## GDP_M0 GDP_M4 GDP_M8 GDP_M12
## GDP_M0 1.00 0.89 0.82 0.72
## GDP_M4 0.89 1.00 0.94 0.89
## GDP_M8 0.82 0.94 1.00 0.95
## GDP_M12 0.72 0.89 0.95 1.00
# Varians selisih antarpasangan waktu (inti asumsi sfierisitas)
pasangan <- combn(kolom_gdp, 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, 1)
## GDP_M0 - GDP_M4 GDP_M0 - GDP_M8 GDP_M0 - GDP_M12 GDP_M4 - GDP_M8
## 90.7 192.2 374.4 71.4
## GDP_M4 - GDP_M12 GDP_M8 - GDP_M12
## 181.5 86.6
# Profile plot: rerata +/- 95% CI per kelompok
p_profil <- ggplot(dat_long, aes(minggu, gdp,
colour = kelompok,
group = kelompok)) +
stat_summary(fun = mean, geom = "line", linewidth = 1) +
stat_summary(fun = mean, geom = "point", size = 2.5) +
stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = .6) +
scale_x_continuous(breaks = minggu) +
labs(x = "Minggu ke-", y = "Gula darah puasa (GDP)",
colour = "Kelompok",
title = "Profil rerata GDP (+/- 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(minggu, gdp, 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 = "GDP",
title = "Lintasan individu dan rerata kelompok")
p_spag

# 3. REPEATED MEASURE ANOVA SATU ARAH
# Pertanyaan: apakah GDP berubah selama 12 minggu pada kelompok
# Standar_Diet_Aktivitas?
d1 <- droplevels(filter(dat_long, kelompok == "Standar_Diet_Aktivitas"))
d1w <- filter(dat_wide, kelompok == "Standar_Diet_Aktivitas")
## 3a. Uji asumsi -------------------------------------------------------------
# (i) Outlier per waktu
d1 |>
group_by(waktu) |>
identify_outliers(gdp)
## # A tibble: 3 × 9
## waktu id kelompok usia jk gdp minggu is.outlier is.extreme
## <fct> <fct> <fct> <dbl> <fct> <dbl> <dbl> <lgl> <lgl>
## 1 M0 D048 Standar_Diet_Aktiv… 64 P 103. 0 TRUE FALSE
## 2 M4 D048 Standar_Diet_Aktiv… 64 P 87.7 4 TRUE FALSE
## 3 M8 D048 Standar_Diet_Aktiv… 64 P 76.3 8 TRUE FALSE
# (ii) Normalitas per waktu (Shapiro-Wilk) dan Q-Q plot
d1 |>
group_by(waktu) |>
shapiro_test(gdp)
## # A tibble: 4 × 4
## waktu variable statistic p
## <fct> <chr> <dbl> <dbl>
## 1 M0 gdp 0.895 0.0331
## 2 M4 gdp 0.893 0.0312
## 3 M8 gdp 0.954 0.433
## 4 M12 gdp 0.966 0.659
ggpubr::ggqqplot(d1, "gdp", facet.by = "waktu")

# (iii) Sfierisitas: Mauchly
aov1_rs <- anova_test(data = d1, dv = gdp, 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 57 98.59 1.54e-22 * 0.838
##
## $`Mauchly's Test for Sphericity`
## Effect W p p<.05
## 1 waktu 0.229 8.67e-05 *
##
## $`Sphericity Corrections`
## Effect GGe DF[GG] p[GG] p[GG]<.05 HFe DF[HF] p[HF]
## 1 waktu 0.522 1.57, 29.78 7.94e-13 * 0.561 1.68, 31.98 1.29e-13
## 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.57 29.78 98.59 7.94e-13 * 0.838
## 3b. ANOVA dengan afex ------------------------------------------------------
aov1 <- aov_ez(id = "id", dv = "gdp", data = d1, within = "waktu",
anova_table = list(es = c("ges", "pes"), correction = "GG"))
aov1
## Anova Table (Type 3 tests)
##
## Response: gdp
## Effect df MSE F ges pes p.value
## 1 waktu 1.57, 29.78 136.02 98.59 *** .319 .838 <.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) 1780792 1 40803 19 829.24 < 2.2e-16 ***
## waktu 21017 3 4050 57 98.59 < 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.22882 8.6723e-05
##
##
## Greenhouse-Geisser and Huynh-Feldt Corrections
## for Departure from Sphericity
##
## GG eps Pr(>F[GG])
## waktu 0.52242 7.942e-13 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## HF eps Pr(>F[HF])
## waktu 0.5611078 1.289203e-13
# Ukuran efek tambahan
eta_squared(aov1, partial = TRUE)
## # Effect Size for ANOVA (Type III)
##
## Parameter | Eta2 (partial) | 95% CI
## -----------------------------------------
## waktu | 0.84 | [0.77, 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.31 | [0.13, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
## 3c. Pendekatan multivariat -------------------------------------------------
aov1$Anova
##
## Type III Repeated Measures MANOVA Tests: Pillai test statistic
## Df test stat approx F num Df den Df Pr(>F)
## (Intercept) 1 0.97760 829.24 1 19 < 2.2e-16 ***
## waktu 1 0.87464 39.54 3 17 6.985e-08 ***
## ---
## 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 171 5.16 19 160 182
## M4 156 5.13 19 145 167
## M8 142 5.66 19 130 154
## M12 128 5.75 19 116 140
##
## Confidence level used: 0.95
pairs(em1, adjust = "bonferroni")
## contrast estimate SE df t.ratio p.value
## M0 - M4 15.0 2.11 19 7.104 <0.0001
## M0 - M8 29.4 3.00 19 9.780 <0.0001
## M0 - M12 43.5 3.83 19 11.370 <0.0001
## M4 - M8 14.4 2.03 19 7.082 <0.0001
## M4 - M12 28.6 2.81 19 10.174 <0.0001
## M8 - M12 14.2 1.59 19 8.913 <0.0001
##
## P value adjustment: bonferroni method for 6 tests
contrast(em1, "trt.vs.ctrl", ref = 1, adjust = "holm")
## contrast estimate SE df t.ratio p.value
## M4 - M0 -15.0 2.11 19 -7.104 <0.0001
## M8 - M0 -29.4 3.00 19 -9.780 <0.0001
## M12 - M0 -43.5 3.83 19 -11.370 <0.0001
##
## P value adjustment: holm method for 3 tests
contrast(em1, "poly")
## contrast estimate SE df t.ratio p.value
## linear -144.96 12.90 19 -11.258 <0.0001
## quadratic 0.79 2.25 19 0.351 0.7294
## cubic -0.32 4.70 19 -0.068 0.9464
## 3e. Alternatif nonparametrik -----------------------------------------------
friedman_test(d1, gdp ~ waktu | id)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <dbl> <dbl> <chr>
## 1 gdp 20 55.3 3 5.87e-12 Friedman test
friedman_effsize(d1, gdp ~ waktu | id)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 gdp 20 0.922 Kendall W large
d1 |>
wilcox_test(gdp ~ 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 gdp M0 M4 20 20 209 0.00000381 0.0000229 ****
## 2 gdp M0 M8 20 20 210 0.00000191 0.0000114 ****
## 3 gdp M0 M12 20 20 210 0.00000191 0.0000114 ****
## 4 gdp M4 M8 20 20 206 0.0000134 0.0000801 ****
## 5 gdp M4 M12 20 20 210 0.00000191 0.0000114 ****
## 6 gdp M8 M12 20 20 209 0.00000381 0.0000229 ****
# (Opsional) ANOVA robust berbasis trimmed mean -- paket WRS2
if (requireNamespace("WRS2", quietly = TRUE)) {
print(WRS2::rmanova(d1$gdp, d1$waktu, d1$id, tr = 0.2))
}
## Call:
## WRS2::rmanova(y = d1$gdp, groups = d1$waktu, blocks = d1$id,
## tr = 0.2)
##
## Test statistic: F = 65.3718
## Degrees of freedom 1: 2.05
## Degrees of freedom 2: 22.56
## p-value: 0
# 4. MIXED DESIGN ANOVA (Kelompok [between] x Waktu [within])
# Pertanyaan: apakah pola perubahan GDP berbeda antarkelompok perlakuan?
## 4a. Uji asumsi -------------------------------------------------------------
# (i) Outlier per sel
dat_long |>
group_by(kelompok, waktu) |>
identify_outliers(gdp)
## # A tibble: 5 × 9
## kelompok waktu id usia jk gdp minggu is.outlier is.extreme
## <fct> <fct> <fct> <dbl> <fct> <dbl> <dbl> <lgl> <lgl>
## 1 Standar_Diet M8 D030 51 P 120. 8 TRUE FALSE
## 2 Standar_Diet M8 D036 62 P 194. 8 TRUE FALSE
## 3 Standar_Diet_Aktiv… M0 D048 64 P 103. 0 TRUE FALSE
## 4 Standar_Diet_Aktiv… M4 D048 64 P 87.7 4 TRUE FALSE
## 5 Standar_Diet_Aktiv… M8 D048 64 P 76.3 8 TRUE FALSE
# (ii) Normalitas per sel (3 x 4 = 12 sel) dan residual model
dat_long |>
group_by(kelompok, waktu) |>
shapiro_test(gdp)
## # A tibble: 12 × 5
## kelompok waktu variable statistic p
## <fct> <fct> <chr> <dbl> <dbl>
## 1 Standar M0 gdp 0.973 0.810
## 2 Standar M4 gdp 0.966 0.667
## 3 Standar M8 gdp 0.940 0.241
## 4 Standar M12 gdp 0.958 0.504
## 5 Standar_Diet M0 gdp 0.976 0.872
## 6 Standar_Diet M4 gdp 0.969 0.743
## 7 Standar_Diet M8 gdp 0.963 0.602
## 8 Standar_Diet M12 gdp 0.940 0.237
## 9 Standar_Diet_Aktivitas M0 gdp 0.895 0.0331
## 10 Standar_Diet_Aktivitas M4 gdp 0.893 0.0312
## 11 Standar_Diet_Aktivitas M8 gdp 0.954 0.433
## 12 Standar_Diet_Aktivitas M12 gdp 0.966 0.659
ggpubr::ggqqplot(dat_long, "gdp", ggtheme = theme_bw()) +
facet_grid(waktu ~ kelompok)

# (iii) Homogenitas varians antarkelompok pada tiap waktu
dat_long |>
group_by(waktu) |>
levene_test(gdp ~ kelompok)
## # A tibble: 4 × 5
## waktu df1 df2 statistic p
## <fct> <int> <int> <dbl> <dbl>
## 1 M0 2 57 0.635 0.533
## 2 M4 2 57 0.797 0.456
## 3 M8 2 57 0.877 0.422
## 4 M12 2 57 0.607 0.549
# (iv) Homogenitas matriks kovarians antarkelompok
box_m(dat_wide[, kolom_gdp], dat_wide$kelompok)
## # A tibble: 1 × 4
## statistic p.value parameter method
## <dbl> <dbl> <dbl> <chr>
## 1 19.8 0.471 20 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 = "gdp", data = dat_long,
between = "kelompok", within = "waktu",
anova_table = list(es = c("ges", "pes"), correction = "GG"))
aov2
## Anova Table (Type 3 tests)
##
## Response: gdp
## Effect df MSE F ges pes p.value
## 1 kelompok 2, 57 1685.46 5.48 ** .150 .161 .007
## 2 waktu 1.89, 107.71 80.55 194.90 *** .221 .774 <.001
## 3 kelompok:waktu 3.78, 107.71 80.55 19.80 *** .054 .410 <.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) 6135619 1 96071 57 3640.3291 < 2e-16 ***
## kelompok 18476 2 96071 57 5.4811 0.00665 **
## waktu 29667 3 8676 171 194.9002 < 2e-16 ***
## kelompok:waktu 6029 6 8676 171 19.8033 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
##
## Mauchly Tests for Sphericity
##
## Test statistic p-value
## waktu 0.43072 5.9188e-09
## kelompok:waktu 0.43072 5.9188e-09
##
##
## Greenhouse-Geisser and Huynh-Feldt Corrections
## for Departure from Sphericity
##
## GG eps Pr(>F[GG])
## waktu 0.62989 < 2.2e-16 ***
## kelompok:waktu 0.62989 7.778e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## HF eps Pr(>F[HF])
## waktu 0.6508229 1.106445e-36
## kelompok:waktu 0.6508229 3.710862e-12
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.98458 3640.3 1 57 < 2.2e-16 ***
## kelompok 2 0.16130 5.5 2 57 0.00665 **
## waktu 1 0.83354 91.8 3 55 < 2.2e-16 ***
## kelompok:waktu 2 0.58289 7.7 6 112 6.388e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Versi rstatix (format ringkas untuk laporan)
aov2_rs <- anova_test(data = dat_long, dv = gdp, wid = id,
between = kelompok, within = waktu,
effect.size = "pes", type = 3)
get_anova_table(aov2_rs, correction = "GG")
## ANOVA Table (type III tests)
##
## Effect DFn DFd F p p<.05 pes
## 1 kelompok 2.00 57.00 5.481 7.00e-03 * 0.161
## 2 waktu 1.89 107.71 194.900 1.38e-35 * 0.774
## 3 kelompok:waktu 3.78 107.71 19.803 7.78e-12 * 0.410
# Ukuran efek
eta_squared(aov2, partial = TRUE)
## # Effect Size for ANOVA (Type III)
##
## Parameter | Eta2 (partial) | 95% CI
## ----------------------------------------------
## kelompok | 0.16 | [0.03, 1.00]
## waktu | 0.77 | [0.73, 1.00]
## kelompok:waktu | 0.41 | [0.31, 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.13 | [0.01, 1.00]
## waktu | 0.22 | [0.12, 1.00]
## kelompok:waktu | 0.05 | [0.00, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
# Plot interaksi dari model
afex_plot(aov2, x = "waktu", trace = "kelompok", error = "within",
mapping = c("colour", "shape", "linetype")) +
labs(y = "GDP", 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 ---------------------------------------------------------
em2 <- emmeans(aov2, ~ waktu | kelompok)
# Efek WAKTU di dalam tiap kelompok
joint_tests(aov2, by = "kelompok")
## Warning in pf(conf$F.ratio, conf$df1, conf$df2, lower.tail = FALSE): NaNs
## produced
## kelompok = Standar:
## model term df1 df2 F.ratio p.value
## waktu 3 57 5.202 0.0030
##
## kelompok = Standar_Diet:
## model term df1 df2 F.ratio p.value
## waktu 3 57 44.071 <0.0001
##
## kelompok = Standar_Diet_Aktivitas:
## model term df1 df2 F.ratio p.value
## waktu 3 57 67.410 <0.0001
# Efek KELOMPOK pada tiap waktu
joint_tests(aov2, by = "waktu")
## waktu = M0:
## model term df1 df2 F.ratio p.value
## kelompok 2 57 0.619 0.5418
##
## waktu = M4:
## model term df1 df2 F.ratio p.value
## kelompok 2 57 3.351 0.0421
##
## waktu = M8:
## model term df1 df2 F.ratio p.value
## kelompok 2 57 6.899 0.0021
##
## waktu = M12:
## model term df1 df2 F.ratio p.value
## kelompok 2 57 13.178 <0.0001
# Post hoc: tiap waktu vs baseline di dalam tiap kelompok
contrast(em2, "trt.vs.ctrl", ref = 1, adjust = "holm")
## kelompok = Standar:
## contrast estimate SE df t.ratio p.value
## M4 - M0 -4.20 1.87 57 -2.247 0.0285
## M8 - M0 -9.36 2.52 57 -3.706 0.0014
## M12 - M0 -11.37 3.10 57 -3.669 0.0014
##
## kelompok = Standar_Diet:
## contrast estimate SE df t.ratio p.value
## M4 - M0 -13.57 1.87 57 -7.261 <0.0001
## M8 - M0 -21.78 2.52 57 -8.628 <0.0001
## M12 - M0 -35.24 3.10 57 -11.375 <0.0001
##
## kelompok = Standar_Diet_Aktivitas:
## contrast estimate SE df t.ratio p.value
## M4 - M0 -14.96 1.87 57 -8.002 <0.0001
## M8 - M0 -29.36 2.52 57 -11.629 <0.0001
## M12 - M0 -43.52 3.10 57 -14.045 <0.0001
##
## P value adjustment: holm method for 3 tests
# Post hoc: perbandingan antarkelompok pada tiap waktu
em2b <- emmeans(aov2, ~ kelompok | waktu)
pairs(em2b, adjust = "tukey")
## waktu = M0:
## contrast estimate SE df t.ratio p.value
## Standar - Standar_Diet -0.515 6.26 57 -0.082 0.9963
## Standar - Standar_Diet_Aktivitas 5.765 6.26 57 0.920 0.6299
## Standar_Diet - Standar_Diet_Aktivitas 6.280 6.26 57 1.002 0.5784
##
## waktu = M4:
## contrast estimate SE df t.ratio p.value
## Standar - Standar_Diet 8.855 6.39 57 1.386 0.3547
## Standar - Standar_Diet_Aktivitas 16.520 6.39 57 2.587 0.0324
## Standar_Diet - Standar_Diet_Aktivitas 7.665 6.39 57 1.200 0.4580
##
## waktu = M8:
## contrast estimate SE df t.ratio p.value
## Standar - Standar_Diet 11.910 6.94 57 1.715 0.2083
## Standar - Standar_Diet_Aktivitas 25.765 6.94 57 3.711 0.0013
## Standar_Diet - Standar_Diet_Aktivitas 13.855 6.94 57 1.996 0.1225
##
## waktu = M12:
## contrast estimate SE df t.ratio p.value
## Standar - Standar_Diet 23.360 7.45 57 3.135 0.0075
## Standar - Standar_Diet_Aktivitas 37.915 7.45 57 5.088 <0.0001
## Standar_Diet - Standar_Diet_Aktivitas 14.555 7.45 57 1.953 0.1333
##
## P value adjustment: tukey method for comparing a family of 3 estimates
## 4d. Kontras interaksi ------------------------------------------------------
# Apakah penurunan (M12 - M0) berbeda antarkelompok?
em_full <- emmeans(aov2, ~ waktu * kelompok)
contrast(em_full,
interaction = list(waktu = list("M12-M0" = c(-1, 0, 0, 1)),
kelompok = "pairwise"),
adjust = "holm")
## waktu_custom kelompok_pairwise estimate SE df t.ratio
## M12-M0 Standar - Standar_Diet 23.88 4.38 57 5.448
## M12-M0 Standar - Standar_Diet_Aktivitas 32.15 4.38 57 7.337
## M12-M0 Standar_Diet - Standar_Diet_Aktivitas 8.28 4.38 57 1.888
## p.value
## <0.0001
## <0.0001
## 0.0641
##
## P value adjustment: holm method for 3 tests
# Tren linear per kelompok dan perbandingannya
contrast(em2, "poly")[c(1, 4, 7)]
## contrast kelompok estimate SE df t.ratio p.value
## linear Standar -39.3 10.2 57 -3.831 0.0003
## linear Standar_Diet -113.9 10.2 57 -11.117 <0.0001
## linear Standar_Diet_Aktivitas -145.0 10.2 57 -14.143 <0.0001
tren_int <- summary(
contrast(em_full,
interaction = c(waktu = "poly", kelompok = "pairwise"),
adjust = "none")
)
tren_lin <- subset(tren_int, waktu_poly == "linear")
tren_lin$p.holm <- p.adjust(tren_lin$p.value, "holm")
tren_lin
## waktu_poly kelompok_pairwise estimate SE df
## 1 linear Standar - Standar_Diet 74.680 14.49466 57
## 4 linear Standar - Standar_Diet_Aktivitas 105.695 14.49466 57
## 7 linear Standar_Diet - Standar_Diet_Aktivitas 31.015 14.49466 57
## t.ratio p.value p.holm
## 1 5.152241 3.342437e-06 6.684875e-06
## 4 7.291995 1.037498e-09 3.112495e-09
## 7 2.139753 3.666865e-02 3.666865e-02
# 5. PEMBANDING: LINEAR MIXED MODEL (LMM)
# Tidak mensyaratkan sfierisitas, menampung data hilang (MAR) dan waktu
# pengukuran yang tidak seragam.
lmm1 <- lmer(gdp ~ kelompok * waktu + (1 | id),
data = dat_long, REML = TRUE)
lmm2 <- lmer(gdp ~ kelompok * waktu + (1 + minggu | id),
data = dat_long, REML = TRUE,
control = lmerControl(optimizer = "bobyqa"))
anova(lmm1, lmm2, refit = FALSE)
## Data: dat_long
## Models:
## lmm1: gdp ~ kelompok * waktu + (1 | id)
## lmm2: gdp ~ kelompok * waktu + (1 + minggu | id)
## npar AIC BIC logLik -2*log(L) Chisq Df Pr(>Chisq)
## lmm1 14 1823.0 1871.8 -897.53 1795.0
## lmm2 16 1775.4 1831.0 -871.68 1743.4 51.69 2 5.966e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
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 258.5 129.26 2 57.00 5.4811 0.00665 **
## waktu 6684.5 2228.16 3 121.08 93.8206 < 2.2e-16 ***
## kelompok:waktu 1450.5 241.75 6 134.40 10.1625 2.961e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
performance::icc(lmm1)
## # Intraclass Correlation Coefficient
##
## Adjusted ICC: 0.890
## Unadjusted ICC: 0.596
# 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 nilai hilang untuk menunjukkan keunggulan LMM
set.seed(1)
dat_miss <- dat_long
dat_miss$gdp[sample(which(dat_miss$waktu != "M0"), 20)] <- NA
lmm_miss <- lmer(gdp ~ kelompok * waktu + (1 + minggu | id),
data = dat_miss,
control = lmerControl(optimizer = "bobyqa"))
anova(lmm_miss, ddf = "Kenward-Roger")
## Type III Analysis of Variance Table with Kenward-Roger's method
## Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
## kelompok 277.1 138.55 2 57.01 5.5473 0.006291 **
## waktu 7232.2 2410.74 3 109.16 95.8187 < 2.2e-16 ***
## kelompok:waktu 1546.3 257.72 6 120.17 10.2259 3.98e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# RM ANOVA akan membuang subjek yang punya minimal 1 nilai hilang
n_distinct(dat_miss$id[is.na(dat_miss$gdp)])
## [1] 19
# 6. MENYIMPAN DATA & RINGKASAN HASIL
dir.create("hasil_repeated_measures_diabetes", showWarnings = FALSE)
write.csv(dat_wide,
"hasil_repeated_measures_diabetes/data_diabetes_gdp_wide.csv",
row.names = FALSE)
write.csv(dat_long,
"hasil_repeated_measures_diabetes/data_diabetes_gdp_long.csv",
row.names = FALSE)
write.csv(desk,
"hasil_repeated_measures_diabetes/deskriptif_gdp.csv",
row.names = FALSE)
write.csv(as.data.frame(get_anova_table(aov1_rs, correction = "auto")),
"hasil_repeated_measures_diabetes/one_way_rm_anova.csv",
row.names = FALSE)
write.csv(as.data.frame(get_anova_table(aov2_rs, correction = "GG")),
"hasil_repeated_measures_diabetes/mixed_design_anova.csv",
row.names = FALSE)
ggsave("hasil_repeated_measures_diabetes/profile_plot_gdp.png",
p_profil, width = 8, height = 5, dpi = 300)
## Warning: Computation failed in `stat_summary()`.
## Caused by error in `fun.data()`:
## ! The package "Hmisc" is required.
ggsave("hasil_repeated_measures_diabetes/spaghetti_plot_gdp.png",
p_spag, width = 8, height = 5, dpi = 300)
sink("hasil_repeated_measures_diabetes/session_info.txt")
sessionInfo()
sink()
list.files("hasil_repeated_measures_diabetes")
## [1] "data_diabetes_gdp_long.csv" "data_diabetes_gdp_wide.csv"
## [3] "deskriptif_gdp.csv" "mixed_design_anova.csv"
## [5] "one_way_rm_anova.csv" "profile_plot_gdp.png"
## [7] "session_info.txt" "spaghetti_plot_gdp.png"