# ============================================================
# TUGAS BIOSTATISTIKA INTERMEDIATE
# NAMA : LUKMAN HAKIM
# NIM : 2611018052
# REPEATED MEASURE ANALYSIS DENGAN R
# Studi: Movingcall - physical activity promotion
# Dataset: SIMULASI berbasis Fischer et al. (2019)
# Outcome: objective MVPA (menit/minggu)
# 3 kelompok x 3 waktu
# ============================================================
# 0. PAKET ---------------------------------------------------
# Paket yang dibutuhkan. Paket yang belum ada akan dipasang otomatis.
required_pkgs <- c(
"dplyr", "tidyr", "ggplot2", "afex", "emmeans", "rstatix",
"car", "effectsize", "lme4", "lmerTest", "performance", "ggpubr"
)
missing_pkgs <- required_pkgs[
!vapply(required_pkgs, requireNamespace, FUN.VALUE = logical(1), quietly = TRUE)
]
## Registered S3 method overwritten by 'lme4':
## method from
## na.action.merMod car
if (length(missing_pkgs) > 0) {
message("Menginstal paket yang belum tersedia: ", paste(missing_pkgs, collapse = ", "))
install.packages(missing_pkgs, dependencies = TRUE)
}
suppressPackageStartupMessages({
invisible(lapply(required_pkgs, library, character.only = TRUE))
})
options(contrasts = c("contr.sum", "contr.poly"))
theme_set(theme_bw(base_size = 12))
# 1. DATA ----------------------------------------------------
# Skrip lama langsung mencari CSV di working directory.
# Versi ini akan memakai file tersebut bila tersedia; jika tidak, RStudio
# akan meminta Anda memilih file CSV secara manual.
default_file <- "Data_Simulasi_MVPA_Movingcall_3x3.csv"
if (file.exists(default_file)) {
data_file <- default_file
} else {
message(
"File '", default_file, "' tidak ditemukan di working directory: ",
getwd(),
"\nSilakan pilih file CSV data MVPA pada jendela yang muncul."
)
data_file <- file.choose()
}
# Deteksi pemisah CSV: koma (,) atau titik koma (;).
first_line <- readLines(data_file, n = 1, warn = FALSE)
sep_detected <- if (grepl(";", first_line, fixed = TRUE)) ";" else ","
dec_detected <- if (sep_detected == ";") "," else "."
dat_wide <- read.table(
data_file,
header = TRUE,
sep = sep_detected,
dec = dec_detected,
check.names = FALSE,
stringsAsFactors = FALSE,
strip.white = TRUE
)
# Bersihkan nama kolom dari spasi yang tidak sengaja.
names(dat_wide) <- trimws(names(dat_wide))
required_cols <- c("id", "kelompok", "Baseline", "M6", "M12")
missing_cols <- setdiff(required_cols, names(dat_wide))
if (length(missing_cols) > 0) {
stop(
"Kolom wajib tidak ditemukan: ", paste(missing_cols, collapse = ", "),
"\nKolom yang terbaca: ", paste(names(dat_wide), collapse = ", "),
"\nFormat yang dibutuhkan: id, kelompok, Baseline, M6, M12"
)
}
# Bersihkan isi variabel kelompok.
dat_wide$kelompok <- trimws(as.character(dat_wide$kelompok))
valid_groups <- c("Control", "Coaching", "Coaching+SMS")
invalid_groups <- setdiff(unique(dat_wide$kelompok), valid_groups)
if (length(invalid_groups) > 0) {
stop(
"Nama kelompok tidak sesuai. Nilai yang tidak dikenali: ",
paste(invalid_groups, collapse = ", "),
"\nGunakan tepat: Control, Coaching, Coaching+SMS"
)
}
# Pastikan outcome numerik. Jika angka tersimpan sebagai karakter dengan koma
# desimal, ubah terlebih dahulu menjadi titik sebelum dikonversi ke numeric.
for (v in c("Baseline", "M6", "M12")) {
if (!is.numeric(dat_wide[[v]])) {
dat_wide[[v]] <- as.numeric(gsub(",", ".", trimws(as.character(dat_wide[[v]])), fixed = TRUE))
}
}
if (anyNA(dat_wide[, c("Baseline", "M6", "M12")])) {
bad_rows <- which(!complete.cases(dat_wide[, c("Baseline", "M6", "M12")]))
stop(
"Ada nilai kosong/tidak numerik pada Baseline, M6, atau M12. Baris bermasalah: ",
paste(bad_rows, collapse = ", ")
)
}
if (anyDuplicated(dat_wide$id)) {
stop("Kolom 'id' harus unik: satu baris per peserta pada format wide.")
}
dat_wide$kelompok <- factor(dat_wide$kelompok, levels = valid_groups)
dat_wide$id <- factor(dat_wide$id)
dat_long <- dat_wide |>
pivot_longer(
cols = c(Baseline, M6, M12),
names_to = "waktu",
values_to = "mvpa"
) |>
mutate(
waktu = factor(waktu, levels = c("Baseline", "M6", "M12")),
bulan = case_when(
waktu == "Baseline" ~ 0,
waktu == "M6" ~ 6,
waktu == "M12" ~ 12
)
)
message("Data berhasil dibaca: ", nrow(dat_wide), " peserta; ", nrow(dat_long), " observasi longitudinal.")
## Data berhasil dibaca: 90 peserta; 270 observasi longitudinal.
print(head(dat_wide))
## id kelompok Baseline M6 M12
## 1 P001 Control 86.0 59.3 54.3
## 2 P002 Control 116.2 122.3 68.0
## 3 P003 Control 82.6 97.1 53.3
## 4 P004 Control 88.2 83.1 111.1
## 5 P005 Control 73.6 57.5 52.5
## 6 P006 Control 95.2 107.8 55.6
print(head(dat_long))
## # A tibble: 6 × 5
## id kelompok waktu mvpa bulan
## <fct> <fct> <fct> <dbl> <dbl>
## 1 P001 Control Baseline 86 0
## 2 P001 Control M6 59.3 6
## 3 P001 Control M12 54.3 12
## 4 P002 Control Baseline 116. 0
## 5 P002 Control M6 122. 6
## 6 P002 Control M12 68 12
str(dat_long)
## tibble [270 × 5] (S3: tbl_df/tbl/data.frame)
## $ id : Factor w/ 90 levels "P001","P002",..: 1 1 1 2 2 2 3 3 3 4 ...
## $ kelompok: Factor w/ 3 levels "Control","Coaching",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ waktu : Factor w/ 3 levels "Baseline","M6",..: 1 2 3 1 2 3 1 2 3 1 ...
## $ mvpa : num [1:270] 86 59.3 54.3 116.2 122.3 ...
## $ bulan : num [1:270] 0 6 12 0 6 12 0 6 12 0 ...
# 2. EKSPLORASI ----------------------------------------------
desk <- dat_long |>
group_by(kelompok, waktu) |>
get_summary_stats(mvpa, type = "mean_sd")
desk
## # A tibble: 9 × 6
## kelompok waktu variable n mean sd
## <fct> <fct> <fct> <dbl> <dbl> <dbl>
## 1 Control Baseline mvpa 30 90.0 27.0
## 2 Control M6 mvpa 30 84.9 26.4
## 3 Control M12 mvpa 30 63.9 26.1
## 4 Coaching Baseline mvpa 30 90.0 26.6
## 5 Coaching M6 mvpa 30 116. 20.6
## 6 Coaching M12 mvpa 30 96.9 20.5
## 7 Coaching+SMS Baseline mvpa 30 90 23.3
## 8 Coaching+SMS M6 mvpa 30 118. 23.9
## 9 Coaching+SMS M12 mvpa 30 106. 28.2
p_profil <- ggplot(dat_long, aes(waktu, mvpa, group = kelompok, colour = kelompok)) +
stat_summary(fun = mean, geom = "line", linewidth = 1) +
stat_summary(fun = mean, geom = "point", size = 2.5) +
labs(x = "Waktu", y = "MVPA objektif (menit/minggu)", colour = "Kelompok",
title = "Profil rerata MVPA") +
theme(legend.position = "bottom")
p_profil

