Latar Belakang

Beton merupakan material konstruksi paling penting dalam rekayasa sipil. Kualitas beton tidak ditentukan oleh satu faktor tunggal, melainkan oleh interaksi kompleks dari berbagai komponen campuran, antara lain proporsi semen (cement), slag, abu terbang (fly ash), air (water), superplasticizer (SP), serta agregat kasar dan halus. Pemahaman tentang bagaimana faktor-faktor ini memengaruhi sifat mekanik beton secara simultan sangat penting dalam optimasi desain campuran beton.

Analisis ini menggunakan Multivariate Analysis of Variance (MANOVA), Analysis of Covariance (ANCOVA), dan Multivariate Analysis of Covariance (MANCOVA) untuk menguji apakah kelompok kadar semen (CementGroup) memberikan pengaruh yang signifikan terhadap tiga variabel respons beton sekaligus, dengan mengontrol pengaruh kandungan air (Water) sebagai kovariat.

Dataset

Dataset yang digunakan dalam analisis ini adalah Concrete Slump Test Dataset yang bersumber dari UCI Machine Learning Repository (Yeh, 2007). Dataset tersebut memuat hasil pengujian 103 campuran beton dengan rincian sebagai berikut.

Variabel Input (7 variabel, satuan kg/m³): Cement, Slag, Fly ash, Water, SP (superplasticizer), Coarse Aggregate, Fine Aggregate.

Variabel Output (3 variabel): Slump (kemudahan pengerjaan beton dalam cm), Flow (kelecakan beton dalam cm), serta Compressive Strength (kuat tekan beton setelah 28 hari dalam MPa).


Import Data

Data diambil dari file slump_test.data yang bersumber dari UCI Machine Learning Repository.

data <- read.table(
  "https://archive.ics.uci.edu/ml/machine-learning-databases/concrete/slump/slump_test.data",
  sep = ",", header = TRUE
)
str(data)
## 'data.frame':    103 obs. of  11 variables:
##  $ No                                : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Cement                            : num  273 163 162 162 154 147 152 145 152 304 ...
##  $ Slag                              : num  82 149 148 148 112 89 139 0 0 0 ...
##  $ Fly.ash                           : num  105 191 191 190 144 115 178 227 237 140 ...
##  $ Water                             : num  210 180 179 179 220 202 168 240 204 214 ...
##  $ SP                                : num  9 12 16 19 10 9 18 6 6 6 ...
##  $ Coarse.Aggr.                      : num  904 843 840 838 923 860 944 750 785 895 ...
##  $ Fine.Aggr.                        : num  680 746 743 741 658 829 695 853 892 722 ...
##  $ SLUMP.cm.                         : num  23 0 1 3 20 23 0 14.5 15.5 19 ...
##  $ FLOW.cm.                          : num  62 20 20 21.5 64 55 20 58.5 51 51 ...
##  $ Compressive.Strength..28.day..Mpa.: num  35 41.1 41.8 42.1 26.8 ...
summary(data) |>
  kable(caption = "Statistik Deskriptif Dataset") |>
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE)
Statistik Deskriptif Dataset
No Cement Slag Fly.ash Water SP Coarse.Aggr. Fine.Aggr. SLUMP.cm. FLOW.cm. Compressive.Strength..28.day..Mpa.
Min. : 1.0 Min. :137.0 Min. : 0.00 Min. : 0.0 Min. :160.0 Min. : 4.40 Min. : 708.0 Min. :640.6 Min. : 0.00 Min. :20.00 Min. :17.19
1st Qu.: 26.5 1st Qu.:152.0 1st Qu.: 0.05 1st Qu.:115.5 1st Qu.:180.0 1st Qu.: 6.00 1st Qu.: 819.5 1st Qu.:684.5 1st Qu.:14.50 1st Qu.:38.50 1st Qu.:30.90
Median : 52.0 Median :248.0 Median :100.00 Median :164.0 Median :196.0 Median : 8.00 Median : 879.0 Median :742.7 Median :21.50 Median :54.00 Median :35.52
Mean : 52.0 Mean :229.9 Mean : 77.97 Mean :149.0 Mean :197.2 Mean : 8.54 Mean : 884.0 Mean :739.6 Mean :18.05 Mean :49.61 Mean :36.04
3rd Qu.: 77.5 3rd Qu.:303.9 3rd Qu.:125.00 3rd Qu.:235.9 3rd Qu.:209.5 3rd Qu.:10.00 3rd Qu.: 952.8 3rd Qu.:788.0 3rd Qu.:24.00 3rd Qu.:63.75 3rd Qu.:41.20
Max. :103.0 Max. :374.0 Max. :193.00 Max. :260.0 Max. :240.0 Max. :19.00 Max. :1049.9 Max. :902.0 Max. :29.00 Max. :78.00 Max. :58.53

Dataset terdiri dari 103 observasi dan 11 variabel, tanpa missing values. Kadar semen berkisar antara 137–374 kg/m³ dengan median 248 kg/m³. Kuat tekan beton bervariasi antara 17,19–58,53 MPa dengan rata-rata 36,04 MPa dan kandungan air berkisar 160–240 kg/m³ dengan rata-rata 197,2 kg/m³.

Rename Kolom

Kolom output asli memiliki nama dengan karakter khusus (spasi, tanda kurung, titik) sehingga perlu diubah agar mudah diakses dalam R.

colnames(data)[colnames(data) == "SLUMP.cm."]                           <- "Slump"
colnames(data)[colnames(data) == "FLOW.cm."]                            <- "Flow"
colnames(data)[colnames(data) == "Compressive.Strength..28.day..Mpa."] <- "CompressiveStrength"

