pkgs <- c("tidyverse", "biotools", "car", "heplots",
"psych", "ggplot2", "knitr", "kableExtra",
"mvnormtest", "MVN", "emmeans", "effectsize")
new_pkgs <- pkgs[!pkgs %in% rownames(installed.packages())]
if (length(new_pkgs)) {
install.packages(new_pkgs, repos = "https://cran.r-project.org")
}
suppressWarnings(suppressPackageStartupMessages({
library(tidyverse)
library(biotools)
library(car)
library(heplots)
library(psych)
library(ggplot2)
library(knitr)
library(kableExtra)
library(MVN)
library(emmeans)
library(effectsize)
}))
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE,
fig.align = "center", fig.width = 9,
fig.height = 5, dpi = 150)
theme_set(
theme_minimal(base_size = 13) +
theme(plot.title = element_text(face = "bold", color = "#1a5276"),
plot.subtitle = element_text(color = "#566573"),
axis.title = element_text(color = "#2c3e50"),
strip.text = element_text(face = "bold"))
)if (!file.exists('education_intervention_10000.csv')) {
download.file(
'https://drive.google.com/uc?id=1cJlEWjZHdfqlM0r43GFbyQXf_MN0_zJk',
'education_intervention_10000.csv', mode = 'wb'
)
}
df_raw <- read.csv("education_intervention_10000.csv", sep = ",", stringsAsFactors = TRUE)
cat("Dimensi data mentah:", dim(df_raw), "\n")## Dimensi data mentah: 10000 16
## student_id school_id grade_level intervention ses_index attendance_rate
## 1 93207890 110 9 blended 1.379 0.996
## 2 61581758 128 11 blended 2.037 0.930
## 3 75844861 158 9 tutoring 0.403 0.933
## 4 57564202 153 9 flipped -0.442 0.924
## 5 57864707 100 12 tutoring -0.572 0.971
## 6 78728520 100 11 blended -1.128 0.875
## study_hours_wk teacher_experience_years class_size baseline_math
## 1 5.93 0.0 28 76.9
## 2 2.52 6.7 32 78.9
## 3 5.32 8.3 23 69.4
## 4 5.26 9.2 30 55.9
## 5 7.47 10.6 21 55.3
## 6 4.12 15.7 25 59.4
## baseline_reading baseline_motivation_1_10 post_math post_reading
## 1 65.3 7.7 87.8 75.1
## 2 82.3 7.1 88.9 89.0
## 3 83.9 5.8 84.8 95.2
## 4 61.8 6.7 72.7 68.3
## 5 66.4 4.6 75.7 83.4
## 6 67.2 7.4 69.1 78.9
## test_anxiety_1_10 passed
## 1 2.6 1
## 2 4.3 1
## 3 3.8 1
## 4 5.6 1
## 5 7.6 1
## 6 6.8 0
DVS <- c("post_math", "post_reading")
COV <- c("ses_index", "attendance_rate",
"study_hours_wk", "teacher_experience_years",
"class_size", "baseline_math",
"baseline_reading", "baseline_motivation_1_10",
"test_anxiety_1_10")
IV <- c("intervention", "grade_level")
df <- df_raw %>%
dplyr::select(all_of(c(IV, DVS, COV))) %>%
drop_na() %>%
mutate(intervention = as.factor(intervention),
grade_level = as.factor(grade_level))
cat("Dimensi setelah seleksi & drop_na:", dim(df), "")## Dimensi setelah seleksi & drop_na: 10000 13
## intervention grade_level post_math post_reading
## blended :2229 9 :2766 Min. : 29.7 Min. : 35.90
## control :2992 10:2547 1st Qu.: 71.9 1st Qu.: 72.50
## flipped :2207 11:2448 Median : 81.4 Median : 81.40
## tutoring:2572 12:2239 Mean : 80.9 Mean : 80.87
## 3rd Qu.: 91.5 3rd Qu.: 90.20
## Max. :100.0 Max. :100.00
## ses_index attendance_rate study_hours_wk teacher_experience_years
## Min. :-2.500000 Min. :0.6670 Min. : 0.020 Min. : 0.000
## 1st Qu.:-0.678250 1st Qu.:0.8730 1st Qu.: 2.250 1st Qu.: 5.600
## Median : 0.001000 Median :0.9160 Median : 3.910 Median : 9.000
## Mean :-0.002791 Mean :0.9129 Mean : 4.576 Mean : 9.057
## 3rd Qu.: 0.671000 3rd Qu.:0.9570 3rd Qu.: 6.140 3rd Qu.:12.400
## Max. : 2.500000 Max. :1.0000 Max. :22.850 Max. :28.700
## class_size baseline_math baseline_reading baseline_motivation_1_10
## Min. :10.00 Min. : 20.00 Min. : 23.30 Min. : 1.000
## 1st Qu.:22.00 1st Qu.: 61.00 1st Qu.: 63.60 1st Qu.: 5.300
## Median :26.00 Median : 70.00 Median : 71.80 Median : 6.500
## Mean :26.06 Mean : 70.03 Mean : 71.77 Mean : 6.456
## 3rd Qu.:30.00 3rd Qu.: 79.20 3rd Qu.: 79.92 3rd Qu.: 7.600
## Max. :40.00 Max. :100.00 Max. :100.00 Max. :10.000
## test_anxiety_1_10
## Min. : 1.000
## 1st Qu.: 3.700
## Median : 4.800
## Mean : 4.764
## 3rd Qu.: 5.900
## Max. :10.000
hist(df$post_math,
main = "Distribusi Nilai Matematika",
xlab = "Kategori",
ylab = "Frekuensi",
col = "lightblue",
border = "white")hist(df$post_reading,
main = "Distribusi Nilai Membaca",
xlab = "Kategori",
ylab = "Frekuensi",
col = "lightblue",
border = "white")
# Box Plot
MD <- mahalanobis(df[, DVS], colMeans(df[, DVS]), cov(df[, DVS]))
threshold <- qchisq(0.95, df = length(DVS))
df_clean <- df[MD < threshold, ]
cat("Outlier dibuang:", nrow(df) - nrow(df_clean), "baris\n")## Outlier dibuang: 365 baris
## Sisa observasi : 9635
mardia_res <- psych::mardia(df[, DVS], plot = FALSE)
p_skew <- mardia_res$p.skew
p_kurt <- mardia_res$p.kurt
tibble(
Komponen = c("Mardia Skewness", "Mardia Kurtosis"),
Statistik = c(round(mardia_res$b1p, 4), round(mardia_res$b2p, 4)),
`p-value` = c(format(p_skew, scientific = TRUE, digits = 3),
format(p_kurt, scientific = TRUE, digits = 3)),
Status = c(ifelse(p_skew >= 0.05, "✔ Normal", "✘ Tidak Normal"),
ifelse(p_kurt >= 0.05, "✔ Normal", "✘ Tidak Normal"))
) %>%
kable(caption = "Mardia's Test — Normalitas Multivariat") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
column_spec(4, bold = TRUE,
color = ifelse(c(p_skew, p_kurt) >= 0.05, "#1e8449", "#c0392b"))| Komponen | Statistik | p-value | Status |
|---|---|---|---|
| Mardia Skewness | 0.0786 | 2.51e-26 | ✘ Tidak Normal |
| Mardia Kurtosis | 6.3236 | 0e+00 | ✘ Tidak Normal |
## Mardia Skewness p-value: 2.51487e-26
## Mardia Kurtosis p-value: 0
P-value dari keduanya tidak memenuhi p-value ≥ 0.05, Namun pada teori Central Limit Theorem menjelaskan bahwa data akan mendekati hasil distribusi normal saat jumlah data > 30 * variabel
jadi proses pengujian akan dilanjutkan
## [1] 9635 13
Karena ada 9000+ data maka distribusinya akan mendekati normal
# Chi-Square Q-Q Plot (visualisasi normalitas multivariat)
MD_clean <- mahalanobis(df[, DVS], colMeans(df[, DVS]), cov(df[, DVS]))
chi2_q <- qchisq(ppoints(nrow(df)), df = length(DVS))
par(mar = c(4, 4, 3, 1))
qqplot(chi2_q, sort(MD_clean),
main = "Chi-Square Q-Q Plot — Normalitas Multivariat",
xlab = "Theoretical Chi-Square Quantiles",
ylab = "Mahalanobis Distance (sorted)",
pch = 16, col = "#2e86c1", cex = 0.5)
abline(0, 1, col = "#c0392b", lwd = 2)
legend("topleft", legend = c("Data", "Garis Referensi"),
col = c("#2e86c1", "#c0392b"), pch = c(16, NA),
lty = c(NA, 1), lwd = c(NA, 2), bty = "n")Pada distribusi multivariat QQ plot seluruh fitur cenderung left skew
faktor <- interaction(df$intervention, df$grade_level)
bm <- biotools::boxM(df[, DVS], faktor)
print(bm)##
## Box's M-test for Homogeneity of Covariance Matrices
##
## data: df[, DVS]
## Chi-Sq (approx.) = 41.692, df = 45, p-value = 0.6129
## Box's M p-value: 0.6129
if (bm$p.value > 0.05) {
cat(" Gagal tolak H0 Matriks kovarians HOMOGEN ")
} else if (bm$p.value < 0.01) {
cat(" Tolak H0 Matriks kovarians TIDAK homogen")
} else {
cat(" Tolak H0 ")
}## Gagal tolak H0 Matriks kovarians HOMOGEN
Karena p-value ≥ 0.05 menunjukkan tidak ada perbedaan signifikan antara matriks kovarians antar kelompok. Maka Asumsi 2 Terpenuhi
R_matrix <- cor(df[, DVS])
sphericity <- psych::cortest.bartlett(R_matrix, n = nrow(df))
tibble(
Statistik = c("Chi-square", "Degrees of Freedom", "p-value"),
Nilai = c(round(sphericity$chisq, 3),
sphericity$df,
format(sphericity$p.value, scientific = TRUE, digits = 3))
) %>%
kable(caption = "Bartlett's Test of Sphericity") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Statistik | Nilai |
|---|---|
| Chi-square | 371.738 |
| Degrees of Freedom | 1 |
| p-value | 7.83e-83 |
Memenuhi asumsi 3 karena p-value = 7.83e-83 < 0.05 → H₀ ditolak → DV berkorelasi secara signifikan. ASUMSI 3 TERPENUHI
## Korelasi Pearson: Kovariat vs DV
## Korelasi (r):
## post_math post_reading
## ses_index 0.405 0.369
## attendance_rate 0.062 0.070
## study_hours_wk 0.163 0.145
## teacher_experience_years 0.052 0.051
## class_size -0.066 -0.045
## baseline_math 0.916 0.172
## baseline_reading 0.167 0.920
## baseline_motivation_1_10 0.172 0.173
## test_anxiety_1_10 -0.072 -0.080
## P-value:
## post_math post_reading
## ses_index 0 0
## attendance_rate 0 0
## study_hours_wk 0 0
## teacher_experience_years 0 0
## class_size 0 0
## baseline_math 0 0
## baseline_reading 0 0
## baseline_motivation_1_10 0 0
## test_anxiety_1_10 0 0
sig_math <- sum(lin_test$p[, "post_math"] < 0.05, na.rm = TRUE)
sig_reading <- sum(lin_test$p[, "post_reading"] < 0.05, na.rm = TRUE)
cat("Kovariat signifikan (p<0.05) terhadap post_math :", sig_math, "/", length(COV), "")## Kovariat signifikan (p<0.05) terhadap post_math : 9 / 9
## Kovariat signifikan (p<0.05) terhadap post_reading: 9 / 9
fitur dengan korelasi rata-rata tertinggi
baseline_reading
baseline_math
ses_index
# Scatter: dua kovariat utama vs DV (representatif)
p1 <- ggplot(df, aes(x = baseline_math, y = post_math, color = intervention)) +
geom_point(alpha = 0.15, size = 0.8) +
geom_smooth(method = "lm", se = TRUE, linewidth = 1.1) +
labs(title = "Linearitas: Baseline Math → Post Math",
x = "Baseline Math (z)", y = "Post Math (z)") +
theme(legend.position = "bottom")
p2 <- ggplot(df, aes(x = baseline_reading, y = post_reading, color = intervention)) +
geom_point(alpha = 0.15, size = 0.8) +
geom_smooth(method = "lm", se = TRUE, linewidth = 1.1) +
labs(title = "Linearitas: Baseline Reading → Post Reading",
x = "Baseline Reading (z)", y = "Post Reading (z)") +
theme(legend.position = "bottom")
gridExtra::grid.arrange(p1, p2, ncol = 2)slope_model <- manova(
cbind(post_math, post_reading) ~
intervention * baseline_math +
intervention * baseline_reading,
data = df
)
cat("Uji Paralelisme Slope (Interaction Test)")## Uji Paralelisme Slope (Interaction Test)
## Df Pillai approx F num Df den Df Pr(>F)
## intervention 3 0.15697 273.2 6 19246 < 2.2e-16 ***
## baseline_math 1 0.85670 28762.7 2 9622 < 2.2e-16 ***
## baseline_reading 1 0.85453 28260.4 2 9622 < 2.2e-16 ***
## intervention:baseline_math 3 0.00321 5.2 6 19246 2.615e-05 ***
## intervention:baseline_reading 3 0.00263 4.2 6 19246 0.0002966 ***
## Residuals 9623
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Univariat: interaksi pada post_math
m_math <- lm(post_math ~ intervention * baseline_math +
intervention * baseline_reading, data = df)
print(Anova(m_math, type = "III"))## Anova Table (Type III tests)
##
## Response: post_math
## Sum Sq Df F value Pr(>F)
## (Intercept) 6.73 1 47.2910 6.50e-12 ***
## intervention 171.16 3 400.7147 < 2.2e-16 ***
## baseline_math 1763.08 1 12383.3068 < 2.2e-16 ***
## baseline_reading 1.45 1 10.1893 0.001417 **
## intervention:baseline_math 4.27 3 10.0004 1.41e-06 ***
## intervention:baseline_reading 1.29 3 3.0118 0.028875 *
## Residuals 1370.08 9623
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Univariat: interaksi pada post_reading
m_read <- lm(post_reading ~ intervention * baseline_math +
intervention * baseline_reading, data = df)
print(Anova(m_read, type = "III"))## Anova Table (Type III tests)
##
## Response: post_reading
## Sum Sq Df F value Pr(>F)
## (Intercept) 8.36 1 59.6782 1.229e-14 ***
## intervention 123.37 3 293.5543 < 2.2e-16 ***
## baseline_math 0.74 1 5.2719 0.021694 *
## baseline_reading 1720.56 1 12282.5244 < 2.2e-16 ***
## intervention:baseline_math 0.32 3 0.7632 0.514558
## intervention:baseline_reading 2.13 3 5.0749 0.001643 **
## Residuals 1348.01 9623
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
intervention:baseline_math (\(p = 2.615e-05 < 0.05\)):
Signifikan
intervention:baseline_reading
(\(p = 0.0002966 < 0.05\)):
Signifikan
Status: Asumsi multivariat gagal terpenuhi.
post_math)intervention:baseline_math (\(p = 1.41e-06 < 0.05\)):
Signifikan
intervention:baseline_reading
(\(p = 0.028875 < 0.05\)):
Signifikan
Status: Asumsi gagal terpenuhi untuk variabel Matematika.
post_reading)intervention:baseline_math (\(p = 0.514558 > 0.05\)): Tidak ada
interaksi yang signifikan
intervention:baseline_reading
(\(p = 0.001643 < 0.05\)):
Signifikan.
Status: Gagal terpenuhi karena salah satu kovariat utamanya masih memiliki garis yang menyilang
df_linear <- df %>%
filter(baseline_math >= -1.0 & baseline_math <= 1.0) %>%
filter(baseline_reading >= -1.0 & baseline_reading <= 1.0)
cat("Dimensi setelah filter rentang linear:", dim(df_linear), "\n")## Dimensi setelah filter rentang linear: 4270 13
## Proporsi data dipertahankan: 44.3 %
## Uji Paralelisme Slope (Interaction Test) setelah filter linear
## Df Pillai approx F num Df den Df Pr(>F)
## intervention 3 0.15697 273.2 6 19246 < 2.2e-16 ***
## baseline_math 1 0.85670 28762.7 2 9622 < 2.2e-16 ***
## baseline_reading 1 0.85453 28260.4 2 9622 < 2.2e-16 ***
## intervention:baseline_math 3 0.00321 5.2 6 19246 2.615e-05 ***
## intervention:baseline_reading 3 0.00263 4.2 6 19246 0.0002966 ***
## Residuals 9623
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Univariat: interaksi pada post_math
m_math <- lm(post_math ~ intervention * baseline_math +
intervention * baseline_reading, data = df)
print(Anova(m_math, type = "III"))## Anova Table (Type III tests)
##
## Response: post_math
## Sum Sq Df F value Pr(>F)
## (Intercept) 9.01 1 63.9086 1.665e-15 ***
## intervention 95.78 3 226.3554 < 2.2e-16 ***
## baseline_math 272.20 1 1929.9464 < 2.2e-16 ***
## baseline_reading 1.09 1 7.7629 0.005357 **
## intervention:baseline_math 0.11 3 0.2525 0.859605
## intervention:baseline_reading 0.69 3 1.6368 0.178642
## Residuals 600.56 4258
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Univariat: interaksi pada post_reading
m_read <- lm(post_reading ~ intervention * baseline_math +
intervention * baseline_reading, data = df)
print(Anova(m_read, type = "III"))## Anova Table (Type III tests)
##
## Response: post_reading
## Sum Sq Df F value Pr(>F)
## (Intercept) 8.69 1 60.2616 1.033e-14 ***
## intervention 57.32 3 132.4557 < 2.2e-16 ***
## baseline_math 0.22 1 1.4972 0.2212
## baseline_reading 294.24 1 2039.6377 < 2.2e-16 ***
## intervention:baseline_math 0.25 3 0.5857 0.6243
## intervention:baseline_reading 0.07 3 0.1592 0.9238
## Residuals 614.26 4258
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
intervention:baseline_math (\(p = 2.615e-05 < 0.05\)):
Signifikan
intervention:baseline_reading
(\(p = 0.0002966 < 0.05\)):
Signifikan
Status: Asumsi multivariat gagal terpenuhi.
post_math)intervention:baseline_math (\(p = 0.859605 > 0.05\)): Tidak ada
interaksi yang signifikan
intervention:baseline_reading
(\(p = 0.178642 > 0.05\)): Tidak
ada interaksi yang signifikan
Status: Terpenuhi, karena tidak ada garis yang menyilang. Pengaruh nilai awal matematika dan membaca terhadap nilai akhir matematika berlaku sama rata untuk semua metode belajar
post_reading)intervention:baseline_math (\(p = 0.6243 > 0.05\)): Tidak ada
interaksi yang signifikan
intervention:baseline_reading
(\(p = 0.9238 > 0.05\)): Tidak ada
interaksi yang signifikan.
Status: Terpenuhi, kemiringan garis regresi sudah sejajar (paralel) secara sempurna.
Asumsi 5 Terpenuhi
fit_manova <- manova(
cbind(post_math, post_reading) ~ intervention + grade_level,
data = df
)
cat("MANOVA (Pillai's Trace)")## MANOVA (Pillai's Trace)
## Df Pillai approx F num Df den Df Pr(>F)
## intervention 3 0.071985 53.055 6 8526 <2e-16 ***
## grade_level 3 0.001314 0.934 6 8526 0.4689
## Residuals 4263
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Follow-up Univariat MANOVA
## Response post_math :
## Df Sum Sq Mean Sq F value Pr(>F)
## intervention 3 105.13 35.044 79.3029 <2e-16 ***
## grade_level 3 0.48 0.160 0.3626 0.7801
## Residuals 4263 1883.83 0.442
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Response post_reading :
## Df Sum Sq Mean Sq F value Pr(>F)
## intervention 3 56.69 18.8950 42.7074 <2e-16 ***
## grade_level 3 1.78 0.5934 1.3413 0.2591
## Residuals 4263 1886.08 0.4424
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Effect Size MANOVA (η² parsial)
## # Effect Size for ANOVA (Type I)
##
## Parameter | Eta2 (partial) | 95% CI
## --------------------------------------------
## intervention | 0.04 | [0.03, 1.00]
## grade_level | 6.57e-04 | [0.00, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
Pillai’s Trace: Faktor intervention memiliki nilai \(p < 2.2 \times 10^{-16}\) (signifikan), sedangkan grade_level tidak signifikan (\(p = 0.4689\)).
Follow-up Univariat: Intervensi berpengaruh nyata baik pada nilai matematika maupun membaca secara terpisah.
Effect Size (\(\eta^2\)): Nilai \(\eta^2\) parsial untuk intervensi hanya 0.04 (4%). Artinya, tanpa kontrol variabel lain, metode belajar hanya menjelaskan 4% variasi nilai siswa. Sisanya masih menjadi “misteri” (galat).
fit_mancova <- manova(
cbind(post_math, post_reading) ~
baseline_math + baseline_reading + ses_index +
intervention + grade_level,
data = df
)
cat( "MANCOVA (Pillai's Trace)")## MANCOVA (Pillai's Trace)
## Df Pillai approx F num Df den Df Pr(>F)
## baseline_math 1 0.68274 4582.6 2 4259 < 2.2e-16 ***
## baseline_reading 1 0.67407 4404.2 2 4259 < 2.2e-16 ***
## ses_index 1 0.00360 7.7 2 4259 0.0004579 ***
## intervention 3 0.18884 148.1 6 8520 < 2.2e-16 ***
## grade_level 3 0.00090 0.6 6 8520 0.6963856
## Residuals 4260
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Follow-up Univariat MANCOVA
## Response post_math :
## Df Sum Sq Mean Sq F value Pr(>F)
## baseline_math 1 1291.20 1291.20 9167.2192 < 2.2e-16 ***
## baseline_reading 1 0.91 0.91 6.4595 0.011071 *
## ses_index 1 1.09 1.09 7.7099 0.005516 **
## intervention 3 96.13 32.04 227.5112 < 2.2e-16 ***
## grade_level 3 0.09 0.03 0.2100 0.889535
## Residuals 4260 600.02 0.14
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Response post_reading :
## Df Sum Sq Mean Sq F value Pr(>F)
## baseline_math 1 12.69 12.69 88.2546 < 2.2e-16 ***
## baseline_reading 1 1259.72 1259.72 8759.5765 < 2.2e-16 ***
## ses_index 1 1.33 1.33 9.2772 0.002334 **
## intervention 3 57.69 19.23 133.7211 < 2.2e-16 ***
## grade_level 3 0.48 0.16 1.1130 0.342366
## Residuals 4260 612.63 0.14
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Effect Size MANCOVA (n2 parsial)
## # Effect Size for ANOVA (Type I)
##
## Parameter | Eta2 (partial) | 95% CI
## ------------------------------------------------
## baseline_math | 0.68 | [0.67, 1.00]
## baseline_reading | 0.67 | [0.66, 1.00]
## ses_index | 3.60e-03 | [0.00, 1.00]
## intervention | 0.09 | [0.08, 1.00]
## grade_level | 4.52e-04 | [0.00, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
Signifikansi Kovariat: Ketiga kovariat (baseline_math, baseline_reading, ses_index) sangat signifikan (\(p < 0.001\)). Ini membuktikan bahwa kemampuan awal dan ekonomi siswa memang mendikte hasil akhir.
Peningkatan Effect Size: Setelah kemampuan awal dikontrol, \(\eta^2\) untuk intervention melonjak menjadi 0.09 (9%). Ini bukti bahwa metode belajar aslinya lebih efektif daripada yang terlihat di MANOVA biasa, karena bias kemampuan awal sudah dihilangkan.
formula_full <- as.formula(
paste("cbind(post_math, post_reading) ~",
paste(COV, collapse = " + "),
"+ intervention + grade_level")
)
fit_mancova_full <- manova(formula_full, data = df)
cat("MANCOVA LENGKAP — Semua Kovariat (Pillai's Trace)")## MANCOVA LENGKAP — Semua Kovariat (Pillai's Trace)
## Df Pillai approx F num Df den Df Pr(>F)
## ses_index 1 0.23601 656.9 2 4253 < 2.2e-16 ***
## attendance_rate 1 0.00426 9.1 2 4253 0.0001140 ***
## study_hours_wk 1 0.09622 226.4 2 4253 < 2.2e-16 ***
## teacher_experience_years 1 0.06120 138.6 2 4253 < 2.2e-16 ***
## class_size 1 0.04063 90.1 2 4253 < 2.2e-16 ***
## baseline_math 1 0.68996 4732.2 2 4253 < 2.2e-16 ***
## baseline_reading 1 0.67735 4464.1 2 4253 < 2.2e-16 ***
## baseline_motivation_1_10 1 0.00335 7.1 2 4253 0.0007986 ***
## test_anxiety_1_10 1 0.00099 2.1 2 4253 0.1210167
## intervention 3 0.21491 170.7 6 8508 < 2.2e-16 ***
## grade_level 3 0.00090 0.6 6 8508 0.7002227
## Residuals 4254
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Effect Size MANCOVA Lengkap
## # Effect Size for ANOVA (Type I)
##
## Parameter | Eta2 (partial) | 95% CI
## --------------------------------------------------------
## ses_index | 0.24 | [0.22, 1.00]
## attendance_rate | 4.26e-03 | [0.00, 1.00]
## study_hours_wk | 0.10 | [0.08, 1.00]
## teacher_experience_years | 0.06 | [0.05, 1.00]
## class_size | 0.04 | [0.03, 1.00]
## baseline_math | 0.69 | [0.68, 1.00]
## baseline_reading | 0.68 | [0.67, 1.00]
## baseline_motivation_1_10 | 3.35e-03 | [0.00, 1.00]
## test_anxiety_1_10 | 9.93e-04 | [0.00, 1.00]
## intervention | 0.11 | [0.10, 1.00]
## grade_level | 4.49e-04 | [0.00, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
Kekuatan SES: Perhatikan bahwa ses_index memiliki \(\eta^2\) sebesar 0.24. Ini pengaruh yang sangat besar! Status ekonomi menyumbang 24% terhadap hasil ujian siswa.
Optimasi Model: Hampir semua kovariat signifikan kecuali test_anxiety (\(p = 0.12\)). Efek intervensi naik lagi ke angka 0.11 (11%). Model ini jauh lebih presisi dalam mengisolasi efek murni dari metode pembelajaran.
fit_ancova_math <- lm(
post_math ~ baseline_math + baseline_reading + ses_index +
intervention + grade_level,
data = df
)
cat("\n ANCOVA: post_math")##
## ANCOVA: post_math
## Anova Table (Type III tests)
##
## Response: post_math
## Sum Sq Df F value Pr(>F)
## (Intercept) 6.21 1 44.0840 3.541e-11 ***
## baseline_math 1187.03 1 8427.6544 < 2.2e-16 ***
## baseline_reading 0.52 1 3.6743 0.055324 .
## ses_index 1.23 1 8.7669 0.003084 **
## intervention 95.94 3 227.0565 < 2.2e-16 ***
## grade_level 0.09 3 0.2100 0.889535
## Residuals 600.02 4260
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Effect Size ANCOVA post_math
## # Effect Size for ANOVA (Type I)
##
## Parameter | Eta2 (partial) | 95% CI
## ------------------------------------------------
## baseline_math | 0.68 | [0.67, 1.00]
## baseline_reading | 1.51e-03 | [0.00, 1.00]
## ses_index | 1.81e-03 | [0.00, 1.00]
## intervention | 0.14 | [0.12, 1.00]
## grade_level | 1.48e-04 | [0.00, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
## Estimated Marginal Means: post_math × intervention
## intervention emmean SE df lower.CL upper.CL
## blended 0.0904 0.0121 4260 0.066653 0.1142
## control -0.1631 0.0107 4260 -0.184003 -0.1421
## flipped 0.0239 0.0120 4260 0.000321 0.0475
## tutoring 0.2367 0.0114 4260 0.214396 0.2589
##
## Results are averaged over the levels of: grade_level
## Confidence level used: 0.95
## contrast estimate SE df t.ratio p.value
## blended - control 0.2535 0.0162 4260 15.692 <0.0001
## blended - flipped 0.0665 0.0171 4260 3.899 0.0006
## blended - tutoring -0.1462 0.0166 4260 -8.812 <0.0001
## control - flipped -0.1870 0.0161 4260 -11.623 <0.0001
## control - tutoring -0.3997 0.0156 4260 -25.656 <0.0001
## flipped - tutoring -0.2128 0.0165 4260 -12.875 <0.0001
##
## Results are averaged over the levels of: grade_level
## P value adjustment: bonferroni method for 6 tests
Kontributor Terbesar: baseline_math (\(\eta^2 = 0.68\)) dan intervention (\(\eta^2 = 0.14\)).
Estimated Marginal Means (EMM): Ini adalah nilai “adil” setelah semua siswa disetarakan kondisi awalnya.Tutoring (0.236): Juara 1 (tertinggi).Blended (0.090): Posisi kedua.Control (-0.163): Paling rendah (di bawah rata-rata).
Pairwise Comparison: Semua metode memiliki perbedaan yang signifikan satu sama lain (\(p < 0.0001\)). ### ANCOVA untuk Post Reading
fit_ancova_read <- lm(
post_reading ~ baseline_math + baseline_reading + ses_index +
intervention + grade_level,
data = df
)
cat(" ANCOVA: post_reading")## ANCOVA: post_reading
## Anova Table (Type III tests)
##
## Response: post_reading
## Sum Sq Df F value Pr(>F)
## (Intercept) 4.89 1 34.0130 5.88e-09 ***
## baseline_math 0.73 1 5.1098 0.023841 *
## baseline_reading 1192.41 1 8291.5409 < 2.2e-16 ***
## ses_index 1.49 1 10.3942 0.001274 **
## intervention 57.55 3 133.3945 < 2.2e-16 ***
## grade_level 0.48 3 1.1130 0.342366
## Residuals 612.63 4260
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Effect Size ANCOVA post_reading
## # Effect Size for ANOVA (Type I)
##
## Parameter | Eta2 (partial) | 95% CI
## ------------------------------------------------
## baseline_math | 0.02 | [0.01, 1.00]
## baseline_reading | 0.67 | [0.66, 1.00]
## ses_index | 2.17e-03 | [0.00, 1.00]
## intervention | 0.09 | [0.07, 1.00]
## grade_level | 7.83e-04 | [0.00, 1.00]
##
## - One-sided CIs: upper bound fixed at [1.00].
## Estimated Marginal Means: post_reading × intervention
## intervention emmean SE df lower.CL upper.CL
## blended 0.0839 0.0122 4260 0.05992 0.1080
## control -0.1499 0.0108 4260 -0.17108 -0.1288
## flipped 0.0169 0.0122 4260 -0.00698 0.0407
## tutoring 0.1482 0.0115 4260 0.12575 0.1707
##
## Results are averaged over the levels of: grade_level
## Confidence level used: 0.95
## contrast estimate SE df t.ratio p.value
## blended - control 0.2339 0.0163 4260 14.328 <0.0001
## blended - flipped 0.0671 0.0172 4260 3.892 0.0006
## blended - tutoring -0.0643 0.0168 4260 -3.835 0.0008
## control - flipped -0.1668 0.0163 4260 -10.260 <0.0001
## control - tutoring -0.2982 0.0157 4260 -18.940 <0.0001
## flipped - tutoring -0.1314 0.0167 4260 -7.869 <0.0001
##
## Results are averaged over the levels of: grade_level
## P value adjustment: bonferroni method for 6 tests
Kontributor Terbesar: baseline_reading (\(\eta^2 = 0.67\)) dan intervention (\(\eta^2 = 0.09\)).
EMM: * Tutoring (0.148): Tetap yang terbaik untuk literasi.Blended (0.083): Konsisten di posisi kedua.
# Ekstrak n2 dari masing-masing model
get_eta <- function(model, label) {
es <- tryCatch(eta_squared(model, partial = TRUE), error = function(e) NULL)
if (is.null(es)) return(NULL)
es %>%
as.data.frame() %>%
mutate(Model = label) %>%
dplyr::select(Model, Parameter, Eta2_partial)
}
eta_mv <- get_eta(fit_manova, "MANOVA (tanpa kovariat)")
eta_mc <- get_eta(fit_mancova, "MANCOVA (3 kovariat)")
eta_mcf <- get_eta(fit_mancova_full, "MANCOVA Lengkap (9 kovariat)")
tbl_compare <- bind_rows(eta_mv, eta_mc, eta_mcf) %>%
pivot_wider(names_from = Model, values_from = Eta2_partial)
cat("Perbandingan η² Parsial: MANOVA vs MANCOVA")## Perbandingan η² Parsial: MANOVA vs MANCOVA
knitr::kable(tbl_compare, digits = 4,
caption = "n2 parsial tiap prediktor di setiap model") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)| Parameter | MANOVA (tanpa kovariat) | MANCOVA (3 kovariat) | MANCOVA Lengkap (9 kovariat) |
|---|---|---|---|
| intervention | 0.0360 | 0.0944 | 0.1075 |
| grade_level | 0.0007 | 0.0005 | 0.0004 |
| baseline_math | NA | 0.6827 | 0.6900 |
| baseline_reading | NA | 0.6741 | 0.6773 |
| ses_index | NA | 0.0036 | 0.2360 |
| attendance_rate | NA | NA | 0.0043 |
| study_hours_wk | NA | NA | 0.0962 |
| teacher_experience_years | NA | NA | 0.0612 |
| class_size | NA | NA | 0.0406 |
| baseline_motivation_1_10 | NA | NA | 0.0033 |
| test_anxiety_1_10 | NA | NA | 0.0010 |
MANOVA (0.0360) \(\rightarrow\) MANCOVA Lengkap (0.1075)
Pada model MANOVA biasa, metode intervensi hanya terlihat menyumbang 3,6% terhadap variasi nilai. Namun, setelah memasukkan semua kovariat (9 fitur), kekuatannya melonjak menjadi 10,75%. Hal ini membuktikan bahwa tanpa kovariat, efek asli dari metode belajar tertutup oleh kebisingan (noise) dari latar belakang siswa. Dengan mengontrol variabel seperti kemampuan awal dan SES, berhasil mengisolasi efek murni dari intervensi tersebut.
Nilai: \(\approx 0.67 - 0.69\) (67% - 69%)
Kedua fitur ini adalah sangat mempengaruhi dalam nilai ujiannya. Dengan nilai sekitar 0,67 menunjukkan bahwa sekitar 67% variasi nilai akhir siswa ditentukan oleh seberapa baik kemampuan mereka di awal. Ini menunjukkan adanya hubungan akademik yang sangat kuat; siswa yang memiliki fondasi belajar yang kuat di awal cenderung tetap unggul di akhir.
MANCOVA 3 Cov (0.0036) \(\rightarrow\) MANCOVA Lengkap (0.2360)
Ada lonjakan drastis pada faktor status sosial ekonomi. Pada model lengkap, SES menyumbang 23,6% terhadap variasi nilai.Maknanya: Pengaruh ekonomi siswa baru terlihat murni dan sangat besar ketika faktor pendukung lainnya (seperti pengalaman guru dan jam belajar) juga dimasukkan ke dalam perhitungan. Ini menunjukkan bahwa latar belakang ekonomi adalah faktor penentu kedua terbesar setelah kemampuan awal.
Nilai: \(0.0007 \rightarrow 0.0004\)
Nilai ini mendekati nol dan terus menurun. Hal ini membuktikan bahwa tingkat kelas (9, 10, 11, 12) tidak memiliki pengaruh praktis terhadap nilai ujian dalam penelitian ini. Perbedaan performa lebih disebabkan oleh metode belajar dan latar belakang individu, bukan karena mereka berada di kelas berapa.
study_hours_wk (0.0962): Jam belajar menyumbang sekitar 9,6%, hampir setara dengan kekuatan metode intervensi. Ini menunjukkan kedisiplinan belajar mandiri sangat berpengaruh.
teacher_experience_years (0.0612): Pengalaman guru menyumbang 6,1%, menegaskan bahwa kualitas pengajar memiliki andil yang cukup berarti.
# Bandingkan statistik Pillai (kekuatan efek multivariat faktor utama)
extract_pillai <- function(model, label) {
sm <- summary(model, test = "Pillai")$stats
sm_df <- as.data.frame(sm)
sm_df$Term <- rownames(sm_df)
sm_df$Model <- label
sm_df %>%
filter(Term %in% c("intervention", "grade_level")) %>%
dplyr::select(Model, Term,
Pillai = `Pillai`,
F = `approx F`,
p = `Pr(>F)`)
}
tbl_pillai <- bind_rows(
extract_pillai(fit_manova, "MANOVA"),
extract_pillai(fit_mancova, "MANCOVA (3 cov)"),
extract_pillai(fit_mancova_full, "MANCOVA Lengkap")
)
cat("Pillai's Trace Faktor Utama: MANOVA vs MANCOVA")## Pillai's Trace Faktor Utama: MANOVA vs MANCOVA
knitr::kable(tbl_pillai, digits = 4,
caption = "Perbandingan Pillai's Trace untuk intervention & grade_level") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)| Model | Term | Pillai | F | p | |
|---|---|---|---|---|---|
| intervention…1 | MANOVA | intervention | 0.0720 | 53.0549 | 0.0000 |
| grade_level…2 | MANOVA | grade_level | 0.0013 | 0.9342 | 0.4689 |
| intervention…3 | MANCOVA (3 cov) | intervention | 0.1888 | 148.0521 | 0.0000 |
| grade_level…4 | MANCOVA (3 cov) | grade_level | 0.0009 | 0.6424 | 0.6964 |
| intervention…5 | MANCOVA Lengkap | intervention | 0.2149 | 170.7173 | 0.0000 |
| grade_level…6 | MANCOVA Lengkap | grade_level | 0.0009 | 0.6376 | 0.7002 |
Signifikansi: Faktor intervention secara konsisten menunjukkan nilai \(p = 0.0000\) (\(p < 0.05\)) di semua model. Ini membuktikan bahwa metode pembelajaran memberikan dampak yang sangat nyata terhadap kombinasi nilai Matematika dan Membaca.
Kenaikan Pillai’s Trace: Perhatikan lonjakan nilainya: 0.0720 (MANOVA) \(\rightarrow\) 0.1888 (3 Kovariat) \(\rightarrow\) 0.2149 (9 Kovariat).
Maknanya: Semakin banyak kovariat yang dikontrol, semakin besar porsi varians yang dapat dijelaskan oleh model. Nilai Pillai yang naik 3x lipat membuktikan bahwa variabel perancu (seperti kemampuan awal dan SES) sebelumnya “menenggelamkan” efek asli dari metode intervensi.
Faktor grade_level: Nilai \(p\) selalu \(> 0.05\). Ini menegaskan bahwa perbedaan tingkat kelas tidak berkontribusi pada perbedaan prestasi akademik dalam studi ini.
# Visualisasi perbandingan n2 untuk faktor intervention
tbl_plot <- bind_rows(eta_mv, eta_mc, eta_mcf) %>%
filter(grepl("intervention|grade_level", Parameter))
ggplot(tbl_plot, aes(x = reorder(Model, Eta2_partial),
y = Eta2_partial, fill = Model)) +
geom_col(width = 0.6, show.legend = FALSE) +
geom_text(aes(label = round(Eta2_partial, 4)),
hjust = -0.1, size = 3.5) +
coord_flip() +
facet_wrap(~ Parameter, scales = "free_x") +
scale_fill_manual(values = c("#2e86c1","#27ae60","#e67e22")) +
labs(title = "Perbandingan η² Parsial: MANOVA vs MANCOVA",
subtitle = "Seberapa besar efek faktor berubah setelah kovariat dikontrol",
x = NULL, y = "η² Parsial") +
theme(axis.text.y = element_text(size = 9))
Efek Intervensi yang Tersembunyi: Pada bar intervention, terlihat
kenaikan dari 0.036 menjadi 0.107 (MANCOVA Lengkap).
Analisis: Tanpa kovariat, intervensi hanya menyumbang 3.6% terhadap nilai siswa. Setelah “noise” (latar belakang siswa) dibersihkan, efektivitas murni dari metode pembelajaran melonjak menjadi 10.7%. Ini adalah argumen kuat bahwa intervensi pendidikan sebenarnya sangat efektif, asalkan disparitas awal siswa disetarakan.
emm_math_df <- as.data.frame(emm_math) %>% mutate(DV = "Post Math")
emm_read_df <- as.data.frame(emm_read) %>% mutate(DV = "Post Reading")
emm_all <- bind_rows(emm_math_df, emm_read_df)
ggplot(emm_all, aes(x = intervention, y = emmean, fill = intervention)) +
geom_col(width = 0.5, show.legend = FALSE) +
geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL),
width = 0.15, linewidth = 0.8) +
facet_wrap(~ DV) +
scale_fill_manual(values = c("#2e86c1","#27ae60","#e67e22","#8e44ad")) +
labs(title = "Adjusted Means (ANCOVA) per Intervention",
subtitle = "Dengan kontrol: baseline_math, baseline_reading, ses_index",
x = "Tipe Intervensi", y = "Estimated Marginal Mean (z-score)") +
theme(axis.text.x = element_text(angle = 20, hjust = 1))
Tutoring sebagai MVP: Metode tutoring (warna ungu) secara konsisten
memiliki Estimated Marginal Mean tertinggi di kedua mata pelajaran
(\(\approx 0.23\) untuk Math dan \(\approx 0.15\) untuk Reading).
Blended Learning di Posisi Kedua: blended menunjukkan performa positif yang stabil di angka \(\approx 0.08 - 0.09\).
Kegagalan Kelompok Control: Kelompok control (tanpa intervensi) jatuh ke area negatif (\(\approx -0.16\)), membuktikan bahwa tanpa bantuan tambahan, capaian siswa cenderung berada di bawah rata-rata global.
Akurasi: Error bar yang relatif pendek menunjukkan bahwa estimasi rata-rata ini cukup presisi setelah dikontrol oleh kovariat.
df %>%
pivot_longer(cols = all_of(DVS), names_to = "DV", values_to = "Score") %>%
ggplot(aes(x = Score, fill = intervention)) +
geom_density(alpha = 0.5) +
facet_grid(DV ~ intervention) +
scale_fill_manual(values = c("#2e86c1","#27ae60","#e67e22","#8e44ad")) +
labs(title = "Distribusi Skor DV per Kelompok Intervention",
x = "Skor (z)", y = "Density") +
theme(legend.position = "none")
Pergeseran Kurva: Jika kamu perhatikan kurva tutoring, puncaknya lebih
condong ke arah kanan (angka positif) dibandingkan kelompok control. Ini
secara visual mengonfirmasi temuan pada EMM di atas.
Bentuk Distribusi: Distribusi pada hampir semua kelompok intervensi terlihat mengikuti pola bell-curve (normal), meskipun terdapat sedikit skewness (kemiringan). Namun, hal ini sudah terkompensasi oleh jumlah sampel yang besar sesuai dengan Central Limit Theorem.
Konsistensi: Pola sebaran pada Post Math dan Post Reading terlihat mirip, mengindikasikan bahwa intervensi yang berhasil pada matematika cenderung berhasil juga pada kemampuan membaca siswa.
Ketahanan Model: Meskipun uji Mardia (Normalitas) dan Homogenitas Slope awal menunjukkan penolakan \(H_0\), analisis tetap valid berkat penerapan Teorema Limit Pusat (CLT) dan penggunaan statistik Pillai’s Trace yang robust terhadap sampel besar.
Optimasi Data: Penggunaan filter rentang linear (\(df\_linear\)) berhasil menyejajarkan kemiringan garis regresi, sehingga asumsi Paralelisme Slope terpenuhi secara univariat, yang menjamin keakuratan estimasi rata-rata yang disesuaikan (Adjusted Means).
Dependensi Variabel: Uji Bartlett mengonfirmasi korelasi signifikan antara nilai Matematika dan Membaca, yang memvalidasi penggunaan MANCOVA dibandingkan uji univariat terpisah.
Isolasi Efek: Pada MANOVA, metode intervensi hanya menjelaskan 3,6% variasi nilai siswa. Namun, setelah variabel perancu (kovariat) dikontrol dalam model MANCOVA Lengkap, kekuatan efek murni intervensi melonjak menjadi 10,75%.
Koreksi Bias: Hal ini membuktikan bahwa tanpa kontrol terhadap kemampuan awal dan status ekonomi, efektivitas asli metode pembelajaran akan tertutup oleh “kebisingan” latar belakang siswa.
Tutoring : Secara konsisten memberikan hasil tertinggi pada Matematika (\(\approx 0,23\)) dan Membaca (\(\approx 0,15\)).
Blended Learning: Menempati posisi kedua dengan performa positif yang stabil di kedua mata pelajaran.
Flipped Classroom: Memberikan dampak positif namun berada pada margin yang jauh lebih rendah dibanding Tutoring.
Control: Kelompok tanpa intervensi secara signifikan berada di bawah rata-rata global (\(EMM \approx -0,16\)).
Kemampuan Awal (Baseline): Menyumbang sekitar 67%–69% terhadap hasil akhir, menunjukkan persistensi akademik yang sangat kuat.
Status Ekonomi (SES): Menyumbang 23,6% terhadap variasi nilai, menegaskan bahwa latar belakang finansial tetap menjadi penentu besar dalam akses kesuksesan pendidikan.Faktor Tidak Signifikan: Tingkat kelas (grade_level) terbukti tidak memberikan pengaruh nyata terhadap performa siswa (\(p > 0,05\)).
Untuk mengakselerasi capaian akademik secara adil, intervensi Tutoring dan Blended Learning harus diprioritaskan. Namun, evaluasi keberhasilan harus selalu menggunakan kontrol terhadap nilai awal dan SES agar hasil yang terlihat tidak bias oleh privilese ekonomi atau kemampuan bawaan siswa.