p_spag <- ggplot(dat_long, aes(waktu, mvpa, group = id)) +
geom_line(alpha = .25) +
stat_summary(aes(group = 1), fun = mean, geom = "line", linewidth = 1.2) +
facet_wrap(~kelompok) +
labs(x = "Waktu", y = "MVPA (menit/minggu)",
title = "Lintasan individu dan rerata kelompok")
p_spag

# 3. REPEATED MEASURE ANOVA SATU ARAH -----------------------
# Contoh fokus: kelompok Coaching+SMS
d1 <- droplevels(filter(dat_long, kelompok == "Coaching+SMS"))
# 3a. Asumsi
# Outlier
d1 |> group_by(waktu) |> identify_outliers(mvpa)
## [1] waktu id kelompok mvpa bulan is.outlier is.extreme
## <0 rows> (or 0-length row.names)
# Normalitas
d1 |> group_by(waktu) |> shapiro_test(mvpa)
## # A tibble: 3 × 4
## waktu variable statistic p
## <fct> <chr> <dbl> <dbl>
## 1 Baseline mvpa 0.938 0.0807
## 2 M6 mvpa 0.968 0.479
## 3 M12 mvpa 0.990 0.993
ggpubr::ggqqplot(d1, "mvpa", facet.by = "waktu")