Pembentukan Matriks dan Variabel Grup

# Matriks variabel dependen
Y <- cbind(
  Slump               = data$Slump,
  Flow                = data$Flow,
  CompressiveStrength = data$CompressiveStrength
)

# Matriks variabel prediktor
X <- data[, c("Cement", "Coarse.Aggr.", "Fine.Aggr.", "Water", "SP")]

# Variabel faktor (pembagian berdasarkan nilai median)
data$CementGroup <- factor(ifelse(data$Cement < median(data$Cement), "Low", "High"))
data$SlagGroup   <- factor(ifelse(data$Slag   < median(data$Slag),   "Low", "High"))

Variabel CementGroup dan SlagGroup dibentuk dengan membagi data menjadi dua kelompok berdasarkan nilai median masing-masing variabel, sehingga menghasilkan pembagian yang relatif seimbang.

dist_tbl <- as.data.frame(table(CementGroup = data$CementGroup))
kable(dist_tbl, caption = "Distribusi Observasi per Kelompok CementGroup",
      col.names = c("CementGroup", "Frekuensi")) |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Distribusi Observasi per Kelompok CementGroup
CementGroup Frekuensi
High 52
Low 51

Pembagian menghasilkan 52 campuran beton dengan kadar semen tinggi (High, Cement ≥ 248 kg/m³) dan 51 campuran dengan kadar semen rendah (Low, Cement < 248 kg/m³).

dt <- data.frame(CementGroup = data$CementGroup, Y)
kable(head(dt, 10),
      caption = "Sepuluh Baris Pertama Dataset (Variabel Dependen dan Faktor)",
      digits  = 3) |>
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Sepuluh Baris Pertama Dataset (Variabel Dependen dan Faktor)
CementGroup Slump Flow CompressiveStrength
High 23.0 62.0 34.99
Low 0.0 20.0 41.14
Low 1.0 20.0 41.81
Low 3.0 21.5 42.08
Low 20.0 64.0 26.82
Low 23.0 55.0 25.21
Low 0.0 20.0 38.86
Low 14.5 58.5 36.59
Low 15.5 51.0 32.71
High 19.0 51.0 38.46

Analisis Eksplorasi Data

Distribusi Variabel — Boxplot

numeric_data <- data[, sapply(data, is.numeric)]
numeric_data <- numeric_data[, !(names(numeric_data) %in% c("No"))]

boxplot(numeric_data,
        las  = 2,
        col  = "pink",
        main = "Boxplot Concrete Slump Test Dataset",
        ylab = "Nilai")
Boxplot seluruh variabel numerik pada Concrete Slump Test Dataset

Boxplot seluruh variabel numerik pada Concrete Slump Test Dataset

Boxplot menunjukkan bahwa variabel Coarse.Aggr. dan Fine.Aggr. memiliki skala yang jauh lebih besar (di atas 600 kg/m³) dibandingkan variabel lainnya, hal ini mencerminkan peran dominan agregat dalam komposisi volume beton. Variabel Slag dan Fly.ash memperlihatkan variasi yang lebar dan variabel Slump menunjukkan sejumlah nilai yang mendekati nol yang merepresentasikan campuran beton sangat kaku (kondisi yang umum dijumpai pada beton berkadar air rendah).

Hubungan antar Variabel — Scatter Plot Matrix

pairs(cbind(Y, X),
      col = "steelblue",
      pch = 19,
      cex = 0.55,
      main = "Scatter Plot Matrix — Variabel Dependen dan Prediktor")
Matriks scatter plot variabel dependen dan prediktor utama

Matriks scatter plot variabel dependen dan prediktor utama

scatterplotMatrix(~ Slump + Flow + CompressiveStrength + Cement + Water + SP,
                  data = data,
                  main = "Scatter Plot Matrix dengan Kurva Estimasi")
Scatter plot matrix dengan estimasi distribusi dan kurva regresi

Scatter plot matrix dengan estimasi distribusi dan kurva regresi

Dari matriks scatter plot, terlihat bahwa Slump dan Flow memiliki korelasi positif yang kuat. Variabel Water berkorelasi positif dengan Slump dan Flow karena penambahan air meningkatkan kemudahan pengerjaan beton. Sebaliknya, CompressiveStrength menunjukkan kecenderungan negatif terhadap Water. Cement memperlihatkan hubungan positif dengan CompressiveStrength, memvalidasi peran semen sebagai komponen utama penentu kekuatan beton.


Uji Asumsi

Asumsi 1 — Normalitas Multivariat

MANOVA mengasumsikan bahwa kombinasi linear dari variabel-variabel dependen berdistribusi normal multivariat di setiap kelompok.

Uji Shapiro-Wilk Multivariat

sw_result <- mshapiro.test(t(Y))
sw_tbl <- data.frame(
  Uji       = "Shapiro-Wilk Multivariat",
  Statistik = round(sw_result$statistic, 5),
  `p-value` = round(sw_result$p.value,   5),
  Keputusan = ifelse(sw_result$p.value > 0.05, "Normal", "Tidak Normal"),
  check.names = FALSE
)
kable(sw_tbl, caption = "Hasil Uji Shapiro-Wilk Multivariat") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Hasil Uji Shapiro-Wilk Multivariat
Uji Statistik p-value Keputusan
W Shapiro-Wilk Multivariat 0.97816 0.08616 Normal

Uji Shapiro-Wilk multivariat menghasilkan W = 0,978 dengan p-value = 0,086. Karena p > 0,05, H₀ tidak ditolak, data secara multivariat dinyatakan berdistribusi normal menurut uji ini. Kombinasi linear dari ketiga variabel dependen (Slump, Flow, dan CompressiveStrength) secara bersama-sama memenuhi asumsi normalitas multivariat.

