20-04-2026library(MVN) # Uji Multivariate Normality
library(biotools) # Box's M test
library(car) # Uji linearitas
data <- read.csv("collegiate_athlete_injury_dataset.csv", header = TRUE)
str(data)
## 'data.frame': 200 obs. of 17 variables:
## $ Athlete_ID : chr "A001" "A002" "A003" "A004" ...
## $ Age : int 24 21 22 24 20 22 22 24 19 20 ...
## $ Gender : chr "Female" "Male" "Male" "Female" ...
## $ Height_cm : int 195 192 163 192 173 180 179 167 166 162 ...
## $ Weight_kg : int 99 65 83 90 79 75 90 64 91 63 ...
## $ Position : chr "Center" "Forward" "Guard" "Guard" ...
## $ Training_Intensity : int 2 8 8 1 3 9 5 6 4 2 ...
## $ Training_Hours_Per_Week : int 13 14 8 13 9 14 13 7 19 8 ...
## $ Recovery_Days_Per_Week : int 2 1 2 1 1 3 1 2 2 3 ...
## $ Match_Count_Per_Week : int 3 3 1 1 2 4 4 3 3 3 ...
## $ Rest_Between_Events_Days: int 1 1 3 1 1 1 2 3 3 2 ...
## $ Fatigue_Score : int 1 4 6 7 2 6 7 2 2 7 ...
## $ Performance_Score : int 99 55 58 82 90 74 97 62 58 62 ...
## $ Team_Contribution_Score : int 58 63 62 74 51 84 56 70 67 52 ...
## $ Load_Balance_Score : int 100 83 100 78 83 99 78 100 80 100 ...
## $ ACL_Risk_Score : int 4 73 62 51 49 54 84 42 50 35 ...
## $ Injury_Indicator : int 0 0 0 0 0 0 1 0 0 0 ...
summary(data)
## Athlete_ID Age Gender Height_cm
## Length:200 Min. :18.00 Length:200 Min. :160.0
## Class :character 1st Qu.:19.00 Class :character 1st Qu.:171.0
## Mode :character Median :21.00 Mode :character Median :182.5
## Mean :21.17 Mean :180.8
## 3rd Qu.:23.00 3rd Qu.:191.0
## Max. :24.00 Max. :199.0
## Weight_kg Position Training_Intensity Training_Hours_Per_Week
## Min. :55.00 Length:200 Min. :1.000 Min. : 5.00
## 1st Qu.:67.00 Class :character 1st Qu.:3.000 1st Qu.: 7.00
## Median :77.50 Mode :character Median :5.000 Median :11.00
## Mean :77.47 Mean :5.105 Mean :11.31
## 3rd Qu.:89.00 3rd Qu.:7.000 3rd Qu.:15.00
## Max. :99.00 Max. :9.000 Max. :19.00
## Recovery_Days_Per_Week Match_Count_Per_Week Rest_Between_Events_Days
## Min. :1.000 Min. :1.000 Min. :1.000
## 1st Qu.:1.000 1st Qu.:1.000 1st Qu.:1.000
## Median :2.000 Median :2.000 Median :2.000
## Mean :1.985 Mean :2.385 Mean :1.975
## 3rd Qu.:3.000 3rd Qu.:3.000 3rd Qu.:3.000
## Max. :3.000 Max. :4.000 Max. :3.000
## Fatigue_Score Performance_Score Team_Contribution_Score Load_Balance_Score
## Min. :1.00 Min. :50.00 Min. :50.00 Min. : 62.00
## 1st Qu.:3.00 1st Qu.:62.00 1st Qu.:60.75 1st Qu.: 89.00
## Median :5.00 Median :74.00 Median :72.00 Median : 98.00
## Mean :4.92 Mean :74.47 Mean :72.63 Mean : 93.39
## 3rd Qu.:7.00 3rd Qu.:86.25 3rd Qu.:85.00 3rd Qu.:100.00
## Max. :9.00 Max. :99.00 Max. :99.00 Max. :100.00
## ACL_Risk_Score Injury_Indicator
## Min. : 2.00 Min. :0.00
## 1st Qu.: 33.00 1st Qu.:0.00
## Median : 45.00 Median :0.00
## Mean : 46.47 Mean :0.07
## 3rd Qu.: 60.00 3rd Qu.:0.00
## Max. :100.00 Max. :1.00
# Hapus missing values
data_clean <- na.omit(data)
# Faktorkan variabel grup (Position sebagai IV)
data_clean$Position <- as.factor(data_clean$Position)
cat("Dimensi data bersih:", nrow(data_clean), "baris,", ncol(data_clean), "kolom\n")
## Dimensi data bersih: 200 baris, 17 kolom
cat("Level Position:", levels(data_clean$Position), "\n")
## Level Position: Center Forward Guard
DV yang diuji: Load_Balance_Score & ACL_Risk_Score
dv <- data_clean[, c("Load_Balance_Score", "ACL_Risk_Score")]
mvn_result <- MVN::mvn(data = dv)
mvn_result
## $multivariate_normality
## Test Statistic p.value Method MVN
## 1 Henze-Zirkler 6.237 <0.001 asymptotic ✗ Not normal
##
## $univariate_normality
## Test Variable Statistic p.value Normality
## 1 Anderson-Darling Load_Balance_Score 16.108 <0.001 ✗ Not normal
## 2 Anderson-Darling ACL_Risk_Score 0.393 0.374 ✓ Normal
##
## $descriptives
## Variable n Mean Std.Dev Median Min Max 25th 75th Skew
## 1 Load_Balance_Score 200 93.395 8.660 98 62 100 89 100 -1.346
## 2 ACL_Risk_Score 200 46.470 18.944 45 2 100 33 60 0.205
## Kurtosis
## 1 4.082
## 2 2.758
##
## $data
## Load_Balance_Score ACL_Risk_Score
## 1 100 4
## 2 83 73
## 3 100 62
## 4 78 51
## 5 83 49
## 6 99 54
## 7 78 84
## 8 100 42
## 9 80 50
## 10 100 35
## 11 84 35
## 12 95 57
## 13 89 55
## 14 87 72
## 15 88 74
## 16 98 47
## 17 100 61
## 18 81 75
## 19 100 60
## 20 98 26
## 21 100 53
## 22 72 71
## 23 80 69
## 24 70 81
## 25 93 65
## 26 100 29
## 27 83 47
## 28 82 67
## 29 93 50
## 30 94 44
## 31 100 62
## 32 100 35
## 33 93 46
## 34 100 35
## 35 100 44
## 36 96 43
## 37 100 43
## 38 75 74
## 39 100 30
## 40 91 77
## 41 92 67
## 42 91 48
## 43 100 49
## 44 93 36
## 45 90 56
## 46 100 42
## 47 100 28
## 48 100 45
## 49 80 66
## 50 100 33
## 51 92 46
## 52 97 70
## 53 100 33
## 54 89 52
## 55 79 36
## 56 91 45
## 57 100 29
## 58 100 47
## 59 100 28
## 60 100 20
## 61 99 44
## 62 81 52
## 63 91 39
## 64 96 53
## 65 100 40
## 66 100 60
## 67 98 12
## 68 94 30
## 69 98 16
## 70 97 68
## 71 100 37
## 72 96 47
## 73 93 33
## 74 93 17
## 75 99 29
## 76 100 22
## 77 100 25
## 78 100 60
## 79 84 50
## 80 100 32
## 81 83 58
## 82 100 50
## 83 100 33
## 84 94 25
## 85 87 72
## 86 100 37
## 87 100 23
## 88 95 27
## 89 100 32
## 90 100 41
## 91 91 49
## 92 100 38
## 93 90 74
## 94 84 53
## 95 66 81
## 96 86 55
## 97 78 91
## 98 87 65
## 99 77 70
## 100 94 41
## 101 100 63
## 102 84 48
## 103 100 30
## 104 99 57
## 105 100 56
## 106 100 41
## 107 78 93
## 108 100 58
## 109 100 38
## 110 95 28
## 111 92 61
## 112 100 13
## 113 91 42
## 114 100 35
## 115 100 28
## 116 90 45
## 117 86 55
## 118 89 50
## 119 98 59
## 120 62 100
## 121 100 19
## 122 82 66
## 123 100 24
## 124 97 54
## 125 90 18
## 126 100 61
## 127 100 36
## 128 100 41
## 129 100 72
## 130 69 62
## 131 89 33
## 132 100 47
## 133 89 42
## 134 98 7
## 135 88 81
## 136 98 77
## 137 100 42
## 138 93 47
## 139 79 61
## 140 100 20
## 141 100 61
## 142 100 31
## 143 100 12
## 144 100 23
## 145 69 79
## 146 91 41
## 147 100 44
## 148 99 48
## 149 95 45
## 150 98 35
## 151 100 40
## 152 100 18
## 153 100 32
## 154 97 42
## 155 100 27
## 156 71 33
## 157 100 42
## 158 100 9
## 159 100 69
## 160 94 20
## 161 94 69
## 162 100 49
## 163 100 52
## 164 84 36
## 165 100 60
## 166 100 49
## 167 90 47
## 168 96 43
## 169 78 66
## 170 100 2
## 171 88 70
## 172 91 76
## 173 100 9
## 174 100 40
## 175 100 17
## 176 100 40
## 177 100 52
## 178 100 31
## 179 88 64
## 180 98 43
## 181 100 29
## 182 100 38
## 183 100 67
## 184 100 38
## 185 100 39
## 186 88 24
## 187 91 44
## 188 70 76
## 189 79 58
## 190 100 28
## 191 74 94
## 192 79 79
## 193 94 30
## 194 95 40
## 195 87 42
## 196 100 39
## 197 100 56
## 198 100 25
## 199 97 61
## 200 100 23
##
## $subset
## NULL
##
## $outlierMethod
## [1] "none"
##
## attr(,"class")
## [1] "mvn"
Interpretasi: Jika nilai p > 0.05 pada uji Henze-Zirkler, asumsi normalitas multivariat terpenuhi.
cor_dv <- cor(dv)
print(cor_dv)
## Load_Balance_Score ACL_Risk_Score
## Load_Balance_Score 1.0000000 -0.5682654
## ACL_Risk_Score -0.5682654 1.0000000
Interpretasi: DV harus saling berkorelasi (tidak independen total) agar MANOVA bermakna. Nilai korelasi sedang (0.2–0.8) adalah ideal.
boxM_result <- boxM(dv, data_clean$Position)
print(boxM_result)
##
## Box's M-test for Homogeneity of Covariance Matrices
##
## data: dv
## Chi-Sq (approx.) = 4.2488, df = 6, p-value = 0.6431
Interpretasi: Jika p > 0.05, asumsi homogenitas matriks kovarians terpenuhi (tidak ada perbedaan signifikan antar grup).
Kovariat: Training_Hours_Per_Week &
Training_Intensity
DV: Load_Balance_Score &
ACL_Risk_Score
Uji linearitas dilakukan hanya untuk DV yang akan dimasukkan dalam MANCOVA.
par(mfrow = c(2, 2))
plot(data_clean$Training_Hours_Per_Week, data_clean$Load_Balance_Score,
main = "Training_Hours vs Load_Balance",
xlab = "Training Hours Per Week", ylab = "Load Balance Score",
pch = 19, col = "steelblue")
abline(lm(Load_Balance_Score ~ Training_Hours_Per_Week, data = data_clean),
col = "red", lwd = 2)
plot(data_clean$Training_Intensity, data_clean$Load_Balance_Score,
main = "Training_Intensity vs Load_Balance",
xlab = "Training Intensity", ylab = "Load Balance Score",
pch = 19, col = "steelblue")
abline(lm(Load_Balance_Score ~ Training_Intensity, data = data_clean),
col = "red", lwd = 2)
plot(data_clean$Training_Hours_Per_Week, data_clean$ACL_Risk_Score,
main = "Training_Hours vs ACL_Risk",
xlab = "Training Hours Per Week", ylab = "ACL Risk Score",
pch = 19, col = "darkorange")
abline(lm(ACL_Risk_Score ~ Training_Hours_Per_Week, data = data_clean),
col = "red", lwd = 2)
plot(data_clean$Training_Intensity, data_clean$ACL_Risk_Score,
main = "Training_Intensity vs ACL_Risk",
xlab = "Training Intensity", ylab = "ACL Risk Score",
pch = 19, col = "darkorange")
abline(lm(ACL_Risk_Score ~ Training_Intensity, data = data_clean),
col = "red", lwd = 2)
par(mfrow = c(1, 1))
# Uji signifikansi linear: kovariat ~ DV
cat("Uji Linear: Training_Hours_Per_Week\n")
## Uji Linear: Training_Hours_Per_Week
summary(lm(Load_Balance_Score ~ Training_Hours_Per_Week, data = data_clean))
##
## Call:
## lm(formula = Load_Balance_Score ~ Training_Hours_Per_Week, data = data_clean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -23.726 -2.969 1.301 5.281 12.278
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 104.6861 1.4477 72.314 < 2e-16 ***
## Training_Hours_Per_Week -0.9979 0.1191 -8.375 9.98e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 7.461 on 198 degrees of freedom
## Multiple R-squared: 0.2616, Adjusted R-squared: 0.2579
## F-statistic: 70.15 on 1 and 198 DF, p-value: 9.977e-15
summary(lm(ACL_Risk_Score ~ Training_Hours_Per_Week, data = data_clean))
##
## Call:
## lm(formula = ACL_Risk_Score ~ Training_Hours_Per_Week, data = data_clean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -43.972 -12.875 -1.625 13.479 46.811
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 36.3865 3.6039 10.096 <2e-16 ***
## Training_Hours_Per_Week 0.8912 0.2966 3.005 0.003 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 18.57 on 198 degrees of freedom
## Multiple R-squared: 0.0436, Adjusted R-squared: 0.03877
## F-statistic: 9.027 on 1 and 198 DF, p-value: 0.003003
cat("\n=== Uji Linear: Training_Intensity ===\n")
##
## === Uji Linear: Training_Intensity ===
summary(lm(Load_Balance_Score ~ Training_Intensity, data = data_clean))
##
## Call:
## lm(formula = Load_Balance_Score ~ Training_Intensity, data = data_clean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -30.868 -4.414 4.404 6.404 7.314
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 94.3245 1.3972 67.51 <2e-16 ***
## Training_Intensity -0.1821 0.2459 -0.74 0.46
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 8.67 on 198 degrees of freedom
## Multiple R-squared: 0.002761, Adjusted R-squared: -0.002276
## F-statistic: 0.5481 on 1 and 198 DF, p-value: 0.46
summary(lm(ACL_Risk_Score ~ Training_Intensity, data = data_clean))
##
## Call:
## lm(formula = ACL_Risk_Score ~ Training_Intensity, data = data_clean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -37.414 -11.014 -0.694 9.330 45.586
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 32.4623 2.8530 11.378 < 2e-16 ***
## Training_Intensity 2.7439 0.5022 5.464 1.39e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 17.7 on 198 degrees of freedom
## Multiple R-squared: 0.131, Adjusted R-squared: 0.1266
## F-statistic: 29.85 on 1 and 198 DF, p-value: 1.389e-07
Catatan: Berdasarkan hasil uji linearitas, kovariat Training_Hours_Per_Week dan Training_Intensity digunakan hanya untuk DV Load_Balance_Score dan ACL_Risk_Score karena keduanya memiliki hubungan linear yang signifikan dengan kedua DV tersebut.
# Jika ada interaksi signifikan, asumsi homogenitas slope dilanggar
cat("Load_Balance_Score\n")
## Load_Balance_Score
summary(aov(Load_Balance_Score ~ Position * Training_Hours_Per_Week, data = data_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 217 109 1.924 0.149
## Training_Hours_Per_Week 1 3734 3734 66.186 4.82e-14 ***
## Position:Training_Hours_Per_Week 2 32 16 0.279 0.757
## Residuals 194 10944 56
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
summary(aov(Load_Balance_Score ~ Position * Training_Intensity, data = data_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 217 108.52 1.472 0.2319
## Training_Intensity 1 38 38.46 0.522 0.4709
## Position:Training_Intensity 2 373 186.28 2.527 0.0825 .
## Residuals 194 14298 73.70
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cat("\nACL_Risk_Score\n")
##
## ACL_Risk_Score
summary(aov(ACL_Risk_Score ~ Position * Training_Hours_Per_Week, data = data_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 1702 851.1 2.492 0.08538 .
## Training_Hours_Per_Week 1 2565 2565.0 7.510 0.00671 **
## Position:Training_Hours_Per_Week 2 892 446.2 1.306 0.27314
## Residuals 194 66256 341.5
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
summary(aov(ACL_Risk_Score ~ Position * Training_Intensity, data = data_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 1702 851 2.786 0.0642 .
## Training_Intensity 1 9445 9445 30.913 8.85e-08 ***
## Position:Training_Intensity 2 991 496 1.622 0.2002
## Residuals 194 59277 306
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretasi: Interaksi
Position × Kovariatharus tidak signifikan (p > 0.05) agar asumsi homogenitas slope terpenuhi.
model_manova <- manova(
cbind(Load_Balance_Score, ACL_Risk_Score) ~ Position,
data = data_clean
)
summary(model_manova, test = "Pillai")
## Df Pillai approx F num Df den Df Pr(>F)
## Position 2 0.025473 1.2707 4 394 0.2809
## Residuals 197
# Hasil univariat untuk setiap DV
summary.aov(model_manova)
## Response Load_Balance_Score :
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 217 108.520 1.4534 0.2363
## Residuals 197 14709 74.664
##
## Response ACL_Risk_Score :
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 1702 851.14 2.4052 0.09289 .
## Residuals 197 69714 353.88
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
library(ggplot2)
ggplot(data_clean, aes(x = Position, y = Load_Balance_Score, fill = Position)) +
geom_boxplot() +
theme_minimal() +
labs(title = "MANOVA: Load Balance Score per Position")
ggplot(data_clean, aes(x = Position, y = ACL_Risk_Score, fill = Position)) +
geom_boxplot() +
theme_minimal() +
labs(title = "MANOVA: ACL Risk Score per Position")
Kovariat: Training_Hours_Per_Week + Training_Intensity
model_mancova <- manova(
cbind(Load_Balance_Score, ACL_Risk_Score) ~ Position +
Training_Hours_Per_Week + Training_Intensity,
data = data_clean
)
summary(model_mancova, test = "Pillai")
## Df Pillai approx F num Df den Df Pr(>F)
## Position 2 0.031431 1.557 4 390 0.1852
## Training_Hours_Per_Week 1 0.266075 35.166 2 194 9.295e-14 ***
## Training_Intensity 1 0.170478 19.935 2 194 1.338e-08 ***
## Residuals 195
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Hasil univariat untuk setiap DV (setelah dikontrol kovariat)
summary.aov(model_mancova)
## Response Load_Balance_Score :
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 217.0 108.5 1.9368 0.1469
## Training_Hours_Per_Week 1 3733.6 3733.6 66.6360 3.981e-14 ***
## Training_Intensity 1 49.4 49.4 0.8811 0.3491
## Residuals 195 10925.8 56.0
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Response ACL_Risk_Score :
## Df Sum Sq Mean Sq F value Pr(>F)
## Position 2 1702 851.1 2.8831 0.058352 .
## Training_Hours_Per_Week 1 2565 2565.0 8.6883 0.003593 **
## Training_Intensity 1 9580 9580.5 32.4519 4.451e-08 ***
## Residuals 195 57568 295.2
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Ambil residual (nilai setelah dikontrol kovariat)
model_lb <- lm(Load_Balance_Score ~ Training_Hours_Per_Week + Training_Intensity, data = data_clean)
model_acl <- lm(ACL_Risk_Score ~ Training_Hours_Per_Week + Training_Intensity, data = data_clean)
data_clean$LB_adjusted <- residuals(model_lb)
data_clean$ACL_adjusted <- residuals(model_acl)
# Plot hasil MANCOVA
ggplot(data_clean, aes(x = Position, y = LB_adjusted, fill = Position)) +
geom_boxplot() +
theme_minimal() +
labs(title = "MANCOVA: Adjusted Load Balance Score")
ggplot(data_clean, aes(x = Position, y = ACL_adjusted, fill = Position)) +
geom_boxplot() +
theme_minimal() +
labs(title = "MANCOVA: Adjusted ACL Risk Score")
manova_sum <- summary(model_manova, test = "Pillai")
mancova_sum <- summary(model_mancova, test = "Pillai")
# Ekstrak statistik Pillai untuk efek Position
pillai_manova <- manova_sum$stats["Position", "Pillai"]
f_manova <- manova_sum$stats["Position", "approx F"]
p_manova <- manova_sum$stats["Position", "Pr(>F)"]
pillai_mancova <- mancova_sum$stats["Position", "Pillai"]
f_mancova <- mancova_sum$stats["Position", "approx F"]
p_mancova <- mancova_sum$stats["Position", "Pr(>F)"]
comparison_table <- data.frame(
Model = c("MANOVA", "MANCOVA"),
Pillai = round(c(pillai_manova, pillai_mancova), 4),
F_approx = round(c(f_manova, f_mancova), 4),
p_value = round(c(p_manova, p_mancova), 4),
Signifikan = ifelse(c(p_manova, p_mancova) < 0.05, "Ya ✓", "Tidak ✗")
)
print(comparison_table)
## Model Pillai F_approx p_value Signifikan
## 1 MANOVA 0.0255 1.2707 0.2809 Tidak ✗
## 2 MANCOVA 0.0314 1.5567 0.1852 Tidak ✗
# Ambil F dan p dari summary.aov
aov_manova <- summary.aov(model_manova)
aov_mancova <- summary.aov(model_mancova)
get_fp <- function(aov_list, term, dv_name) {
tbl <- aov_list[[dv_name]]
row <- rownames(tbl)[trimws(rownames(tbl)) == term]
if (length(row) == 0) return(c(NA, NA))
c(tbl[row, "F value"], tbl[row, "Pr(>F)"])
}
dv_names <- trimws(names(aov_mancova))
rows <- list()
for (dv in dv_names) {
fp_mancova <- get_fp(aov_mancova, "Position", dv)
rows[[dv]] <- data.frame(
DV = dv,
F_MANCOVA = round(fp_mancova[1], 3),
p_MANCOVA = round(fp_mancova[2], 4)
)
}
uni_table <- do.call(rbind, rows)
rownames(uni_table) <- NULL
print(uni_table)
## DV F_MANCOVA p_MANCOVA
## 1 Response Load_Balance_Score NA NA
## 2 Response ACL_Risk_Score NA NA
# Hitung eta-squared parsial untuk kovariat di MANCOVA (per DV)
eta_sq_partial <- function(aov_list, dv_name) {
dv_name <- trimws(dv_name)
tbl <- aov_list[[dv_name]]
if (is.null(tbl)) return(NULL)
ss <- tbl[, "Sum Sq"]
terms <- trimws(rownames(tbl))
names(ss) <- terms
if (!"Residuals" %in% names(ss)) return(NULL)
ss_resid <- ss["Residuals"]
kovariat_terms <- c("Training_Hours_Per_Week", "Training_Intensity")
result <- data.frame()
for (kt in kovariat_terms) {
if (kt %in% names(ss)) {
eta2p <- ss[kt] / (ss[kt] + ss_resid)
result <- rbind(result, data.frame(
DV = dv_name,
Term = kt,
eta2_p = round(eta2p, 4)
))
}
}
result
}
eta_lb <- eta_sq_partial(aov_mancova, "Load_Balance_Score")
eta_acl <- eta_sq_partial(aov_mancova, "ACL_Risk_Score")
eta_all <- rbind(eta_lb, eta_acl)
rownames(eta_all) <- NULL
cat("Effect Size (η² Parsial) Kovariat dalam MANCOVA\n")
## Effect Size (η² Parsial) Kovariat dalam MANCOVA
print(eta_all)
## NULL
cat("\nKriteria: kecil = 0.01, sedang = 0.06, besar = 0.14\n")
##
## Kriteria: kecil = 0.01, sedang = 0.06, besar = 0.14