# Sphericity + ANOVA
aov1_rs <- anova_test(data = d1, dv = mvpa, 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 2 58 22.843 4.82e-08 * 0.441
##
## $`Mauchly's Test for Sphericity`
## Effect W p p<.05
## 1 waktu 0.998 0.975
##
## $`Sphericity Corrections`
## Effect GGe DF[GG] p[GG] p[GG]<.05 HFe DF[HF] p[HF] p[HF]<.05
## 1 waktu 0.998 2, 57.9 4.94e-08 * 1.072 2.14, 62.17 4.82e-08 *
get_anova_table(aov1_rs, correction = "auto")
## ANOVA Table (type III tests)
##
## Effect DFn DFd F p p<.05 pes
## 1 waktu 2 58 22.843 4.82e-08 * 0.441
# 3b. afex + effect size
aov1 <- aov_ez(id = "id", dv = "mvpa", data = d1, within = "waktu",
anova_table = list(es = c("ges","pes"), correction = "GG"))
aov1
## Anova Table (Type 3 tests)
##
## Response: mvpa
## Effect df MSE F ges pes p.value
## 1 waktu 2.00, 57.90 267.96 22.84 *** .181 .441 <.001
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
##
## Sphericity correction method: GG
summary(aov1)
## 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) 986630 1 39833 29 718.300 < 2.2e-16 ***
## waktu 12221 2 15514 58 22.843 4.824e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
##
## Mauchly Tests for Sphericity
##
## Test statistic p-value
## waktu 0.99823 0.97548
##
##
## Greenhouse-Geisser and Huynh-Feldt Corrections
## for Departure from Sphericity
##
## GG eps Pr(>F[GG])
## waktu 0.99823 4.942e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## HF eps Pr(>F[HF])
## waktu 1.071969 4.824455e-08
eta_squared(aov1, partial = TRUE)
## # Effect Size for ANOVA (Type III)
##
## Parameter | Eta2 (partial) | 95% CI
## -----------------------------------------
## waktu | 0.44 | [0.28, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
# 3c. Post hoc
em1 <- emmeans(aov1, ~ waktu)
pairs(em1, adjust = "holm")
## contrast estimate SE df t.ratio p.value
## Baseline - M6 -28.5 4.16 29 -6.856 <0.0001
## Baseline - M12 -15.6 4.20 29 -3.713 0.0017
## M6 - M12 12.9 4.31 29 2.994 0.0056
##
## P value adjustment: holm method for 3 tests
contrast(em1, "trt.vs.ctrl", ref = 1, adjust = "holm")
## contrast estimate SE df t.ratio p.value
## M6 - Baseline 28.5 4.16 29 6.856 <0.0001
## M12 - Baseline 15.6 4.20 29 3.713 0.0009
##
## P value adjustment: holm method for 2 tests
# 3d. Non-parametrik pembanding
friedman_test(d1, mvpa ~ waktu | id)
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <dbl> <dbl> <chr>
## 1 mvpa 30 18.2 2 0.000112 Friedman test
friedman_effsize(d1, mvpa ~ waktu | id)
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 mvpa 30 0.303 Kendall W moderate
d1 |> pairwise_wilcox_test(mvpa ~ waktu, paired = TRUE, p.adjust.method = "holm")
## # 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 mvpa Baseline M6 30 30 8 0.0000000466 1.40e-7 ****
## 2 mvpa Baseline M12 30 30 91 0.00277 5.53e-3 **
## 3 mvpa M6 M12 30 30 352. 0.0122 1.22e-2 *
# 4. MIXED DESIGN ANOVA: KELOMPOK x WAKTU -------------------
# 4a. Asumsi
# Outlier per sel
dat_long |> group_by(kelompok, waktu) |> identify_outliers(mvpa)
## # A tibble: 1 × 7
## kelompok waktu id mvpa bulan is.outlier is.extreme
## <fct> <fct> <fct> <dbl> <dbl> <lgl> <lgl>
## 1 Control Baseline P011 24.1 0 TRUE FALSE
# Normalitas per sel
dat_long |> group_by(kelompok, waktu) |> shapiro_test(mvpa)
## # A tibble: 9 × 5
## kelompok waktu variable statistic p
## <fct> <fct> <chr> <dbl> <dbl>
## 1 Control Baseline mvpa 0.971 0.580
## 2 Control M6 mvpa 0.987 0.968
## 3 Control M12 mvpa 0.961 0.336
## 4 Coaching Baseline mvpa 0.989 0.988
## 5 Coaching M6 mvpa 0.969 0.510
## 6 Coaching M12 mvpa 0.949 0.164
## 7 Coaching+SMS Baseline mvpa 0.938 0.0807
## 8 Coaching+SMS M6 mvpa 0.968 0.479
## 9 Coaching+SMS M12 mvpa 0.990 0.993
# Homogenitas varians antar kelompok pada tiap waktu
dat_long |> group_by(waktu) |> levene_test(mvpa ~ kelompok)
## # A tibble: 3 × 5
## waktu df1 df2 statistic p
## <fct> <int> <int> <dbl> <dbl>
## 1 Baseline 2 87 0.0595 0.942
## 2 M6 2 87 0.783 0.460
## 3 M12 2 87 1.16 0.320
# Box's M untuk homogenitas matriks kovarians
tryCatch(
box_m(dat_wide[, c("Baseline", "M6", "M12")], dat_wide$kelompok),
error = function(e) message("Box's M tidak dapat dihitung: ", e$message)
)
## # A tibble: 1 × 4
## statistic p.value parameter method
## <dbl> <dbl> <dbl> <chr>
## 1 6.59 0.883 12 Box's M-test for Homogeneity of Covariance Matric…
# 4b. Mixed ANOVA
aov2 <- aov_ez(id = "id", dv = "mvpa", data = dat_long,
between = "kelompok", within = "waktu",
anova_table = list(es = c("ges","pes"), correction = "GG"))
aov2
## Anova Table (Type 3 tests)
##
## Response: mvpa
## Effect df MSE F ges pes p.value
## 1 kelompok 2, 87 1313.67 12.63 *** .171 .225 <.001
## 2 waktu 2.00, 173.64 271.59 33.00 *** .100 .275 <.001
## 3 kelompok:waktu 3.99, 173.64 271.59 15.82 *** .096 .267 <.001
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
##
## Sphericity correction method: GG
summary(aov2)
## 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) 2444128 1 114289 87 1860.534 < 2.2e-16 ***
## kelompok 33196 2 114289 87 12.635 1.523e-05 ***
## waktu 17889 2 47159 174 33.003 7.056e-13 ***
## kelompok:waktu 17156 4 47159 174 15.825 4.580e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
##
## Mauchly Tests for Sphericity
##
## Test statistic p-value
## waktu 0.99794 0.91509
## kelompok:waktu 0.99794 0.91509
##
##
## Greenhouse-Geisser and Huynh-Feldt Corrections
## for Departure from Sphericity
##
## GG eps Pr(>F[GG])
## waktu 0.99794 7.416e-13 ***
## kelompok:waktu 0.99794 4.777e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## HF eps Pr(>F[HF])
## waktu 1.02135 7.056007e-13
## kelompok:waktu 1.02135 4.579800e-11
eta_squared(aov2, partial = TRUE)
## # Effect Size for ANOVA (Type III)
##
## Parameter | Eta2 (partial) | 95% CI
## ----------------------------------------------
## kelompok | 0.23 | [0.10, 1.00]
## waktu | 0.28 | [0.18, 1.00]
## kelompok:waktu | 0.27 | [0.17, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
# Versi rstatix
aov2_rs <- anova_test(data = dat_long, dv = mvpa, wid = id,
between = kelompok, within = waktu,
effect.size = "pes", type = 3)
get_anova_table(aov2_rs, correction = "auto")
## ANOVA Table (type III tests)
##
## Effect DFn DFd F p p<.05 pes
## 1 kelompok 2 87 12.635 1.52e-05 * 0.225
## 2 waktu 2 174 33.003 7.06e-13 * 0.275
## 3 kelompok:waktu 4 174 15.825 4.58e-11 * 0.267
# 4c. Simple effects dan post hoc
joint_tests(aov2, by = "kelompok") # efek waktu pada tiap kelompok
## kelompok = Control:
## model term df1 df2 F.ratio p.value
## waktu 2 87 22.058 <0.0001
##
## kelompok = Coaching:
## model term df1 df2 F.ratio p.value
## waktu 2 87 20.078 <0.0001
##
## kelompok = Coaching+SMS:
## model term df1 df2 F.ratio p.value
## waktu 2 87 22.035 <0.0001
joint_tests(aov2, by = "waktu") # efek kelompok pada tiap waktu
## waktu = Baseline:
## model term df1 df2 F.ratio p.value
## kelompok 2 87 0.000 1.0000
##
## waktu = M6:
## model term df1 df2 F.ratio p.value
## kelompok 2 87 18.936 <0.0001
##
## waktu = M12:
## model term df1 df2 F.ratio p.value
## kelompok 2 87 22.938 <0.0001
em_time <- emmeans(aov2, ~ waktu | kelompok)
contrast(em_time, "trt.vs.ctrl", ref = 1, adjust = "holm")
## kelompok = Control:
## contrast estimate SE df t.ratio p.value
## M6 - Baseline -5.09 4.31 87 -1.181 0.2410
## M12 - Baseline -26.09 4.15 87 -6.281 <0.0001
##
## kelompok = Coaching:
## contrast estimate SE df t.ratio p.value
## M6 - Baseline 26.51 4.31 87 6.148 <0.0001
## M12 - Baseline 6.90 4.15 87 1.662 0.1002
##
## kelompok = Coaching+SMS:
## contrast estimate SE df t.ratio p.value
## M6 - Baseline 28.50 4.31 87 6.611 <0.0001
## M12 - Baseline 15.61 4.15 87 3.757 0.0003
##
## P value adjustment: holm method for 2 tests
em_group <- emmeans(aov2, ~ kelompok | waktu)
pairs(em_group, adjust = "tukey")
## waktu = Baseline:
## contrast estimate SE df t.ratio p.value
## Control - Coaching 0.00000 6.63 87 0.000 1.0000
## Control - (Coaching+SMS) -0.00667 6.63 87 -0.001 1.0000
## Coaching - (Coaching+SMS) -0.00667 6.63 87 -0.001 1.0000
##
## waktu = M6:
## contrast estimate SE df t.ratio p.value
## Control - Coaching -31.59667 6.12 87 -5.159 <0.0001
## Control - (Coaching+SMS) -33.59667 6.12 87 -5.485 <0.0001
## Coaching - (Coaching+SMS) -2.00000 6.12 87 -0.327 0.9430
##
## waktu = M12:
## contrast estimate SE df t.ratio p.value
## Control - Coaching -32.99667 6.50 87 -5.079 <0.0001
## Control - (Coaching+SMS) -41.70667 6.50 87 -6.420 <0.0001
## Coaching - (Coaching+SMS) -8.71000 6.50 87 -1.341 0.3767
##
## P value adjustment: tukey method for comparing a family of 3 estimates
# 4d. Kontras interaksi: apakah perubahan Baseline -> M12 berbeda antar kelompok
# Hitung perubahan M12 - Baseline pada tiap kelompok, lalu bandingkan perubahan tersebut.
em_change <- contrast(
em_time,
method = list("M12 - Baseline" = c(-1, 0, 1))
)
pairs(em_change, adjust = "holm")
## kelompok = Control:
## contrast estimate SE df z.ratio p.value
## (nothing) nonEst NA NA NA NA
##
## kelompok = Coaching:
## contrast estimate SE df z.ratio p.value
## (nothing) nonEst NA NA NA NA
##
## kelompok = Coaching+SMS:
## contrast estimate SE df z.ratio p.value
## (nothing) nonEst NA NA NA NA
# 5. PEMBANDING: LINEAR MIXED MODEL -------------------------
lmm1 <- lmer(mvpa ~ kelompok * waktu + (1 | id), data = dat_long, REML = TRUE)
lmm2 <- lmer(mvpa ~ kelompok * waktu + (1 + bulan | id), data = dat_long, REML = TRUE,
control = lmerControl(optimizer = "bobyqa"))
## boundary (singular) fit: see help('isSingular')
anova(lmm1, lmm2, refit = FALSE)
## Data: dat_long
## Models:
## lmm1: mvpa ~ kelompok * waktu + (1 | id)
## lmm2: mvpa ~ kelompok * waktu + (1 + bulan | id)
## npar AIC BIC logLik -2*log(L) Chisq Df Pr(>Chisq)
## lmm1 11 2406.0 2445.6 -1192 2384.0
## lmm2 13 2409.9 2456.7 -1192 2383.9 0.0552 2 0.9728
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 6846 3423.0 2 87.00 12.635 1.523e-05 ***
## waktu 17889 8944.6 2 115.30 32.826 5.199e-12 ***
## kelompok:waktu 17145 4286.1 4 129.03 15.700 1.712e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
performance::icc(lmm1)
## # Intraclass Correlation Coefficient
##
## Adjusted ICC: 0.562
## Unadjusted ICC: 0.398
tryCatch(
performance::check_model(lmm2),
error = function(e) message("Plot diagnostik LMM tidak dapat dibuat: ", e$message)
)
# 6. SIMPAN OUTPUT ------------------------------------------
output_dir <- file.path(getwd(), "output_repeated_measure")
if (!dir.exists(output_dir)) dir.create(output_dir, recursive = TRUE)
write.csv(
desk,
file.path(output_dir, "Ringkasan_Deskriptif_MVPA.csv"),
row.names = FALSE
)
ggsave(
file.path(output_dir, "Profil_MVPA.png"),
p_profil, width = 7, height = 4.5, dpi = 300
)
ggsave(
file.path(output_dir, "Spaghetti_MVPA.png"),
p_spag, width = 9, height = 4.5, dpi = 300
)
message("Selesai. Output tersimpan di: ", normalizePath(output_dir, winslash = "/", mustWork = FALSE))
## Selesai. Output tersimpan di: C:/Users/kesba/Downloads/FERI/ARS/BIOSTATISTIKA/KIM HAKIM/output_repeated_measure