Uji Henze-Zirkler

mvn(Y)
## $multivariate_normality
##            Test Statistic p.value     Method          MVN
## 1 Henze-Zirkler     2.736  <0.001 asymptotic ✗ Not normal
## 
## $univariate_normality
##               Test            Variable Statistic p.value    Normality
## 1 Anderson-Darling               Slump     7.337  <0.001 ✗ Not normal
## 2 Anderson-Darling                Flow     3.268  <0.001 ✗ Not normal
## 3 Anderson-Darling CompressiveStrength     0.376   0.406     ✓ Normal
## 
## $descriptives
##              Variable   n   Mean Std.Dev Median   Min   Max 25th   75th   Skew
## 1               Slump 103 18.049   8.751  21.50  0.00 29.00 14.5 24.000 -1.097
## 2                Flow 103 49.611  17.569  54.00 20.00 78.00 38.5 63.750 -0.513
## 3 CompressiveStrength 103 36.039   7.838  35.52 17.19 58.53 30.9 41.205  0.189
##   Kurtosis
## 1    2.854
## 2    2.087
## 3    3.135
## 
## $data
##        Slump Flow CompressiveStrength
##   [1,] 23.00 62.0               34.99
##   [2,]  0.00 20.0               41.14
##   [3,]  1.00 20.0               41.81
##   [4,]  3.00 21.5               42.08
##   [5,] 20.00 64.0               26.82
##   [6,] 23.00 55.0               25.21
##   [7,]  0.00 20.0               38.86
##   [8,] 14.50 58.5               36.59
##   [9,] 15.50 51.0               32.71
##  [10,] 19.00 51.0               38.46
##  [11,] 24.50 61.0               26.02
##  [12,] 23.75 58.0               28.03
##  [13,] 25.50 67.0               31.37
##  [14,] 17.00 54.0               33.91
##  [15,] 14.50 42.5               32.44
##  [16,] 23.50 54.5               34.05
##  [17,] 12.00 35.0               28.29
##  [18,] 25.00 68.5               41.01
##  [19,] 20.50 48.2               49.30
##  [20,] 15.00 48.5               29.23
##  [21,] 20.00 49.0               29.77
##  [22,] 13.00 46.0               36.19
##  [23,]  0.00 20.0               18.52
##  [24,] 18.00 46.0               17.19
##  [25,]  0.00 20.0               36.72
##  [26,] 23.75 53.0               33.38
##  [27,] 25.00 70.0               42.08
##  [28,] 26.50 70.0               39.40
##  [29,] 16.00 26.0               41.27
##  [30,] 21.50 64.0               41.14
##  [31,] 24.00 60.0               45.82
##  [32,] 20.00 68.5               43.95
##  [33,] 24.75 62.7               52.65
##  [34,] 26.50 68.0               35.52
##  [35,] 27.50 70.0               34.45
##  [36,] 25.75 64.5               43.54
##  [37,] 23.00 54.0               33.11
##  [38,] 14.50 20.0               18.26
##  [39,] 19.00 43.0               34.99
##  [40,] 21.00 57.0               33.78
##  [41,]  2.50 20.0               35.66
##  [42,] 23.00 65.0               33.51
##  [43,] 13.00 38.0               33.51
##  [44,] 24.00 59.0               27.62
##  [45,]  3.00 20.0               30.97
##  [46,] 17.50 48.0               31.77
##  [47,] 25.50 64.0               37.39
##  [48,] 25.00 61.0               43.01
##  [49,]  0.00 20.0               58.53
##  [50,] 21.50 42.0               52.65
##  [51,] 23.50 60.0               45.69
##  [52,] 21.00 61.0               32.04
##  [53,]  8.00 30.0               36.46
##  [54,] 24.00 62.0               38.59
##  [55,] 20.50 61.5               45.42
##  [56,] 23.00 50.0               19.19
##  [57,] 22.00 40.0               31.50
##  [58,] 22.00 49.0               29.63
##  [59,] 25.00 69.0               26.42
##  [60,] 24.00 65.0               29.50
##  [61,] 19.00 48.0               32.71
##  [62,] 22.50 48.5               39.93
##  [63,] 25.00 63.0               28.29
##  [64,] 23.00 69.0               30.43
##  [65,] 27.00 60.0               37.39
##  [66,] 21.00 51.0               35.39
##  [67,] 18.00 48.0               37.66
##  [68,] 21.00 54.0               40.34
##  [69,]  2.00 20.0               46.36
##  [70,] 26.00 64.0               31.90
##  [71,]  0.00 20.0               44.08
##  [72,] 23.00 58.0               28.16
##  [73,] 25.50 67.0               29.77
##  [74,] 24.00 47.0               41.27
##  [75,] 24.00 67.0               27.89
##  [76,] 23.50 58.5               28.70
##  [77,] 12.00 39.0               32.57
##  [78,] 23.00 63.5               34.18
##  [79,] 16.25 31.0               30.83
##  [80,] 23.50 53.0               30.43
##  [81,] 24.50 57.0               26.42
##  [82,] 21.00 64.0               26.28
##  [83,] 24.00 75.0               36.19
##  [84,] 21.25 46.0               36.32
##  [85,] 23.50 52.5               33.78
##  [86,] 24.50 60.0               30.97
##  [87,] 25.00 55.0               27.09
##  [88,] 26.50 78.0               38.46
##  [89,]  9.50 27.5               37.92
##  [90,] 14.50 36.5               38.19
##  [91,] 14.50 41.5               35.52
##  [92,] 17.00 27.0               32.84
##  [93,] 25.00 78.0               44.48
##  [94,]  0.00 20.0               41.54
##  [95,]  0.00 20.0               41.81
##  [96,]  0.00 20.0               41.01
##  [97,] 27.50 64.0               39.13
##  [98,] 25.00 77.0               44.08
##  [99,]  0.00 20.0               49.97
## [100,]  2.00 20.0               50.23
## [101,]  0.00 20.0               50.50
## [102,] 27.50 67.0               49.17
## [103,] 29.00 78.0               48.77
## 
## $subset
## NULL
## 
## $outlierMethod
## [1] "none"
## 
## attr(,"class")
## [1] "mvn"

Uji Henze-Zirkler menghasilkan statistik 2,736 dengan p < 0,001, menunjukkan normalitas multivariat secara formal tidak terpenuhi. Pemeriksaan univariat menyatakan bahwa Slump (skewness = −1,097) dan Flow (skewness = −0,513) tidak berdistribusi normal, sementara CompressiveStrength normal (p = 0,406). Ketidaknormalan pada Slump dan Flow disebabkan oleh batas bawah fisik, sejumlah campuran menghasilkan nilai minimum (0 cm dan 20 cm) yang menciptakan left skewness pada distribusi.

Meskipun demikian, MANOVA tetap dapat dilanjutkan dengan pertimbangan berikut: (1) Uji Shapiro-Wilk multivariat menunjukkan normalitas terpenuhi (p = 0,086); (2) MANOVA dikenal cukup robust terhadap pelanggaran normalitas ringan apabila ukuran sampel memadai (n = 103); dan (3) Pillai’s Trace akan diprioritaskan sebagai statistik uji karena paling robust di antara keempat statistik MANOVA yang tersedia.

Asumsi 2 — Uji Outlier Multivariat

mahal  <- mahalanobis(Y, colMeans(Y), cov(Y))
cutoff <- qchisq(0.999, df = ncol(Y))
outlier <- which(mahal > cutoff)

out_tbl <- data.frame(
  `Cut-off χ²(0.999, df=3)` = round(cutoff, 4),
  `Jumlah Outlier`           = length(outlier),
  `Indeks Observasi`         = ifelse(length(outlier) == 0, "Tidak ada", paste(outlier, collapse = ", ")),
  check.names = FALSE
)
kable(out_tbl, caption = "Hasil Deteksi Outlier Multivariat — Mahalanobis Distance") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Hasil Deteksi Outlier Multivariat — Mahalanobis Distance
Cut-off χ²(0.999, df=3) Jumlah Outlier Indeks Observasi
16.2662 0 Tidak ada

Tidak ditemukan satu pun outlier multivariat pada dataset ini dan juga tidak ada observasi yang memiliki Mahalanobis Distance melebihi nilai kritis χ²(0,999; df = 3). Hal ini berarti seluruh observasi dapat digunakan dalam analisis tanpa menghapus data.

Asumsi 3 — Uji Multikolinearitas

model_vif  <- lm(Slump ~ Cement + Coarse.Aggr. + Fine.Aggr. + Water + SP, data = data)
vif_values <- vif(model_vif)

vif_tbl <- data.frame(
  Variabel  = names(vif_values),
  VIF       = round(vif_values, 4),
  Status    = ifelse(vif_values > 10, "Serius ",
              ifelse(vif_values > 5,  "Perhatikan",
                                      "Aman"))
)
rownames(vif_tbl) <- NULL
kable(vif_tbl, caption = "Nilai Variance Inflation Factor (VIF) Variabel Prediktor") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE) |>
  column_spec(3, color = ifelse(vif_tbl$Status == "Aman ", "green", "red"))
Nilai Variance Inflation Factor (VIF) Variabel Prediktor
Variabel VIF Status
Cement 1.1461 Aman
Coarse.Aggr. 2.5125 Aman
Fine.Aggr. 1.4328 Aman
Water 1.8273 Aman
SP 1.1231 Aman

VIF tertinggi adalah Coarse.Aggr. = 2,51, Water = 1,83 dan Fine.Aggr. = 1,43. Tidak ada satu variabel pun yang melampaui batas 5 dan 10, berarti tidak terdapat masalah multikolinearitas antar variabel prediktor. Estimasi koefisien model dapat dipercaya karena setiap prediktor memberikan informasi yang relatif independen.

Asumsi 4 — Homogenitas Varians (Levene’s Test)

lev_slump <- leveneTest(Slump               ~ CementGroup, data = data)
lev_flow  <- leveneTest(Flow                ~ CementGroup, data = data)
lev_cs    <- leveneTest(CompressiveStrength ~ CementGroup, data = data)

lev_tbl <- data.frame(
  `Variabel Dependen` = c("Slump", "Flow", "CompressiveStrength"),
  `F-value`  = round(c(lev_slump$`F value`[1], lev_flow$`F value`[1], lev_cs$`F value`[1]), 4),
  `p-value`  = round(c(lev_slump$`Pr(>F)`[1],  lev_flow$`Pr(>F)`[1],  lev_cs$`Pr(>F)`[1]),  4),
  Keputusan  = c("Homogen", "Homogen", "Tidak Homogen"),
  check.names = FALSE
)
kable(lev_tbl, caption = "Hasil Levene's Test — Homogenitas Varians per Variabel Dependen") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Hasil Levene’s Test — Homogenitas Varians per Variabel Dependen
Variabel Dependen F-value p-value Keputusan
Slump 1.1973 0.2765 Homogen
Flow 0.4866 0.4871 Homogen
CompressiveStrength 3.9587 0.0493 Tidak Homogen

Dua dari tiga variabel dependen memenuhi asumsi homogenitas varians dengan baik: Slump (p = 0,277) dan Flow (p = 0,487) tidak menunjukkan perbedaan varians yang signifikan antar kelompok. CompressiveStrength sedikit menyimpang dengan p = 0,049. Namun penyimpangan ini dapat dijelaskan karena campuran beton berkadar semen tinggi menghasilkan kuat tekan yang lebih konsisten (varians lebih kecil), sedangkan semen rendah menghasilkan kuat tekan yang lebih bervariasi. Karena hanya ada satu variabel yang bermasalah dan penyimpangannya tipis, Pillai’s Trace tetap dipilih untuk statistik uji karena paling robust terhadap kondisi ini.

Asumsi 5 — Homogenitas Matriks Kovarians (Box’s M Test)

bm_cement <- boxM(Y, data$CementGroup)
bm_slag   <- boxM(Y, data$SlagGroup)
bm_inter  <- boxM(Y, interaction(data$CementGroup, data$SlagGroup))

bm_tbl <- data.frame(
  Pengelompokan = c("CementGroup", "SlagGroup", "Interaksi CementGroup × SlagGroup"),
  `Chi-Sq`      = round(c(bm_cement$statistic, bm_slag$statistic, bm_inter$statistic), 4),
  df            =       c(bm_cement$parameter,  bm_slag$parameter,  bm_inter$parameter),
  `p-value`     = round(c(bm_cement$p.value,    bm_slag$p.value,    bm_inter$p.value),  4),
  Keputusan     = c("Homogen", "Homogen", "Homogen"),
  check.names   = FALSE
)
kable(bm_tbl, caption = "Hasil Box's M Test — Homogenitas Matriks Varians-Kovarians") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Hasil Box’s M Test — Homogenitas Matriks Varians-Kovarians
Pengelompokan Chi-Sq df p-value Keputusan
CementGroup 4.0558 6 0.6691 Homogen
SlagGroup 10.5192 6 0.1044 Homogen
Interaksi CementGroup × SlagGroup 24.9163 18 0.1272 Homogen

Hasil Box’s M Test untuk semua skema pengelompokan menunjukkan nilai p yang jauh di atas 0,05: CementGroup (p = 0,669), SlagGroup (p = 0,104), dan interaksi keduanya (p = 0,127). Ketiga hasil ini tidak signifikan, yang berarti asumsi homogenitas matriks varians-kovarians terpenuhi sepenuhnya.

Asumsi 6 — Dependensi antar Variabel Dependen (Bartlett’s Test)

bartlett_result <- cortest.bartlett(cor(Y), n = nrow(Y))

bt_tbl <- data.frame(
  `Chi-Kuadrat` = round(bartlett_result$chisq,   4),
  df            =       bartlett_result$df,
  `p-value`     = formatC(bartlett_result$p.value, format = "e", digits = 2),
  Kesimpulan    = "DV saling berkorelasi - MANOVA justified",
  check.names   = FALSE
)
kable(bt_tbl, caption = "Hasil Bartlett's Sphericity Test — Korelasi antar Variabel Dependen") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Hasil Bartlett’s Sphericity Test — Korelasi antar Variabel Dependen
Chi-Kuadrat df p-value Kesimpulan
181.1798 3 4.91e-39 DV saling berkorelasi - MANOVA justified

Bartlett’s Sphericity Test menghasilkan χ² = 181,18 dengan p = 4,9 × 10⁻³⁹ yang artinya sangat signifikan. Hasil ini membuktikan bahwa matriks korelasi antar ketiga variabel dependen jauh berbeda dari identity matrix, artinya Slump, Flow, dan CompressiveStrength saling berkorelasi secara signifikan.


Analisis MANOVA

MANOVA (Multivariate Analysis of Variance) digunakan untuk menguji apakah vektor rata-rata dari variabel dependen berbeda secara signifikan antar kelompok. Faktor yang diuji adalah CementGroup kelompok kadar semen tinggi versus rendah, dengan tiga variabel dependen simultan: Slump, Flow, dan CompressiveStrength.

Hipotesis:

H₀: Tidak terdapat perbedaan vektor rata-rata (Slump, Flow, CompressiveStrength) antara kelompok CementGroup High dan Low.

H₁: Terdapat perbedaan vektor rata-rata antara kedua kelompok tersebut.

model_manova <- manova(Y ~ CementGroup, data = data)

Hasil MANOVA — Empat Statistik Uji

wilks     <- summary(model_manova, test = "Wilks")$stats
pillai    <- summary(model_manova, test = "Pillai")$stats
hotelling <- summary(model_manova, test = "Hotelling-Lawley")$stats
roy       <- summary(model_manova, test = "Roy")$stats
result_table <- data.frame(
  `Statistik Uji`  = c("Wilks' Lambda", "Pillai's Trace",
                        "Hotelling-Lawley Trace", "Roy's Largest Root"),
  Nilai            = round(c(wilks[1,2],    pillai[1,2],
                              hotelling[1,2], roy[1,2]),    4),
  `Nilai F`        = round(c(wilks[1,3],    pillai[1,3],
                              hotelling[1,3], roy[1,3]),    4),
  `df1`            =       c(wilks[1,4],    pillai[1,4],
                              hotelling[1,4], roy[1,4]),
  `df2`            =       c(wilks[1,5],    pillai[1,5],
                              hotelling[1,5], roy[1,5]),
  `p-value`        = formatC(c(wilks[1,6],  pillai[1,6],
                                hotelling[1,6], roy[1,6]),
                              format = "e", digits = 3),
  Signifikansi     = rep("***", 4),
  check.names      = FALSE
)
kable(result_table,
      caption = "Tabel Ringkasan Hasil MANOVA — Pengaruh CementGroup terhadap (Slump, Flow, CompressiveStrength)") |>
  kable_styling(bootstrap_options = c("striped","hover","bordered"), full_width = FALSE) |>
  row_spec(2, bold = TRUE, background = "#EAF3DE")
Tabel Ringkasan Hasil MANOVA — Pengaruh CementGroup terhadap (Slump, Flow, CompressiveStrength)
Statistik Uji Nilai Nilai F df1 df2 p-value Signifikansi
Wilks’ Lambda 0.7510 10.9402 3 99 2.873e-06 ***
Pillai’s Trace 0.2490 10.9402 3 99 2.873e-06 ***
Hotelling-Lawley Trace 0.3315 10.9402 3 99 2.873e-06 ***
Roy’s Largest Root 0.3315 10.9402 3 99 2.873e-06 ***

Kesimpulan MANOVA: H₀ ditolak, terdapat perbedaan yang sangat signifikan pada kombinasi Slump, Flow, dan Compressive Strength antara campuran beton berkadar semen tinggi dan rendah (Pillai’s Trace = 0,249; F(3,99) = 10,94; p < 0,001). Kadar semen terbukti berpengaruh nyata terhadap profil kualitas beton secara keseluruhan.


Analisis ANOVA Lanjutan

Ketika MANOVA menghasilkan penolakan H₀, analisis lanjutan berupa ANOVA univariat dilakukan untuk mengidentifikasi variabel dependen mana yang paling berkontribusi terhadap perbedaan multivariat yang ditemukan.

anova_followup <- summary.aov(model_manova)
# Ekstrak hasil per DV
anova_rows <- lapply(names(anova_followup), function(nm) {
  tbl <- anova_followup[[nm]]
  data.frame(
    `Variabel Dependen` = gsub("Response ", "", nm),
    `F-value`  = round(tbl[1, "F value"], 4),
    `p-value`  = formatC(tbl[1, "Pr(>F)"], format = "e", digits = 3),
    Signifikansi = ifelse(tbl[1,"Pr(>F)"] < 0.001, "***",
                   ifelse(tbl[1,"Pr(>F)"] < 0.01,  "**",
                   ifelse(tbl[1,"Pr(>F)"] < 0.05,  "*", "ns"))),
    Keputusan = ifelse(tbl[1,"Pr(>F)"] < 0.05, "Signifikan ", "Tidak Signifikan"),
    check.names = FALSE
  )
})
anova_tbl <- do.call(rbind, anova_rows)
rownames(anova_tbl) <- NULL

kable(anova_tbl,
      caption = "Hasil ANOVA Lanjutan per Variabel Dependen (Follow-up MANOVA)") |>
  kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) |>
  row_spec(3, bold = TRUE, background = "#EAF3DE")
Hasil ANOVA Lanjutan per Variabel Dependen (Follow-up MANOVA)
Variabel Dependen F-value p-value Signifikansi Keputusan
Slump 2.3395 1.293e-01 ns Tidak Signifikan
Flow 3.4289 6.699e-02 ns Tidak Signifikan
CompressiveStrength 22.8934 5.857e-06 *** Signifikan

Analisis MANCOVA

MANCOVA (Multivariate Analysis of Covariance) merupakan perluasan MANOVA dengan menambahkan kovariat kontinu guna mengontrol pengaruhnya terhadap variabel dependen. Kovariat yang digunakan adalah Water (kandungan air, kg/m³). Dengan mengontrol Water, perbandingan antar kelompok CementGroup menjadi lebih akurat karena efek perbedaan kadar air yang diketahui sangat berpengaruh pada kualitas beton telah dieleminasi.

Hipotesis:

H₀: Setelah mengontrol kandungan air (Water), tidak terdapat perbedaan vektor rata-rata (Slump, Flow, CompressiveStrength) antar kelompok CementGroup.

H₁: Setelah mengontrol Water, terdapat perbedaan vektor rata-rata antar kelompok CementGroup.

model_mancova <- manova(Y ~ CementGroup + Water, data = data)

Uji Asumsi Khusus MANCOVA — Homogenitas Slope Regresi

cat("Slump ~ CementGroup x Water\n")
## Slump ~ CementGroup x Water
summary(aov(Slump ~ CementGroup * Water, data = data))
##                   Df Sum Sq Mean Sq F value   Pr(>F)    
## CementGroup        1    177   176.8   2.879   0.0929 .  
## Water              1   1551  1551.5  25.257 2.23e-06 ***
## CementGroup:Water  1      1     1.3   0.021   0.8857    
## Residuals         99   6081    61.4                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cat("\nFlow ~ CementGroup * Water=\n")
## 
## Flow ~ CementGroup * Water=
summary(aov(Flow ~ CementGroup * Water, data = data))
##                   Df Sum Sq Mean Sq F value   Pr(>F)    
## CementGroup        1   1034    1034   5.445   0.0216 *  
## Water              1  11648   11648  61.354 5.46e-12 ***
## CementGroup:Water  1      5       5   0.026   0.8715    
## Residuals         99  18796     190                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cat("\nCompressiveStrength ~ CementGroup * Water\n")
## 
## CompressiveStrength ~ CementGroup * Water
summary(aov(CompressiveStrength ~ CementGroup * Water, data = data))
##                   Df Sum Sq Mean Sq F value   Pr(>F)    
## CementGroup        1   1158  1158.0  27.091 1.05e-06 ***
## Water              1    748   748.1  17.503 6.21e-05 ***
## CementGroup:Water  1    129   128.9   3.016   0.0856 .  
## Residuals         99   4232    42.7                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
slope_slump <- summary(aov(Slump               ~ CementGroup * Water, data = data))
slope_flow  <- summary(aov(Flow                ~ CementGroup * Water, data = data))
slope_cs    <- summary(aov(CompressiveStrength ~ CementGroup * Water, data = data))

extract_interaction <- function(aov_summary, dv_name) {
  row <- aov_summary[[1]]["CementGroup:Water", ]
  data.frame(
    `Variabel Dependen`  = dv_name,
    `F Interaksi`        = round(row[["F value"]], 4),
    `p-value`            = round(row[["Pr(>F)"]],  4),
    Keputusan            = ifelse(row[["Pr(>F)"]] > 0.05,
                           "Slope homogen", "Slope tidak homogen"),
    check.names = FALSE
  )
}

slope_tbl <- rbind(
  extract_interaction(slope_slump, "Slump"),
  extract_interaction(slope_flow,  "Flow"),
  extract_interaction(slope_cs,    "CompressiveStrength")
)
rownames(slope_tbl) <- NULL

kable(slope_tbl,
      caption = "Hasil Uji Homogenitas Slope Regresi (Interaksi CementGroup × Water)") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Hasil Uji Homogenitas Slope Regresi (Interaksi CementGroup × Water)
Variabel Dependen F Interaksi p-value Keputusan
Slump 0.0208 0.8857 Slope homogen
Flow 0.0263 0.8715 Slope homogen
CompressiveStrength 3.0160 0.0856 Slope homogen

Karena seluruh nilai p > 0,05, asumsi homogenitas slope terpenuhi untuk ketiga variabel dependen. Ini berarti kandungan air memiliki pola pengaruh yang konsisten terhadap kualitas beton, tidak peduli apakah kadar semennya tinggi atau rendah.

Korelasi antar Variabel Dependen

cor_matrix <- round(cor(Y), 4)
kable(cor_matrix,
      caption = "Matriks Korelasi antar Variabel Dependen") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Matriks Korelasi antar Variabel Dependen
Slump Flow CompressiveStrength
Slump 1.0000 0.9061 -0.2234
Flow 0.9061 1.0000 -0.1240
CompressiveStrength -0.2234 -0.1240 1.0000

Matriks korelasi mempertegas pola hubungan antar variabel dependen. Slump dan Flow berkorelasi positif kuat, CompressiveStrength berkorelasi negatif dengan Slump dan Flow.

Hasil MANCOVA

mancova_summary <- summary(model_mancova, test = "Pillai")$stats
mancova_clean   <- mancova_summary[rownames(mancova_summary) != "Residuals", ]

mancova_tbl <- data.frame(
  Faktor       = rownames(mancova_clean),
  `Pillai's Trace` = round(mancova_clean[, "Pillai"],   4),
  `Nilai F`    = round(mancova_clean[, "approx F"],      4),
  `df1`        =       mancova_clean[, "num Df"],
  `df2`        =       mancova_clean[, "den Df"],
  `p-value`    = formatC(mancova_clean[, "Pr(>F)"],
                         format = "e", digits = 3),
  Signifikansi = ifelse(mancova_clean[, "Pr(>F)"] < 0.001, "***", "ns"),
  check.names  = FALSE
)
rownames(mancova_tbl) <- NULL

kable(mancova_tbl,
      caption = "Tabel Ringkasan Hasil MANCOVA — Pillai's Trace (Faktor: CementGroup, Kovariat: Water)") |>
  kable_styling(bootstrap_options = c("striped","hover","bordered"), full_width = FALSE)
Tabel Ringkasan Hasil MANCOVA — Pillai’s Trace (Faktor: CementGroup, Kovariat: Water)
Faktor Pillai’s Trace Nilai F df1 df2 p-value Signifikansi
CementGroup 0.2534 11.0865 3 98 2.493e-06 ***
Water 0.5577 41.1921 3 98 2.612e-17 ***

Kesimpulan MANCOVA: Penambahan kovariat Water meningkatkan presisi analisis. Nilai Pillai CementGroup sedikit meningkat dari 0,249 (MANOVA) menjadi 0,253 (MANCOVA), mengonfirmasi bahwa pengaruh semen terhadap kualitas beton bersifat nyata dan independen dari kandungan air campuran.


Analisis ANCOVA

ANCOVA (Analysis of Covariance) adalah versi univariat dari MANCOVA yang hanya menganalisis satu variabel dependen dengan kovariat. Dalam analisis ini, Slump dipilih sebagai variabel dependen dan Water sebagai kovariat.

Hipotesis:

H₀: Setelah mengontrol kandungan air (Water), rata-rata Slump tidak berbeda antar kelompok CementGroup.

H₁: Setelah mengontrol Water, rata-rata Slump berbeda secara signifikan antar kelompok CementGroup.

model_ancova <- aov(Slump ~ CementGroup + Water, data = data)

Uji Asumsi ANCOVA

Homogenitas Slope Regresi

slope_ancova <- summary(aov(Slump ~ CementGroup * Water, data = data))[[1]]

slope_ancova_tbl <- data.frame(
  Sumber      = rownames(slope_ancova),
  Df          =       slope_ancova[, "Df"],
  `Sum Sq`    = round(slope_ancova[, "Sum Sq"],  2),
  `Mean Sq`   = round(slope_ancova[, "Mean Sq"], 2),
  `F-value`   = round(slope_ancova[, "F value"], 4),
  `p-value`   = round(slope_ancova[, "Pr(>F)"],  4),
  check.names = FALSE
)
kable(slope_ancova_tbl,
      caption = "Uji Homogenitas Slope Regresi ANCOVA — Slump ~ CementGroup × Water",
      na.string = "") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Uji Homogenitas Slope Regresi ANCOVA — Slump ~ CementGroup × Water
Sumber Df Sum Sq Mean Sq F-value p-value
CementGroup 1 176.83 176.83 2.8787 0.0929
Water 1 1551.49 1551.49 25.2574 0.0000
CementGroup:Water 1 1.28 1.28 0.0208 0.8857
Residuals 99 6081.28 61.43 NA NA

Interaksi CementGroup × Water menghasilkan F = 0,021 dengan p = 0,886. Hal ini membuktikan bahwa hubungan linier antara kandungan air dan nilai slump konsisten di kedua kelompok semen (slope regresi paralel). Asumsi homogenitas slope terpenuhi dan ANCOVA valid untuk dilanjutkan.

Normalitas Residual

sw_ancova <- shapiro.test(residuals(model_ancova))

sw_ancova_tbl <- data.frame(
  `Statistik W` = round(sw_ancova$statistic, 5),
  `p-value`     = formatC(sw_ancova$p.value, format = "e", digits = 3),
  Keputusan     = "Residual tidak normal",
  check.names   = FALSE
)
kable(sw_ancova_tbl,
      caption = "Uji Shapiro-Wilk — Normalitas Residual ANCOVA") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Uji Shapiro-Wilk — Normalitas Residual ANCOVA
Statistik W p-value Keputusan
W 0.91698 7.388e-06 Residual tidak normal

Uji Shapiro-Wilk pada residual ANCOVA menghasilkan W = 0,917 dengan p = 7,388 × 10⁻⁶** berarti residual tidak berdistribusi normal. Penyebab utamanya adalah banyaknya nilai Slump = 0 dalam dataset (campuran beton sangat kaku), yang menciptakan left skewness pada distribusi residual. Meskipun asumsi ini terlanggar, hasil ANCOVA masih dapat diinterpretasikan karena: (1) ukuran sampel n = 103 cukup besar sehingga Teorema Limit Pusat berlaku; (2) pelanggaran bersifat sistematis (nilai nol fisik) bukan acak; dan (3) kesimpulan tentang pengaruh Water yang kuat tidak berubah.

Homogenitas Varians

lev_ancova <- leveneTest(Slump ~ CementGroup, data = data)

lev_ancova_tbl <- data.frame(
  `F-value` = round(lev_ancova$`F value`[1], 4),
  `p-value` = round(lev_ancova$`Pr(>F)`[1],  4),
  Keputusan = "Varians homogen",
  check.names = FALSE
)
kable(lev_ancova_tbl,
      caption = "Levene's Test — Homogenitas Varians Slump antar CementGroup") |>
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Levene’s Test — Homogenitas Varians Slump antar CementGroup
F-value p-value Keputusan
1.1973 0.2765 Varians homogen

Levene’s Test menghasilkan F = 1,197 dengan p = 0,277** (tidak signifikan). Artinya, varians Slump antara kelompok High dan Low tidak berbeda secara signifikan, sehingga asumsi homogenitas varians untuk ANCOVA terpenuhi.

Hasil ANCOVA

ancova_summary <- summary(model_ancova)[[1]]

ancova_tbl <- data.frame(
  Sumber    = rownames(ancova_summary),
  Df        =       ancova_summary[, "Df"],
  `Sum Sq`  = round(ancova_summary[, "Sum Sq"],  2),
  `Mean Sq` = round(ancova_summary[, "Mean Sq"], 2),
  `F-value` = round(ancova_summary[, "F value"], 4),
  `p-value` = round(ancova_summary[, "Pr(>F)"],  6),
  Signifikansi = c(
    ifelse(ancova_summary["CementGroup", "Pr(>F)"] < 0.05, "*", "ns"),
    ifelse(ancova_summary["Water",       "Pr(>F)"] < 0.001, "***", "*"),
    ""
  ),
  check.names = FALSE
)
kable(ancova_tbl,
      caption = "Tabel Ringkasan Hasil ANCOVA — Variabel Dependen: Slump",
      na.string = "") |>
  kable_styling(bootstrap_options = c("striped","hover","bordered"), full_width = FALSE) |>
  row_spec(2, bold = TRUE, background = "#EAF3DE")
Tabel Ringkasan Hasil ANCOVA — Variabel Dependen: Slump
Sumber Df Sum Sq Mean Sq F-value p-value Signifikansi
CementGroup 1 176.83 176.83 2.9072 0.091291 ns
Water 1 1551.49 1551.49 25.5072 0.000002 ***
Residuals 100 6082.56 60.83 NA NA

Kesimpulan ANCOVA: Nilai slump beton tidak ditentukan secara signifikan oleh kadar semen, melainkan dipengaruhi oleh kandungan air dalam campuran.


Kesimpulan

Secara keseluruhan, analisis ini memberikan kesimpulan: Pertama, peningkatan kadar semen merupakan strategi efektif untuk meningkatkan kuat tekan (hubungan ini terbukti signifikan dan konsisten baik dalam MANOVA maupun MANCOVA). Kedua, kandungan air adalah parameter paling kritis yang menentukan workability dan flowability beton, bukan kadar semen. Ketiga, dalam perancangan campuran beton yang optimal, parameter semen untuk kekuatan dan air untuk kemudahan pengerjaan perlu dioptimalkan secara bersamaan