Concrete Compressive Strength Prediction

Memprediksikan Kuat Tekan Beton

Penulis

Taruma Sakti Megariansyah

Diterbitkan

Selasa, 20 Desember 2022

Diubah

Sabtu, 31 Desember 2022

Pendahuluan

Lembar kerja ini merupakan versi open source dari project capstone dengan judul yang serupa. Alur dokumen ini lebih mengarah ke perjalanan atau diary saat menerapkan machine learning ataupun mengeksplorasi dataset. Sehingga, dipastikan terdapat langkah yang keliru sepanjang perjalanan yang kemudian dikoreksi di langkah berikutnya. Jadi lembar kerja ini tidak terstruktur dan mengikuti konsep “learning as you go”.

Semoga dokumen dan lembar kerja ini dapat bermanfaat dan memberikan gambaran bahwa mengeksplorasi dataset maupun implementasinya, bukanlah langkah yang cukup sekali dilakukan, dan akan muncul kesalahan sepanjang perjalanan. Dokumen ini sebagai catatan, bahwa kekeliruan yang terjadi bisa dikoreksi pada eksperimen berikutnya dan dapat digunakan sebagai pembelajaran.

Source code dokumen ini bisa diakses di GitHub taruma/concrete-prediction.

Catatan

Lembar kerja ini dirancang untuk dilihat di browser dengan resolusi 1920x1080 dengan scale 100%. Lihat perubahan di Changelog.

Dataset

Concrete Compressive Strength

Sumber Dataset

(Concrete Compressive Strength (2007)). Dengan sumber aslinya di Archive UCI ML atau Archive UCI (Beta). Pada lembar kerja ini menggunakan dataset yang sudah berformat .csv dari Kaggle: elikplim/concrete-compressive-strength-data-set

Goal

Memprediksikan kuat tekan beton berdasarkan campuran beton dan umur beton.

Struktur lembar kerja ini sebagai berikut:

  1. Bab 1 Pengaturan awal: Bagian package apa saja yang digunakan dalam lembar kerja ini.
  2. Bab 2 Dataset: Penjelasan singkat mengenai dataset Concrete Strength.
  3. Bab 3 Prapemrosesan Data: Mempersiapkan dataset untuk pekerjaan berikutnya.
  4. Bab 4 Analisis data eksploratif: Mengeksplorasi dataset dan memperoleh informasi sebelum dilakukan pemodelan.
  5. Bab 5 Pemodelan: Pemodelan machine learning.
  6. Bab 6 Penutup: Kesimpulan dan saran.

Struktur tersebut bisa ditambah seiringnya waktu.

1 Pengaturan awal

Versi R yang digunakan adalah \(4.2+\) dan piping yang digunakan adalah native piping (|>).

               _                                
platform       x86_64-w64-mingw32               
arch           x86_64                           
os             mingw32                          
crt            ucrt                             
system         x86_64, mingw32                  
status                                          
major          4                                
minor          2.1                              
year           2022                             
month          06                               
day            23                               
svn rev        82513                            
language       R                                
version.string R version 4.2.1 (2022-06-23 ucrt)
nickname       Funny-Looking Kid                

2 Dataset

Dataset yang digunakan adalah Concrete Compressive Strength (Concrete Compressive Strength (2007)) yang berisikan hasil observasi kuat tekan beton berdasarkan campuran beton dan umur beton. Initial split menjadi data training dan testing dibagi menggunakan informasi dari data/index_split.csv. Dan dilakukan perubahan nama kolomnya sehingga lebih sederhana.

Membaca dataset dan menyimpannya sebagai concrete_train dan concrete_test
concrete_all <- read.csv("data/concrete_data.csv")
concrete_all$id <- paste0("O", sequence(nrow(concrete_all)))
names(concrete_all) <- c(
  "cement", "slag", "flyash",   "water", "super_plast",
  "coarse_agg", "fine_agg", "age", "strength", "id"
)
concrete_all <- concrete_all |> 
  select(all_of(c(
  "id", "cement", "slag", "flyash", "water", "super_plast",
  "coarse_agg", "fine_agg", "age", "strength"
)))

split_index <- read.csv("data/index_split.csv")

concrete_train <- concrete_all[-split_index$split_index,]
concrete_test <- concrete_all[split_index$split_index,]
concrete_train |> glimpse()
Rows: 825
Columns: 10
$ id          <chr> "O1", "O2", "O3", "O4", "O5", "O7", "O8", "O10", "O11", "O…
$ cement      <dbl> 540.0, 540.0, 332.5, 332.5, 198.6, 380.0, 380.0, 475.0, 19…
$ slag        <dbl> 0.0, 0.0, 142.5, 142.5, 132.4, 95.0, 95.0, 0.0, 132.4, 132…
$ flyash      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ water       <dbl> 162, 162, 228, 228, 192, 228, 228, 228, 192, 192, 228, 228…
$ super_plast <dbl> 2.5, 2.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0…
$ coarse_agg  <dbl> 1040.0, 1055.0, 932.0, 932.0, 978.4, 932.0, 932.0, 932.0, …
$ fine_agg    <dbl> 676.0, 676.0, 594.0, 594.0, 825.5, 594.0, 594.0, 594.0, 82…
$ age         <dbl> 28, 28, 270, 365, 360, 365, 28, 28, 90, 28, 28, 90, 90, 36…
$ strength    <dbl> 79.99, 61.89, 40.27, 41.05, 44.30, 43.70, 36.45, 39.29, 38…

Keterangan setiap kolom/variabel di dataset dapat dilihat di Tabel 2.1.

Tabel 2.1: Deksripsi setiap variabel di dataset
Kolom/variabel Deskripsi Satuan
id ID unik setiap campuran beton / observasi -
cement Jumlah semen \(\text{Kg}\)
slag Jumlah blast furnace slag (BFS)1 \(\text{Kg}\).
flyash Jumlah abu terbang (fly ash)2 \(\text{Kg}\)
super_plast Jumlah superplasticizer3 \(\text{Kg}\)
coarse_agg Jumlah aggregat kasar \(\text{Kg}\)
fine_agg Jumlah aggregat halus \(\text{Kg}\)
age Umur beton \(\text{hari}\)
strength Kuat tekan beton \(\text{MPa}\)

Objek yang digunakan untuk prapemrosesan data (Bab 3) adalah concrete_train dan concrete_test.

3 Prapemrosesan Data

Untuk prapemrosesan data terdapat langkah-langkah yang dapat dilakukan antara lain memeriksa:

  1. Deskripsi dataset untuk prapemrosesan data (Bab 3.1).
  2. Data yang hilang (Bab 3.2).
  3. Outliers / Pencilan (Bab 3.3).
  4. Korelasi independent variables (Bab 3.4).
  5. Normalisasi / Standarisasi (Bab 3.5).

3.1 Deskripsi dataset

Pada bagian ini, dicoba untuk memahami mengenai dataset secara umum dari informasi yang tersedia di Bab 2 dan Tabel 2.1. Dari infromasi tersebut diketahui bahwa dataset memiliki \(10\) kolom yaitu id, cement, slag, flyash, water, super_plast, coarse_agg, fine_agg, age, strength.

Diketahui bahwa pada lembar kerja ini kolom strength berlaku sebagai dependent variables. Sedangkan independent variables antara lain: cement, slag, flyash, water, super_plast, coarse_agg, fine_agg, age. Berikut \(5\) baris pertama dari dataset concrete_train di Tabel 3.1.

Tabel 3.1: 5 baris pertama concrete_train
id cement slag flyash water super_plast coarse_agg fine_agg age strength
O1 540.0 0.0 0 162 2.5 1040.0 676.0 28 79.99
O2 540.0 0.0 0 162 2.5 1055.0 676.0 28 61.89
O3 332.5 142.5 0 228 0.0 932.0 594.0 270 40.27
O4 332.5 142.5 0 228 0.0 932.0 594.0 365 41.05
O5 198.6 132.4 0 192 0.0 978.4 825.5 360 44.30

Dataset concrete_train memiliki dimensi \(825\) baris dan \(10\) kolom, sedangkan dataset concrete_test memiliki dimensi \(205\) baris dan \(10\) kolom. Setelah mengetahui variabel mana yang dijadikan sebagai independent dan dependent, dilanjutkan dengan memeriksa data yang hilang di Bab 3.2.

3.2 Data yang hilang

Pemeriksaan data yang hilang akan dilakukan untuk data concrete_train dan concrete_test. Pemeriksaan dimulai dengan menggunakan anyNA().

Memeriksa dengan anyNA()
concrete_train |> anyNA()
## [1] FALSE
concrete_test |> select(-strength) |> anyNA()
## [1] FALSE

Jika hasil anyNA() bernilai FALSE maka dataset tidak memiliki data yang hilang. Dan dari hasil evaluasi diatas diperoleh bahwa dataset concrete_train dan concrete_test tidak memiliki data yang hilang (NA). Prapemrosesan dilanjut dengan memeriksa outliers.

3.3 Outliers

Pemeriksaan outliers biasanya dilakukan menggunakan visualisasi boxplot() atau memeriksa jumlah nilai dibawah/diatas minimum/maksimumnya (\(\text{min} = Q_1 - 1.5\times\text{IQR}\) atau \(\text{max} = Q_3 + 1.5\times\text{IQR}\)).

Boxplot dibangkitkan menggunakan fungsi boxplot() dan diterapkan ke seluruh kolom numerik di dataset, hasilnya dapat dilihat di Gambar 3.1.

(a) Boxplot cement

(b) Boxplot slag

(c) Boxplot flyash

(d) Boxplot water

(e) Boxplot super_plast

(f) Boxplot coarse_agg

(g) Boxplot fine_agg

(h) Boxplot age

(i) Boxplot strength

Gambar 3.1: Boxplot kolom numeric

Memeriksa ada potensi outlier berdasarkan boxplot
!is.na(outlier_data)
##      cement        slag      flyash       water super_plast  coarse_agg 
##       FALSE        TRUE       FALSE        TRUE        TRUE       FALSE 
##    fine_agg         age    strength 
##        TRUE        TRUE        TRUE

Dari Gambar 3.1, bisa terlihat terdapat beberapa kolom/variabel yang memiliki “potensi” outlier, antara lain: slag, water, super_plast, fine_agg, age, strength. Akan tetapi, outlier disini belum tentu data yang tidak valid. Sehingga, saat ini belum dapat diputuskan jika outlier tersebut dapat dihilangkan dari observasi.

Untuk melihat distribusi untuk setiap dataset bisa menggunakan fungsi hist(). Seluruh histogram bisa dilihat pada Gambar 3.2.

(a) Histogram cement

(b) Histogram slag

(c) Histogram flyash

(d) Histogram water

(e) Histogram super_plast

(f) Histogram coarse_agg

(g) Histogram fine_agg

(h) Histogram age

(i) Histogram strength

Gambar 3.2: Histogram kolom numeric

Dari Gambar 3.2, terlihat terdapat variabel yang tidak mendekati distribusi normal. Seperti pada Gambar 3.2 (b) (slag), Gambar 3.2 (c) (flyash), Gambar 3.2 (e) (super_plast) bisa ditransformasi baik menggunakan log ataupun metode lainnya. Akan tetapi, untuk tahap ini, transformasi dilakukan ketika masuk ke Bab 5 Pemodelan.

Untuk kolom age, bisa dibilang bahwa kolom tersebut bukanlah nilai yang kontinu. Hal tersebut dikarenakan pada pengukuran kuat tekan beton dilakukan pada interval hari-hari tertentu (dengan penggunaan aktualnya yaitu \(28\) hari. Di concrete_train terdapat nilai unik di kolom age yaitu 1, 3, 7, 14, 28, 56, 90, 91, 100, 120, 180, 270, 360, 365 hari. Frekuensi penggunaan umur beton di dataset concrete_train dapat dilihat di Gambar 3.3.

(a) Frekuensi di concrete_train

(b) Frekuensi di concrete_test

Gambar 3.3: Frekuensi umur beton pada dataset

Akan tetapi, dugaan tersebut bisa saja keliru, karena bisa saja terdapat hubungan linear ataupun non-linear antara kuat tekan beton dengan umur beton yang dianggap sebagai kontinu. Jadi, pada proses nantinya, nilai umur beton ini akan dianggap sebagai nilai yang kontinu.

Dari Gambar 3.3 Frekuensi observasi berdasarkan age, terlihat di concrete_train terdapat observasi dengan umur beton yang tidak tersedia di concrete_test yaitu pada umur beton 1, 360. Dengan mengetahui hal tersebut, bisa juga dilakukan penghapusan observasi di concrete_train yang tidak diuji di concrete_test.

Menutup bagian outlier, dari eksperimen yang telah dilakukan diatas, dapat diidentifikasi beberapa “potensi” outlier dan karakteristik distribusi masing-masing variabel. Tapi untuk melakukan tindakan terkait informasi tersebut ditunda pada tahap pemodelan untuk variasi data input.

3.4 Korelasi

Sampai saat ini, dataset masih tidak ada transformasi ataupun koreksi. Dataset concrete_train maupun concrete_test tidak memiliki data yang hilang. Sedangkan untuk outliers, masih ditunda terlebih dahulu dan akan dievaluasi lebih lanjut saat Bab 4 Analisis data eksploratif (Exploratory Data Analysis).

Pada Bab 3.4, akan diperiksa korelasi antar variabel dalam dataset. Apakah terdapat variabel independen yang saling berhubungan atau tidak. Pemeriksaan ini diperlukan jika menggunakan pemodelan sederhana seperti regresi linear45. Tapi untuk lembar kerja ini tidak akan menggunakan model regresi linear.

Untuk melihat korelasi bisa divisualisasikan dalam bentuk correlogram menggunakan fungsi ggcorr(), hasilnya dapat dilihat di Gambar 3.4.

Gambar 3.4: Korelasi concrete_train menggunakan ggcorr()

Dari Gambar 3.4, jika mengevaluasi nilai yang mendekati \(1\) diketahui bahwa hubungan antara water dan super_plast berkorelasi negatif dengan nilai \(-0.7\).

Dari informasi diatas, dapat dilakukan penyesuaian kembali mengenai prediktor (cement, slag, flyash, water, super_plast, coarse_agg, fine_agg, age) dengan target (strength) seperti menggabungkan dua (atau lebih) variabel yang memiliki keserupaan/berkorelasi tinggi (positif maupun negatif). Tapi untuk sampai saat ini, tidak akan tindakan karena korelasi antar variabel masih tergolong rendah.

3.5 Normalisasi

Tahap normalisasi atau standarisasi akan tergantung pada model yang digunakan dan limitasi model tersebut. Sehingga tahapan transformasi ini akan dilakukan sebelum masuk ke tahap pemodelan di Bab 5.

4 Analisis data eksploratif

Dalam bagian analisis data eksploratif (ADE) akan lebih fokus mempelajari mengenai hubungan antara variabel yang tersedia di dataset. Sehingga, tahapan ini akan lebih fokus ke memperoleh insight yang bisa didapatkan dari dataset. Berikut beberapa proses yang akan dilakukan di bagian ini:

  1. Bab 4.1 Visualisasi: Memvisualisasikan berbagai jenis grafik untuk melihat hubungan variabel di dataset.
  2. Bab 4.2 Statistik: Menghitung deskriptif statistik pada dataset train dan test.
  3. Bab 4.3 Outliers dan anomali: Melihat observasi yang berbeda dengan yang lain (outliers).
  4. Bab 4.4 Hubungan linear: Serupa dengan Bab 3.4 Korelasi akan tetapi ini lebih detail melihat hubungannya.
  5. Bab 4.5 Transformasi: Melakukan beberapa transformasi dataset yang diperlukan.

4.1 Visualisasi dataset

Visualisasi mengenai setiap variabel yang tersedia dalam dataset sudah divisualisasikan sebelumnya pada Bab 3 di Gambar 3.1 Boxplot setiap variabel, Gambar 3.2 Histogram setiap variabel, Gambar 3.3 Barplot frekuensi variabel age, Gambar 3.4 Correlogram setiap variabel.

4.1.1 Histogram

Visualisasi histogram dapat memberikan gambaran besar mengenai distribusi/penyebaran variabelnya. Hal ini bisa mempengaruhi bagaimana mentransformasi dataset untuk pemodelan. Seperti yang sempat didiskusikan di Bab 3.3 dan Gambar 3.3 mengenai frekuensi age pada dataset, variabel age bisa dianggap sebagai suatu nilai kategorikal. Untuk melihat distribusi setiap variabel terhadap age dapat dilihat pada Gambar 4.1 untuk dataset concrete_train dan Gambar 4.2 untuk dataset concrete_test. Histogram dibangkitkan menggunakan ggplot() dengan geom_histogram().

(a) Histogram cement

(b) Histogram slag

(c) Histogram flyash

(d) Histogram water

(e) Histogram super_plast

(f) Histogram coarse_agg

(g) Histogram fine_agg

(h) Histogram strength

Gambar 4.1: Histogram concrete_train terhadap age

Seperti dinyatakan sebelumnya bahwa untuk memperoleh kuat tekan beton yang optimal biasanya sudah diperoleh pada umur beton \(28\) hari6, sehingga kemungkinan pada saat pengujian lebih sering dilakukan pada \(28\) hari, yang mengakibatkan informasi pada \(28\) hari lebih banyak dibandingkan hari-hari lainnya.

Dari Gambar 4.1, dapat diperoleh beberapa insight berupa:

  • Dibandingkan dengan Gambar 3.2, pada umur beton tertentu memiliki kontribusi frekuensi terbesar keseluruhan yaitu \(28\) hari. Seperti di gambar Gambar 4.1 (a) (cement) atau Gambar 4.1 (g) (fine_agg), terlihat umur beton \(28\) hari memiliki kontribusi yang lebih banyak dibandingkan umur beton lainnya. Ini juga bisa dikarenakan jumlah observasi dengan umur beton \(28\) hari lebih banyak dengan yang lain (Gambar 3.3 Frekuensi observasi dengan umur beton).
  • Terlepas pemisahan dengan umur beton, Gambar 4.1 (b) (slag), Gambar 4.1 (c) (flyash), dan Gambar 4.1 (e) (super_plast), material tersebut tidak banyak digunakan di campuran beton dalam dataset concrete_train. Hal ini bisa diasumsikan bahwa komponen material tersebut bisa tidak terlalu signifikan. Akan tetapi, kesimpulan tersebut belum bisa diraih karena bisa dianalisis lebih lanjut dengan membandingkan kuat tekan beton dengan variabel tersebut.

Berikut proses yang serupa tetapi menggunakan dataset concrete_test (Gambar 4.2).

(a) Histogram cement

(b) Histogram slag

(c) Histogram flyash

(d) Histogram water

(e) Histogram super_plast

(f) Histogram coarse_agg

(g) Histogram fine_agg

Gambar 4.2: Histogram concrete_test terhadap age

Melihat secara sekilas Gambar 4.2 Histogram concrete_test tidak jauh berbeda dengan Gambar 4.1 Histogram concrete_train. Akan tetapi, dapat dilihat pada concrete_test tidak ada umur beton 1, 360 hari dikarenakan umur beton tersebut tidak tersedia di dataset concrete_test. Informasi tersebut juga bisa dilihat di Gambar 3.3 mengenai frekuensi umur beton di kedua dataset.

4.1.2 Box Plot

Box plot juga dapat diterapkan untuk setiap variabel yang tersedia di dataset. Seperti sebelumnya di Bab 4.1.1, dataset akan divisualisasikan terhadap umur beton. Boxplot untuk dataset concrete_train dan concrete_test bisa dilihat pada Gambar 4.3 dan Gambar 4.4. Boxplot setidaknya memberikan gambaran sebaran data setiap variabel berdasarkan umur beton sehingga mampu memberi informasi terkait hubungan antara umur beton dengan variabel, yang harapannya akan lebih jelas dibandingkan grafik histogram di Bab 4.1.1. Boxplot dibangkitkan menggunakan ggplot() dengan geom_boxplot() dan geom_jitter().

(a) Boxplot cement

(b) Boxplot slag

(c) Boxplot flyash

(d) Boxplot water

(e) Boxplot super_plast

(f) Boxplot coarse_agg

(g) Boxplot fine_agg

(h) Boxplot strength

Gambar 4.3: Boxplot concrete_train terhadap age

Dari Gambar 4.3, bisa melihat distribusinya lebih jelas yang mampu mempertajam informasi setelah grafik histogram di Bab 4.1.1 Histogram. Akan tetapi, visualisasi boxplot bergantung dengan jumlah datanya, sehingga akan sulit mengambil kesimpulan distribusi mengenai setiap variabel terhadap umur beton. Berikut informasi yang dapat diperoleh dari visualisasi Gambar 4.3 Boxplot concrete_train terhadap umur beton:

  • Jika ukuran kotak (IQR) kecil bisa disimpulkan bahwa datanya sedikit, tidak menyebar (pada range tertentu), atau tidak memiliki dataset sama sekali. Perilaku ini bisa dilihat pada Gambar 4.3 (a) (cement) di umur beton \(120\) hari dan \(1\) hari (hanya tersedia 2 data point atau observasi). Karena itu, di varibel lainnya seperti Gambar 4.3 (h) (strength) umur beton \(1\) dan \(120\) hari memiliki IQR yang kecil dibandingkan umur beton lainnya yang memiliki observasi yang lebih banyak (lebih dari dua observasi).
  • Berdasarkan informasi histogram di Gambar 4.1, diketahui bahwa slag, flyash, dan super_plast memiliki jumlah data yang banyak dengan berat \(0\ \text{Kg}\). Dan hal tersebut terlihat pada Gambar 4.3 (b), Gambar 4.3 (c), Gambar 4.3 (e). Pada umur beton tertentu terdapat observasi dimana campuran beton tidak menggunakan komponen tersebut sama sekali.

Berikut visualisasi yang serupa untuk data concrete_test di Gambar 4.4.

(a) Boxplot cement

(b) Boxplot slag

(c) Boxplot flyash

(d) Boxplot water

(e) Boxplot super_plast

(f) Boxplot coarse_agg

(g) Boxplot fine_agg

Gambar 4.4: Boxplot concrete_test terhadap age

Perlu dicatat bahwa pada concrete_test tidak memiliki observasi dengan umur beton 1, 360 hari. Berikut yang bisa diperoleh dengan mengevaluasi Gambar 4.4:

  • Secara sekilas bahwa dataset concrete_test dan concrete_train memiliki keserupaan. Seperti pada Gambar 4.4 (b) (slag), Gambar 4.4 (c) (flyash), Gambar 4.4 (e) (super_plast) memiliki karakteristik yang sama dengan concrete_train yaitu, pada umur beton tertentu, terdapat campuran beton yang tidak menggunakan material tersebut.
  • Pada umur beton \(120\) hari, hanya tersedia satu observasi yang akan diuji. Hal ini bisa dilihat di boxplot semua variabel tentunya tapi terlihat jelas ketika melihat Gambar 4.4 (g) (fine_agg).
  • Keseluruhan data yang paling banyak observasinya yaitu \(28\) hari (informasi ini juga bisa diketahui dengan Gambar 3.3), sehingga sebaran data yang paling bervariasi didominasi oleh yang berumur beton \(28\) hari.

4.1.3 Scatter plot

Scatter plot digunakan untuk melihat hubungan antara dua (atau lebih) variabel. Berbeda dengan visualisasi sebelumnya yang dikategorikan dengan umur beton (age), untuk visualisasi scatter plot akan dilihat hubungan antara predictor/features/independent variable dengan target/dependent variable yaitu kuat tekan beton (strength). Oleh karena itu, untuk concrete_test tidak dapat divisualisasikan karena tidak memiliki informasi kuat tekan betonnya. Scatter plot dibangkitkan menggunakan ggplot() dengan geom_point() dan geom_smooth() dengan argumen method = lm. Hasilnya dapat dilihat di Gambar 4.5.

(a) Hubungan dengan cement

(b) Hubungan dengan slag

(c) Hubungan dengan flyash

(d) Hubungan dengan water

(e) Hubungan dengan super_plast

(f) Hubungan dengan coarse_agg

(g) Hubungan dengan fine_agg

Gambar 4.5: Hubungan antara features dengan strength

Dari Gambar 4.5 diatas, berikut beberapa informasi yang dapat diperoleh:

  • Hubungan linear antara predictor dan target yang lebih baik (dibandingkan yang lain) yaitu hubungan strength dengan cement, water, coarse_agg, dan fine_agg. Ke empat prediktor tersebut tidak “terbebani” oleh jumlah material \(0\ \text{Kg}\) sehingga hasil “regresi”-nya mampu memberikan gambaran besar mengenai hubungan antara prediktor tersebut dengan kuat tekan beton dibandingkan material lainnya.
  • Secara sekilas bahwa umur beton yang muda, tidak memiliki kuat beton yang tinggi. Hal ini dapat dilihat di salah satu grafik hubungan antara Gambar 4.5 (a) (cement) atau Gambar 4.5 (b) (slag) yang terlihat terdapat observasi dengan umur beton yang muda (kurang dari \(14\) hari). Informasi ini juga memperkuat visualisasi boxplot di Gambar 4.3 (h) (strength) yang memberikan distribusi kuat tekan beton yang berumur dibawah \(14\) hari kecil (tidak mencapai kuat tekan beton optimal).
  • Seperti dinyatakan di poin pertama, bahwa regresi untuk Gambar 4.5 (b) (slag), Gambar 4.5 (c) (flyash), Gambar 4.5 (e) (super_plast) dibebani oleh data poin yang tertumpuk pada \(0\ \text{Kg}\). Akan tetapi, tidak adanya penggunaan material tersebut bukan berarti sebagai outlier yang harus dihilangkan karena data tersebut merupakan data yang valid.

Setelah cukup melakukan visualisasi, dataset akan dieksplorasi kembali menggunakan statistik deskriptif di Bab 4.2.

4.2 Statistik

Sebenarnya, statistik disini sudah dirangkum dalam visualisasi yang dilakukan di Bab 4.1 Visualisasi. Akan tetapi, jika membutuhkan perbandingan informasi perhitungan, lebih mudah jika melihat menggunakan angka yang diperoleh dari perhitungan statistiknya. Berikut nilai statistik yang diperoleh menggunakan desc() dan freq() pada dataset concrete_train dan concrete_test yang dapat dilihat di Tabel 4.1.

Tabel 4.1: Tabel Summary

(a) Summary numerik training
(b) Summary numerik testing
(c) Frekuensi age training
Freq % Valid % Valid Cum. % Total % Total Cum.
1 2 0.24 0.24 0.24 0.24
3 115 13.94 14.18 13.94 14.18
7 95 11.52 25.70 11.52 25.70
14 50 6.06 31.76 6.06 31.76
28 339 41.09 72.85 41.09 72.85
56 71 8.61 81.45 8.61 81.45
90 44 5.33 86.79 5.33 86.79
91 18 2.18 88.97 2.18 88.97
100 43 5.21 94.18 5.21 94.18
120 2 0.24 94.42 0.24 94.42
180 21 2.55 96.97 2.55 96.97
270 10 1.21 98.18 1.21 98.18
360 6 0.73 98.91 0.73 98.91
365 9 1.09 100.00 1.09 100.00
0 NA NA 0.00 100.00
Total 825 100.00 100.00 100.00 100.00
(d) Frekuensi age testing
Freq % Valid % Valid Cum. % Total % Total Cum.
3 19 9.27 9.27 9.27 9.27
7 31 15.12 24.39 15.12 24.39
14 12 5.85 30.24 5.85 30.24
28 86 41.95 72.20 41.95 72.20
56 20 9.76 81.95 9.76 81.95
90 10 4.88 86.83 4.88 86.83
91 4 1.95 88.78 1.95 88.78
100 9 4.39 93.17 4.39 93.17
120 1 0.49 93.66 0.49 93.66
180 5 2.44 96.10 2.44 96.10
270 3 1.46 97.56 1.46 97.56
365 5 2.44 100.00 2.44 100.00
0 NA NA 0.00 100.00
Total 205 100.00 100.00 100.00 100.00

Informasi statistik diatas telah divisualisasikan di Bab 3 Prapemrosesan data atau Bab 4.1 Visualisasi di Bab 4 ADE. Dan beberapa grafik sudah diberi penjelasan atau informasi yang diperoleh dari memvisualisasikannya. Tapi terdapat grafik yang belum melihat dispersi dataset menggunakan geom_density(). Grafik density plot dapat dilihat di Gambar 4.6. Tapi sebelum melihat grafik density plot, bisa dilihat kecenderungan dispersi (sebaran) data menggunakan skewness() atau kurtosis(). Hasil perhitungan bisa dilihat di Tabel 4.2.

Tabel 4.2: Dispersi data menggunakan skewness() dan kurtosis()

(a) Dispersi concrete_train
skewness kurtosis
cement 0.5033640 -0.5080640
slag 0.8215773 -0.4386317
flyash 0.5458517 -1.3079074
water 0.0680329 0.2406717
super_plast 0.8600918 1.1259952
coarse_agg -0.0279172 -0.5835493
fine_agg -0.2289398 -0.1342315
strength 0.4107550 -0.3284447
(b) Dispersi concrete_test
skewness kurtosis
cement 0.5210288 -0.6336327
slag 0.7020375 -0.8290623
flyash 0.4922340 -1.4372194
water 0.0776284 -0.3864010
super_plast 1.0790926 2.4481578
coarse_agg -0.0813921 -0.7275872
fine_agg -0.4088668 -0.1295096

Dari Tabel 4.2, diperoleh inforasi skewness dan kurtosis yang bisa memberikan kecenderungan distribusi data cenderung ke-kiri ataupun ke-kanan dari distribusi normal. Jika nilai skewness positif, maka data cenderung ke kiri, berlaku juga sebaliknya. Jika nilainya mendekati \(0\), maka dataset cenderung ke distribusi normal. Untuk kurtosis, jika nilainya \(0\) maka bentuk distribusinya seperti distribusi normal (bell-shape). Jika nilainya positif, disebut leptokurtic (lebih runcing kepuncak), sedangkan jika negatif, disebut platykurtic (lebih merata puncaknya)7. Setelah memahami hal tersebut, baru bisa mudah menghubungkan angka tersebut dengan grafik Gambar 4.6 atau Gambar 4.7.

(a) Density plot cement

(b) Density plot slag

(c) Density plot flyash

(d) Density plot water

(e) Density plot super_plast

(f) Density plot coarse_agg

(g) Density plot fine_agg

(h) Density plot strength

Gambar 4.6: Density plot data concrete_train

Dari Gambar 4.6 diatas, terlihat bahwa kecenderungan penyebaran dataset. Yang mendekati distribusi normal antara lain Gambar 4.6 (d), Gambar 4.6 (f), Gambar 4.6 (g), Gambar 4.6 (h) secara visual dengan parameter skewness dan kurtosis di Tabel 4.2 (a). Berikut dispersi untuk dataset concrete_test di Gambar 4.7.

(a) Density plot cement

(b) Density plot slag

(c) Density plot flyash

(d) Density plot water

(e) Density plot super_plast

(f) Density plot coarse_agg

(g) Density plot fine_agg

Gambar 4.7: Density plot data concrete_test

Dari Gambar 4.7 diatas, memiliki bentuk yang tidak jauh berbeda dengan dataset concrete_train di Gambar 4.6. Sehingga, bisa diasumsikan bahwa dataset untuk pengujian bisa mewakili distribusi yang terjadi di dataset training. Informasi diatas akan dibahas kembali saat memasuki pemodelan. Setelah menghitung beberapa parameter statistik, dilanjutkan dengan evaluasi outliers dan/atau anomali.

4.3 Outliers dan anomali

Pada bab-bab sebelumnya, sempat dibahas mengenai “potensi” outlier dari informasi boxplot. Berikut outlier yang diperoleh menggunakan boxplot() dengan argumen plot = FALSE yang disimpan di objek outlier_data dari bagian Bab 3.3.

Objek outlier_data
outlier_data
## $cement
## [1] NA
## 
## $slag
## [1] 359.4 359.4
## 
## $flyash
## [1] NA
## 
## $water
## [1] 121.8 121.8 121.8 121.8 121.8 237.0 247.0 246.9 236.7
## 
## $super_plast
## [1] 32.2 28.2 28.2 32.2 28.2 32.2 28.2
## 
## $coarse_agg
## [1] NA
## 
## $fine_agg
##  [1] 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0
## [13] 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0 594.0 992.6 992.6
## [25] 992.6 992.6 992.6
## 
## $age
##  [1] 270 365 360 365 365 180 180 180 365 270 180 365 365 270 365 270 180 180 180
## [20] 270 270 270 180 270 360 180 180 180 360 180 365 180 365 180 270 180 180 360
## [39] 180 360 180 180 180 180 360 270
## 
## $strength
## [1] 79.99 80.20 79.40 82.60 81.75

Akan tetapi, sebelum mengevaluasi outlier tersebut, terdapat data yang bisa dihilangkan berdasarkan umur beton karena pada data concrete_test terdapat umur beton yang tidak diuji yaitu 1, 360 hari. Sehingga umur beton tersebut bisa dihilangkan di concrete_train. Dan diperoleh id dengan kode O5, O67, O617, O747, O764, O770, O793, O815 merupakan sampel yang tidak akan diuji umur betonnya.

Objek concrete_train_clean_age
concrete_train_clean_age <- concrete_train |> 
  filter(!(id %in% id_sample_not_tested))
concrete_train_clean_age_factored <- concrete_train_clean_age |> 
  mutate(age = as.factor(age))

nrow_concrete_train_clean_age <- concrete_train_clean_age |> nrow()
ncol_concrete_train_clean_age <- concrete_train_clean_age |> ncol()

dim(concrete_train_clean_age)
## [1] 817  10

Jumlah baris concrete_train yang sebelumnya \(825\) baris menjadi \(817\) baris, atau sebanyak \(8\) baris yang dihapus. Adapun proporsi perbandingan umur beton dapat dilihat pada Tabel 4.3.

Tabel 4.3: Banyaknya data dan proporsinya berdasarkan umur beton (age)
age train test train_percentage test_percentage
3 115 19 14.08 9.27
7 95 31 11.63 15.12
14 50 12 6.12 5.85
28 339 86 41.49 41.95
56 71 20 8.69 9.76
90 44 10 5.39 4.88
91 18 4 2.20 1.95
100 43 9 5.26 4.39
120 2 1 0.24 0.49
180 21 5 2.57 2.44
270 10 3 1.22 1.46
365 9 5 1.10 2.44

Untuk memudahkan membandingkan perbandingan data tersebut, dibuatkan juga visualisasinya yang dapat dilihat di Gambar 4.8.

(a) Perbandingan jumlah data

(b) Perbandingan proporsi data

Gambar 4.8: Banyaknya data dan proporsinya berdasarkan umur beton

Di Gambar 4.8 (a), yang membandingkan dengan jumlah data, sudah jelas dataset train pasti lebih banyak karena jumlah observasinya berbeda jauh. Di concrete_train_clean_age terdapat \(817\) observasi, sedangkan di concrete_test terdapat \(205\) observasi. Akan tetapi jika dilihat proporsinya di Gambar 4.8 (b), terlihat bahwa proporsinya tidak jauh berbeda. Sehingga, jika dimodelkan, bisa menggunakan hipotesis bahwa dataset saat training maupun testing merata.

Sejauh ini penghapusan outlier masih sebatas melihat berdasarkan umur beton yang sampai saat ini diasumsikan sebagai categorical atau factor. Akan tetapi, kenyataannya, kuat tekan beton dapat dipengaruhi umur beton dan bersifat kontinu (baik linear maupun non-linear), hanya saja untuk mengetahui kuat tekan beton hanya dapat dilakukan dengan uji kuat tekan beton. Alasan tersebut lah yang memungkinkan bahwa pada variabel age atau umur beton seperti diskrit atau kategori.

4.4 Hubungan linear

Hubungan antara target yaitu strength terhadap variabel lainnya sempat dibahas di Bab 4.1 pada bagian Bab 4.1.3 Scatter plot. Grafik hubungan antar variabel juga bisa dilihat di Gambar 4.5. Pada bagian ini, akan disajikan korelasi dengan beberapa informasi tambahan seperti informasi Confidence Interval (CI) ataupun t-test. Informasi tersebut dapat dilihat di Tabel 4.4. Tabel korelasi dibangkitkan menggunakan fungsi correlation().

Tabel 4.4: Tabel korelasi setiap variabel di dataset concrete_train_clean_age

Tabel Tabel 4.4 menyajikan hubungan antara variabel seluruhnya, akan tetapi yang ingin kita tinjau lebih lanjut adalah hubungan antara target yaitu strength. Berikut informasi yang serupa tapi hanya fokus pada strength sebagai Parameter2 di Tabel 4.5.

Tabel 4.5: Tabel korelasi terhadap strength
Parameter1 Parameter2 r CI_low CI_high t p
cement strength 0.5070 0.4542 0.5562 16.7909 0.0000
age strength 0.3659 0.3050 0.4239 11.2257 0.0000
super_plast strength 0.3631 0.3020 0.4212 11.1250 0.0000
slag strength 0.1251 0.0570 0.1920 3.5985 0.0041
flyash strength -0.1058 -0.1732 -0.0375 -3.0383 0.0246
coarse_agg strength -0.1346 -0.2014 -0.0667 -3.8791 0.0015
fine_agg strength -0.1930 -0.2581 -0.1260 -5.6140 0.0000
water strength -0.2837 -0.3456 -0.2194 -8.4474 0.0000

Dari Tabel 4.5 diatas, didapatkan informasi sebagai berikut:

  • Variabel cement memiliki korelasi positif tertinggi dibandingkan variabel lainnya.
  • Meskipun water memiliki korelasi negatif terbesar, perbandingan dengan variabel sebelumnya masih tergolong sedikit.
  • Terlepas nilai korelasinya, besarnya p-value seluruh variabel dibawah significance level (\(\alpha=0.05\)), sehingga bisa dibilang variabel dapat dianggap sebagai signifikan terhadap hubungan linearnya.

Sama halnya dengan Gambar 4.5, divisualisasikan ulang dengan informasi correlation test di Gambar 4.9.

(a) Hubungan dengan cement

(b) Hubungan dengan slag

(c) Hubungan dengan flyash

(d) Hubungan dengan water

(e) Hubungan dengan super_plast

(f) Hubungan dengan coarse_agg

(g) Hubungan dengan fine_agg

Gambar 4.9: Korelasi features dengan strength

Setelah melakukan korelasi atau hubungan linear, dapat dilanjutkan ke pemodelan baik regresi linear ataupun model lainnya. Sebelum itu, dataset bisa ditransformasikan terlebih dahulu untuk mempersiapkan dataset sebelum pemodelan. Meski, saat pemodelan akan muncul ide baru untuk memperoleh kriteria prediksi yang akurat.

4.5 Transformasi

Dari panjangnya narasi yang telah dibuat mengenai dataset, selalu disinggung mengenai perlakuan variabel umur beton age. Sejauh ini, variabel tersebut diperlakukan sebagai kategorikal, tapi bagaimana jika diperlakukan sebagai numerik yang kontinu. Sehingga, saat pemodelan bisa diprediksikan ketika menggunakan input umur beton yang tidak tercatat di dataset training. Berikut percobaan mentransformasikan umur beton menggunakan log() dan sqrt() yang dapat dilihat hasilnya di Gambar 4.10.

(a) Sebelum transformasi

(b) Setelah transformasi log()

(c) Setelah transformasi sqrt()

Gambar 4.10: Hubungan age vs. strength sebelum dan setelah transformasi

Dari Gambar 4.10 diatas, dapat dilihat secara visual pengaruh penggunaan fungsi log() memiliki hasil yang baik dibandingkan sqrt(). Tujuan transformasi ini menyamaratakan atau membuat bidang baru sehingga nilai umur beton dari setiap pengujiannya memiliki jarak yang sama, sehingga saat pemodelan, model akan lebih sensitif terhadap umur beton. Dapat dilihat juga pada Gambar 4.10 (c), transformasi sqrt() juga dapat mencapai tujuan tersebut, akan tetapi penggunaan log() jauh lebih baik. Selain itu, di Gambar 4.10 terdapat informasi statistik korelasinya. Yang jika dilihat korelasi terbaik diperoleh menggunakan transformasi log(). Jika kita melakukan visualiasasi seperti di Gambar 4.9 dan melibatkan variabel umur beton, diperoleh kelengkapan hubungan seluruh independent variable dengan dependent varible di Gambar 4.11.

(a) Hubungan dengan cement

(b) Hubungan dengan slag

(c) Hubungan dengan flyash

(d) Hubungan dengan water

(e) Hubungan dengan super_plast

(f) Hubungan dengan coarse_agg

(g) Hubungan dengan fine_agg

(h) Hubungan dengan age

Gambar 4.11: Korelasi features dengan strength

Transformasi lebih lanjutnya akan disesuaikan berdasarkan model yang akan digunakan, dan digunakan berbagai jenis dataset yang akan dijadikan sebagai input model (variasi input data untuk setiap model).

4.6 Rekapitulasi

Setelah mengeksplorasi dataset concrete_train dan concrete_test pada akhirnya diambil beberapa tindakan dan informasi sebagai berikut:

  • Pada Bab 4.3 Outliers, umur beton dari concrete_train yang tidak tersedia di concrete_test dihapus observasinya. Meskipun, keputusan tersebut bisa saja tidak begitu signifikan terhadap nanti pemodelan. Sehingga akan dipersiapkan dataset yang menyertakan umur beton tersebut atau tidak.
  • Selain itu, dataset yang diduga sebagai outlier menggunakan box plot, tidak dilakukan tindakan sama sekali. Karena observasi tersebut dianggap sebagai observasi yang valid dan relevan di dataset dan bukan hasil kekeliruan.
  • Pada Bab 4.5 Transformasi, variabel umur beton age dipilih transformasi log() untuk memudahkan model untuk mengenali perbedaan antara umur beton yang berdekatan.

Sebelum memasuki pemodelan akan dipersiapkan turunan dari objek concrete_train dan concrete_test untuk memudahkan saat pengelolaan kodenya maupun bereksperimen di saat pemodelan. Dan disimpan sebagai objek dfsource_* (untuk membedakan dengan objek data_[train/val/test]_*) dan dfeval_* (evaluasi / concrete_test). Objek *_trimmed_* diartikan objek yang telah menghapus umur beton 1, 360 hari.

Pembuatan objek dfsource dan dfeval
dfsource_original <- concrete_train
dfsource_original_log <- dfsource_original |> 
  mutate(age = log(age))

dfsource_trimmed <- concrete_train_clean_age
dfsource_trimmed_log <- dfsource_trimmed |> 
  mutate(age = log(age))

dfeval_original <- concrete_test
dfeval_original_log <- dfeval_original |> 
  mutate(age = log(age))

set.seed(41608481)
sample_eda_index <- sample(nrow(dfeval_original), 20) |> as.integer()

dfsource_original |> slice(sample_eda_index)
dfsource_original_log |> slice(sample_eda_index)
dfsource_trimmed |> slice(sample_eda_index)
dfsource_trimmed_log |> slice(sample_eda_index)
dfeval_original |> slice(sample_eda_index)
dfeval_original_log |> slice(sample_eda_index)

Tabel 4.6: Sample Dataset hasil Exploratory Data Analysis

(a) Data dfsource_original
(b) Data dfsource_original_log
(c) Data dfsource_trimmed
(d) Data dfsource_trimmed_log
(e) Data dfeval_original
(f) Data dfeval_original_log

Dan berikut summary dari dataset diatas di Tabel 4.7.

Tabel 4.7: Tabel Summary

(a) Summary numerik dfsource_original
Min Q1 Median Mean Q3 Max
cement 102.00 194.70 275.10 280.94 350.00 540.0
slag 0.00 0.00 20.00 73.18 141.30 359.4
flyash 0.00 0.00 0.00 54.03 118.20 200.1
water 121.80 164.90 184.00 181.12 192.00 247.0
super_plast 0.00 0.00 6.50 6.27 10.10 32.2
coarse_agg 801.00 932.00 968.00 972.82 1028.40 1145.0
fine_agg 594.00 734.00 780.10 775.63 826.80 992.6
age 1.00 7.00 28.00 45.14 56.00 365.0
strength 2.33 23.64 34.57 35.79 45.94 82.6
(b) Summary numerik dfsource_trimmed
Min Q1 Median Mean Q3 Max
cement 102.00 194.70 273.00 280.64 350.00 540.0
slag 0.00 0.00 22.00 73.48 142.50 359.4
flyash 0.00 0.00 0.00 54.56 118.20 200.1
water 121.80 164.90 184.00 181.01 192.00 247.0
super_plast 0.00 0.00 6.70 6.33 10.10 32.2
coarse_agg 801.00 932.00 968.00 972.46 1028.40 1145.0
fine_agg 594.00 734.00 780.00 775.46 826.80 992.6
age 3.00 7.00 28.00 42.94 56.00 365.0
strength 2.33 23.64 34.56 35.82 46.23 82.6
(c) Summary numerik dfeval_original
Min Q1 Median Mean Q3 Max
cement 122.60 190.70 265.00 282.10 359.0 540.0
slag 0.00 0.00 26.00 76.78 151.2 305.3
flyash 0.00 0.00 0.00 54.81 121.6 194.9
water 127.00 164.90 185.70 183.39 195.0 228.0
super_plast 0.00 0.00 6.00 5.96 10.4 32.2
coarse_agg 801.00 932.00 967.00 973.31 1043.6 1134.3
fine_agg 594.00 719.70 777.80 765.32 804.0 925.7
age 3.00 14.00 28.00 47.75 56.0 365.0
strength 3.32 23.85 33.72 35.94 46.2 79.3
(d) Summary numerik dfsource_original_log
Min Q1 Median Mean Q3 Max
cement 102.00 194.70 275.10 280.94 350.00 540.0
slag 0.00 0.00 20.00 73.18 141.30 359.4
flyash 0.00 0.00 0.00 54.03 118.20 200.1
water 121.80 164.90 184.00 181.12 192.00 247.0
super_plast 0.00 0.00 6.50 6.27 10.10 32.2
coarse_agg 801.00 932.00 968.00 972.82 1028.40 1145.0
fine_agg 594.00 734.00 780.10 775.63 826.80 992.6
age 0.00 1.95 3.33 3.15 4.03 5.9
strength 2.33 23.64 34.57 35.79 45.94 82.6
(e) Summary numerik dfsource_trimmed_log
Min Q1 Median Mean Q3 Max
cement 102.00 194.70 273.00 280.64 350.00 540.0
slag 0.00 0.00 22.00 73.48 142.50 359.4
flyash 0.00 0.00 0.00 54.56 118.20 200.1
water 121.80 164.90 184.00 181.01 192.00 247.0
super_plast 0.00 0.00 6.70 6.33 10.10 32.2
coarse_agg 801.00 932.00 968.00 972.46 1028.40 1145.0
fine_agg 594.00 734.00 780.00 775.46 826.80 992.6
age 1.10 1.95 3.33 3.14 4.03 5.9
strength 2.33 23.64 34.56 35.82 46.23 82.6
(f) Summary numerik dfeval_original_log
Min Q1 Median Mean Q3 Max
cement 122.60 190.70 265.00 282.10 359.00 540.0
slag 0.00 0.00 26.00 76.78 151.20 305.3
flyash 0.00 0.00 0.00 54.81 121.60 194.9
water 127.00 164.90 185.70 183.39 195.00 228.0
super_plast 0.00 0.00 6.00 5.96 10.40 32.2
coarse_agg 801.00 932.00 967.00 973.31 1043.60 1134.3
fine_agg 594.00 719.70 777.80 765.32 804.00 925.7
age 1.10 2.64 3.33 3.23 4.03 5.9
strength 3.32 23.85 33.72 35.94 46.20 79.3
(g) Frekuensi age dfsource_original
Freq % Valid % Valid Cum. % Total % Total Cum.
1 2 0.24 0.24 0.24 0.24
3 115 13.94 14.18 13.94 14.18
7 95 11.52 25.70 11.52 25.70
14 50 6.06 31.76 6.06 31.76
28 339 41.09 72.85 41.09 72.85
56 71 8.61 81.45 8.61 81.45
90 44 5.33 86.79 5.33 86.79
91 18 2.18 88.97 2.18 88.97
100 43 5.21 94.18 5.21 94.18
120 2 0.24 94.42 0.24 94.42
180 21 2.55 96.97 2.55 96.97
270 10 1.21 98.18 1.21 98.18
360 6 0.73 98.91 0.73 98.91
365 9 1.09 100.00 1.09 100.00
0 NA NA 0.00 100.00
Total 825 100.00 100.00 100.00 100.00
(h) Frekuensi age dfsource_trimmed
Freq % Valid % Valid Cum. % Total % Total Cum.
1 0 0.00 0.00 0.00 0.00
3 115 14.08 14.08 14.08 14.08
7 95 11.63 25.70 11.63 25.70
14 50 6.12 31.82 6.12 31.82
28 339 41.49 73.32 41.49 73.32
56 71 8.69 82.01 8.69 82.01
90 44 5.39 87.39 5.39 87.39
91 18 2.20 89.60 2.20 89.60
100 43 5.26 94.86 5.26 94.86
120 2 0.24 95.10 0.24 95.10
180 21 2.57 97.67 2.57 97.67
270 10 1.22 98.90 1.22 98.90
360 0 0.00 98.90 0.00 98.90
365 9 1.10 100.00 1.10 100.00
0 NA NA 0.00 100.00
Total 817 100.00 100.00 100.00 100.00
(i) Frekuensi age dfeval_original
Freq % Valid % Valid Cum. % Total % Total Cum.
1 0 0.00 0.00 0.00 0.00
3 19 9.27 9.27 9.27 9.27
7 31 15.12 24.39 15.12 24.39
14 12 5.85 30.24 5.85 30.24
28 86 41.95 72.20 41.95 72.20
56 20 9.76 81.95 9.76 81.95
90 10 4.88 86.83 4.88 86.83
91 4 1.95 88.78 1.95 88.78
100 9 4.39 93.17 4.39 93.17
120 1 0.49 93.66 0.49 93.66
180 5 2.44 96.10 2.44 96.10
270 3 1.46 97.56 1.46 97.56
360 0 0.00 97.56 0.00 97.56
365 5 2.44 100.00 2.44 100.00
0 NA NA 0.00 100.00
Total 205 100.00 100.00 100.00 100.00

Analisis data eksploratif diakhiri di bagian ini, yang akan dilanjutkan ke bagian Bab 5 Pemodelan.

5 Pemodelan

Pemodelan machine learning yang akan dicoba diterapkan antara lain regresi linear, random forest, dan artificial neural networks. Perlu dicatat bahwa untuk pemodelan ini akan lebih fokus ke tujuan utama lembar kerja ini yaitu memprediksikan kuat tekan beton dari variabel yang tersedia. Sehingga, apakah pemodelan sesuai dengan asumsi model (semisal untuk regresi linear harus memenuhi kriteria tertentu) tidak akan disinggung sama sekali.

Pada Bab 5 Pemodelan, berikut beberapa langkah yang akan dilakukan:

  1. Bab 5.1 Cross-Validation: Membagi dataset menjadi training dan validation.
  2. Bab 5.2 Input model: Mempersiapkan input model seperti transformasi, normalisasi ataupun standarisasi.
  3. Bab 5.3 Implementasi model: Implementasi berbagai model.
  4. Bab 5.4 Komparasi model: Membandingkan performa antar model.
  5. Bab 5.5 Evaluasi model: Evaluasi akhir dari model yang terbaik.

5.1 Cross-Validation

Pada bagian ini akan membagi dataset menjadi tiga bagian yaitu training, validation, dan testing. Untuk data training dan validation diperoleh dari dfsource sedangkan testing diperoleh dari dfeval. Setiap objek data input akan dinamai dengan data_train*_*, data_val*_*, dan data_test*_*. Karena di lembar kerja sudah tersedia pemisahan antara training dan testing maka tidak perlu dilakukan initial_split().

Objek data_test_*
# testing
data_test_original <- dfeval_original
data_test_log <- dfeval_original_log

Untuk pemisahan data training dan validation akan dicoba untuk menggunakan proporsi yang berbeda (*1 (\(80\%\)) dengan *2 (\(75\%\))). Penerapan pembagian itu diterapkan di dataset dfsource_original, dfsource_original_log, dfsource_trimmed, dan dfsource_trimmed_log.

Objek data_train*_* dan data_val*_*
set.seed(41608481)
split1_original <- dfsource_original |> validation_split(prop = 0.8)
split2_original <- dfsource_original |> validation_split(prop = 0.75)

data_train1_original <- split1_original |> get_rsplit(1) |> training()
data_train2_original <- split2_original |> get_rsplit(1) |> training()
data_val1_original <- split1_original |> get_rsplit(1) |> testing()
data_val2_original <- split2_original |> get_rsplit(1) |> testing()

index_train1 <- data_train1_original |> rownames() |> as.integer()
index_train2 <- data_train2_original |> rownames() |> as.integer()
index_val1 <- data_val1_original |> rownames() |> as.integer()
index_val2 <- data_val2_original |> rownames() |> as.integer()

data_train1_log <- dfsource_original_log |> slice(index_train1)
data_train2_log <- dfsource_original_log |> slice(index_train2)
data_val1_log <- dfsource_original_log |> slice(index_val1)
data_val2_log <- dfsource_original_log |> slice(index_val2)
Objek data_train*_trimmed_* dan data_val*_trimmed_*
set.seed(41608481)
split1_trimmed <- dfsource_trimmed |> validation_split(prop = 0.8)
split2_trimmed <- dfsource_trimmed |> validation_split(prop = 0.75)

data_train1_trimmed <- split1_trimmed |> get_rsplit(1) |> training()
data_train2_trimmed <- split2_trimmed |> get_rsplit(1) |> training()
data_val1_trimmed <- split1_trimmed |> get_rsplit(1) |> testing()
data_val2_trimmed <- split2_trimmed |> get_rsplit(1) |> testing()

index_train1_trimmed <- data_train1_trimmed |> rownames() |> as.integer()
index_train2_trimmed <- data_train2_trimmed |> rownames() |> as.integer()
index_val1_trimmed <- data_val1_trimmed |> rownames() |> as.integer()
index_val2_trimmed <- data_val2_trimmed |> rownames() |> as.integer()

data_train1_trimmed_log <- dfsource_trimmed_log |> slice(index_train1_trimmed)
data_train2_trimmed_log <- dfsource_trimmed_log |> slice(index_train2_trimmed)
data_val1_trimmed_log <- dfsource_trimmed_log |> slice(index_val1_trimmed)
data_val2_trimmed_log <- dfsource_trimmed_log |> slice(index_val2_trimmed)

Setelah memperoleh bagian data training dan validation. Normalisasi/standarisasi yang dilakukan pada data training akan diterapkan di data validation nantinya. Proses tersebut akan dilakukan di Bab 5.2 Input model. Sebelumnya, dieksplorasi terlebih dahulu antara data training dan validation. Eksplorasi ini tidak jauh berbeda yang telah dilakukan di Bab 4 Analisis data eksploratif.

(a) cement (training)

(b) cement (validation)

(c) slag (training)

(d) slag (validation)

(e) flyash (training)

(f) flyash (validation)

(g) water (training)

(h) water (validation)

(i) super_plast (training)

(j) super_plast (validation)

(k) coarse_agg (training)

(l) coarse_agg (validation)

(m) fine_agg (training)

(n) fine_agg (validation)

(o) age* (training)

(p) age* (validation)

Gambar 5.1: Grafik scatter plot antara data training dan validation

(a) cement (training)

(b) cement (testing)

(c) slag (training)

(d) slag (testing)

(e) flyash (training)

(f) flyash (testing)

(g) water (training)

(h) water (testing)

(i) super_plast (training)

(j) super_plast (testing)

(k) coarse_agg (training)

(l) coarse_agg (testing)

(m) fine_agg (training)

(n) fine_agg (testing)

(o) age* (training)

(p) age* (testing)

(q) strength* (training)

(r) strength* (testing)

Gambar 5.2: Grafik density plot antara data training dan testing

Dari Gambar 5.1 dan Gambar 5.2, perbedaan antara data training dan validation tidak jauh berbeda secara sekilas. Sebagai catatan, grafik variabel age menggunakan yang telah ditransformasi log(). Berikut summary data training dan validation di Tabel 5.1.

Tabel 5.1: Tabel Summary data training dan validation

(a) Summary data training
Min Q1 Median Mean Q3 Max
cement 102.00 192.00 255.00 277.56 350.00 540.00
slag 0.00 0.00 22.00 73.27 137.20 359.40
flyash 0.00 0.00 0.00 56.80 118.30 200.10
water 121.80 164.80 182.00 180.57 192.00 247.00
super_plast 0.00 0.00 6.70 6.54 10.40 32.20
coarse_agg 801.00 931.20 968.00 970.74 1028.40 1145.00
fine_agg 594.00 739.30 780.10 778.71 840.50 992.60
age 0.00 1.95 3.33 3.09 4.03 5.90
strength 2.33 22.93 34.20 35.20 44.86 81.75
(b) Summary data validation
Min Q1 Median Mean Q3 Max
cement 102.00 190.50 277.15 286.68 366.50 540.0
slag 0.00 0.00 16.30 69.52 137.50 305.3
flyash 0.00 0.00 0.00 51.63 111.60 193.0
water 121.80 162.05 181.70 179.50 192.00 228.0
super_plast 0.00 0.00 6.60 6.14 9.90 28.2
coarse_agg 819.00 932.00 973.65 976.91 1040.00 1125.0
fine_agg 594.00 738.00 781.05 779.73 828.00 943.1
age 1.10 1.95 3.33 3.10 4.03 5.6
strength 4.57 22.69 36.33 35.92 50.42 79.4

Setelah membuat dua jenis, ternyata data *_trimmed tidak akan digunakan sama sekali karena jika menganggap umur beton sebagai variabel numerik dan kontinu, umur beton yang tidak tersedia di data validation bisa di interpolasi dari dataset training-nya. Sehingga, untuk seterusnya hanya akan digunakan data original yang belum ditransformasi ataupun sudah (variabel age saja).

5.2 Input model

Untuk mengurangi kesulitan mengikuti kode, akan disederhanakan lagi mengenai pembagian yang dilakukan pada Bab 5.1 Cross-validation. Untuk dataset input hanya ada dua objek yaitu train0 dan val0. Dan untuk yang telah dinormalisasi akan diberi nama train1 dan val1. Jika akan dibuat modifikasi lainnya, akan diberi nama train2, val2, train3, val3, dst.

Objek training dan validation
train0 <- data_train1_log
val0 <- data_val1_log
test0 <- data_test_log

Digunakan data yang variabel age telah ditransformasi terkait informasi yang diperoleh saat Bab 4 Analisis data eksploratif.

5.2.1 Normalisasi / Standarisasi

Melihat distribusi data training dan validation beserta statistiknya di Gambar 5.2 dan Tabel 5.1. Berikut beberapa yang dilakukan terhadap data yang digunakan untuk model.

  • Variabel slag, flyash, dan super_plast memiliki nilai \(0\) yang dominan. Untuk menghindari perubahan distribusi tersebut, dilakukan Min Max Scaling. Nilai \(0\) ini merupakan informasi signifikan yang tidak bisa diabaikan oleh karena itu, penggunaan min max scaling diharapkan mampu mempertahankan informasi tersebut saat pemodelan.
  • Variabel cement, water, coarse_agg, dan fine_agg hampir mendekati dengan distribusi normal (meski kenyataannya kurtosis dan skewness-nya bisa tidak sesuai dengan karakterstik distribusi normal), sehingga untuk variabel tersebut bisa diterapkan standarisasi.
  • Untuk variabel age yang telah ditransformasikan dengan log() akan tetap menggunakan hasil transformasinya.
  • Variabel strength sebagai target juga akan di normalisasi, tapi sebagai set input yang berbeda karena harapannya, hanya features saja yang diubah. Kebutuhan ini akan disesuaikan dengan modelnya. Dan digunakan min max scaling untuk dapet dilakukan inverse transform.
  • Untuk eksperimen lainnya (jika sempat), akan dilakukan transformasi PCA untuk variabel yang memiliki proses scaling yang berbeda (kecuali age yang diabaikan).

Prapemrosesan input data diatas akan dibuat bervariasi sehingga dapat juga dianalisis perbedaan ketika menggunakan input data yang memiliki prapemrosesan berbeda-beda. Prapemrosesan data akan menggunakan fungsi preProcess().

Prapemrosesan input data untuk train1, val1, test1
minmax_scaler <- preProcess(train0 |> select(slag, flyash, super_plast), method = c("range"))
standard_scaler <- preProcess(train0 |> select(cement, water, coarse_agg, fine_agg), method = c("center", "scale"))

train1 <- train0 |> 
  predict(minmax_scaler, newdata = _) |> 
  predict(standard_scaler, newdata = _)

val1 <- val0 |>
  predict(minmax_scaler, newdata = _) |> 
  predict(standard_scaler, newdata = _)

test1 <- test0 |>
  predict(minmax_scaler, newdata = _) |> 
  predict(standard_scaler, newdata = _)

Objek train1, val1, dan test1 merupakan objek yang seluruh kolom kecuali age dan strength yang normalisasi/standarisasi. Sebagai catatan, perubahan ini tidak akan mengubah korelasi data sama sekali karena proses ini tidak memindahkan nilai variabel ke bidang yang baru.

Prapemrosesan input data untuk train2, val2, test2
min_train_strength <- min(train1$strength)
max_train_strength <- max(train1$strength)

strength_minmax <- train1 |> select(strength) |> 
  preProcess(method = c("range"))

train2 <- strength_minmax |> predict(newdata = train1)
val2   <- strength_minmax |> predict(newdata = val1)
test2  <- test1

Objek train2, val2, dan test2 merupakan objek yang variabel strength sudah dinormalisasikan. Nilai min_train_strength dan max_train_strength untuk mentransformasikan nilai ke skala original.

Sejauh ini persiapan untuk input data terdapat 3 jenis data yang memiliki prapemrosesan yang berbeda yaitu:

  1. train0, val0, test0: dataset asli yang kolom age telah ditransformasik menggunakan log().
  2. train1, val1, test1: dataset train0 yang variabel selain age disesuaikan dengan normalisasi atau standarisasi.
  3. train2, val2, test2: dataset train1 yang target variable (strength) di normalisasikan dengan min max scaling.

Masih terdapat eksperimen yang bisa dilakukan seperti membuat objek baru dengan potensi outlier dihilangkan dari data training, kemudian mentransformasi seluruh prediktor menggunakan log() atau sqrt(). Akan tetapi langkah tersebut ketika dari 3 set training diatas tidak memenuhi kriteria model.

5.3 Implementasi pemodelan

Pemodelan yang akan dilakukan antara lain regresi linear menggunakan lm(), random forest menggunakan randomForest(), dan neural networks menggunakan keras_model_sequential()

5.3.1 Regresi linear

Dalam pemodelan regresi linear terdapat asumsi yang harus dipenuhi agar dataset dianggap sebagai model linear. Akan tetapi, pengujian tersebut tidak akan dilakukan di lembar kerja ini. Karena fokus utamanya adalah memprediksikan kuat tekan beton yang akurat. Pemodelan menggunakan lm().

Pemodelan regresi linear lm()
model_lm0 <- lm(strength ~ ., train0 |> select(-id))
model_lm1 <- lm(strength ~ ., train1 |> select(-id))
model_lm2 <- lm(strength ~ ., train2 |> select(-id))
Menampilkan summary model
summary(model_lm0)
summary(model_lm1)
summary(model_lm2)

Call:
lm(formula = strength ~ ., data = select(train0, -id))

Residuals:
     Min       1Q   Median       3Q      Max 
-22.3018  -4.2166   0.0043   3.7735  29.9234 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -93.067078  25.399357  -3.664 0.000274 ***
cement        0.139384   0.008163  17.076  < 2e-16 ***
slag          0.119423   0.009504  12.566  < 2e-16 ***
flyash        0.103465   0.011909   8.688  < 2e-16 ***
water        -0.093172   0.038102  -2.445 0.014800 *  
super_plast   0.119893   0.085767   1.398 0.162741    
coarse_agg    0.035130   0.008829   3.979  7.9e-05 ***
fine_agg      0.038128   0.010267   3.714 0.000226 ***
age           8.801068   0.263457  33.406  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 7.039 on 522 degrees of freedom
Multiple R-squared:  0.8174,    Adjusted R-squared:  0.8146 
F-statistic: 292.1 on 8 and 522 DF,  p-value: < 2.2e-16

Call:
lm(formula = strength ~ ., data = select(train1, -id))

Residuals:
     Min       1Q   Median       3Q      Max 
-22.3018  -4.2166   0.0043   3.7735  29.9234 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -7.4110     1.7385  -4.263  2.4e-05 ***
cement       14.3818     0.8422  17.076  < 2e-16 ***
slag         42.9205     3.4156  12.566  < 2e-16 ***
flyash       20.7033     2.3830   8.688  < 2e-16 ***
water        -2.0087     0.8214  -2.445 0.014800 *  
super_plast   3.8606     2.7617   1.398 0.162741    
coarse_agg    2.7673     0.6955   3.979  7.9e-05 ***
fine_agg      3.1389     0.8452   3.714 0.000226 ***
age           8.8011     0.2635  33.406  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 7.039 on 522 degrees of freedom
Multiple R-squared:  0.8174,    Adjusted R-squared:  0.8146 
F-statistic: 292.1 on 8 and 522 DF,  p-value: < 2.2e-16

Call:
lm(formula = strength ~ ., data = select(train2, -id))

Residuals:
     Min       1Q   Median       3Q      Max 
-0.28081 -0.05309  0.00005  0.04751  0.37677 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.122651   0.021890  -5.603 3.41e-08 ***
cement       0.181085   0.010605  17.076  < 2e-16 ***
slag         0.540424   0.043007  12.566  < 2e-16 ***
flyash       0.260681   0.030005   8.688  < 2e-16 ***
water       -0.025292   0.010343  -2.445 0.014800 *  
super_plast  0.048609   0.034773   1.398 0.162741    
coarse_agg   0.034844   0.008757   3.979 7.90e-05 ***
fine_agg     0.039523   0.010643   3.714 0.000226 ***
age          0.110817   0.003317  33.406  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.08863 on 522 degrees of freedom
Multiple R-squared:  0.8174,    Adjusted R-squared:  0.8146 
F-statistic: 292.1 on 8 and 522 DF,  p-value: < 2.2e-16

Dari ketiga model dengan input dataset yang berbeda, nilai adjusted R-squared tidak berubah sama sekali karena perubahan train0 ke train1 atau train2 dikarenakan tidak ada transformasi yang mengubah distribusi dataset sama sekali. Sehingga, hasil pemodelannya sama saja.

5.3.2 Random Forest

Untuk random forest dataset train* dan val* akan digabungkan karena untuk validasi set dibuat saat training dengan fold yang diatur menggunakan trainControl() dengan argumen method = "repeatedcv".

Pemodelan random forest
ctrlconfig <- trainControl(
  method = "repeatedcv", number = 6, repeats = 4
)

if (file.exists("model/model_rf0.RDS")) {
  model_rf0 <- readRDS("model/model_rf0.RDS")
} else {
  set.seed(41608481)
  model_rf0 <- train(strength ~ ., data = rbind(train0, val0) |> select(-id), method = "rf", trControl = ctrlconfig)
  model_rf0 |> saveRDS("model/model_rf0.RDS")
}

if (file.exists("model/model_rf1.RDS")) {
  model_rf1 <- readRDS("model/model_rf1.RDS")
} else {
  set.seed(41608481)
  model_rf1 <- train(strength ~ ., data = rbind(train1, val1) |> select(-id), method = "rf", trControl = ctrlconfig)
  model_rf1 |> saveRDS("model/model_rf1.RDS")
}

if (file.exists("model/model_rf2.RDS")) {
  model_rf2 <- readRDS("model/model_rf2.RDS")
} else {
  set.seed(41608481)
  model_rf2 <- train(strength ~ ., data = rbind(train2, val2) |> select(-id), method = "rf", trControl = ctrlconfig)
  model_rf2 |> saveRDS("model/model_rf2.RDS")
}

Berikut informasi final model (kiri/atas (train0) sampai kanan/bawah (train2)).

Menampilkan final model Random Forest
model_rf0$finalModel
model_rf1$finalModel
model_rf2$finalModel

Call:
 randomForest(x = x, y = y, mtry = param$mtry) 
               Type of random forest: regression
                     Number of trees: 500
No. of variables tried at each split: 5

          Mean of squared residuals: 28.46287
                    % Var explained: 89.54

Call:
 randomForest(x = x, y = y, mtry = param$mtry) 
               Type of random forest: regression
                     Number of trees: 500
No. of variables tried at each split: 5

          Mean of squared residuals: 28.33125
                    % Var explained: 89.59

Call:
 randomForest(x = x, y = y, mtry = param$mtry) 
               Type of random forest: regression
                     Number of trees: 500
No. of variables tried at each split: 5

          Mean of squared residuals: 0.004538333
                    % Var explained: 89.48

Dari hasil diatas perubahan prediktor tidak mempengaruhi hasilnya, akan tetapi ketika mentransformasi target hasilnya akan berubah.

5.3.3 Artificial Neural Networks

Untuk pemodelan ANN terdapat perubahan mengenai input data. Pada pemodelan ANN digunakan recipe() (meski hanya menghilangkan id saja 😅) dan diperlukan prapemrosesan lebih lanjut lagi. Untuk dataset yang digunakan hanya train0, val0, dan test0. Dikarenakan untuk proses normalisasi akan menggunakan layer_normalization(). Dan karena pemisahan training dan testing sudah dilakukan terpisah sejak awal, tidak perlu melakukan initial_split(). Akan tetapi untuk validation tetap menggunakan val0.

Mempersiapkan input data features dan target
dataset_training <- recipe(strength ~ ., rbind(train0, val0)) |> 
  step_rm(id) |> 
  prep() |> 
  bake(new_data = NULL)

train_features <- dataset_training |> select(-strength)
train_target <- dataset_training |> select(strength)

Untuk pemodelan ANN, akan dicoba 3 jenis model Deep Neural Networks yang memiliki variasi jumlah hidden layers beserta node-nya. Penamaan dimulai dari angka 3 agar tidak tertukar/bingung dengan model dari jenis set input data sebelumnya (model_*0 - model_*2). Dan perlu dicatat bahwa target variabel tidak ditransformasi sama sekali.

Fungsi build_and_compile_model*
build_and_compile_model3 <- function(norm) {
  model <- keras_model_sequential(name = "model3") |> 
    norm() |> 
    layer_dense(64, activation = "relu") |> 
    layer_dense(64, activation = "relu") |> 
    layer_dense(1)
  
  model |> compile(
    loss = "mean_absolute_error",
    optimizer = optimizer_adam(0.001),
    metrics = "mse"
  )
  
  model
}

build_and_compile_model4 <- function(norm) {
  model <- keras_model_sequential(name = "model4") |> 
    norm() |> 
    layer_dense(64, activation = "relu") |> 
    layer_dense(32, activation = "relu") |> 
    layer_dense(16, activation = "relu") |> 
    layer_dense(1)
  
  model |> compile(
    loss = "mean_absolute_error",
    optimizer = optimizer_adam(0.001),
    metrics = "mse"
  )
  
  model
}

build_and_compile_model5 <- function(norm) {
  model <- keras_model_sequential(name = "model5") |> 
    norm() |> 
    layer_dense(32, activation = "relu") |> 
    layer_dense(16, activation = "relu") |> 
    layer_dense(1)
  
  model |> compile(
    loss = "mean_absolute_error",
    optimizer = optimizer_adam(0.001),
    metrics = "mse"
  )
  
  model
}
Model NN
normalizer <- layer_normalization(axis = -1L)
normalizer |> adapt(as.matrix(train_features))

model_nn3 <- build_and_compile_model3(normalizer)
model_nn4 <- build_and_compile_model4(normalizer)
model_nn5 <- build_and_compile_model5(normalizer)

model_nn3 |> summary()
## Model: "model3"
## ________________________________________________________________________________
##  Layer (type)                  Output Shape               Param #    Trainable  
## ================================================================================
##  normalization (Normalization)  (None, 8)                 17         Y          
##  dense_2 (Dense)               (None, 64)                 576        Y          
##  dense_1 (Dense)               (None, 64)                 4160       Y          
##  dense (Dense)                 (None, 1)                  65         Y          
## ================================================================================
## Total params: 4,818
## Trainable params: 4,801
## Non-trainable params: 17
## ________________________________________________________________________________
model_nn4 |> summary()
## Model: "model4"
## ________________________________________________________________________________
##  Layer (type)                  Output Shape               Param #    Trainable  
## ================================================================================
##  normalization (Normalization)  (None, 8)                 17         Y          
##  dense_6 (Dense)               (None, 64)                 576        Y          
##  dense_5 (Dense)               (None, 32)                 2080       Y          
##  dense_4 (Dense)               (None, 16)                 528        Y          
##  dense_3 (Dense)               (None, 1)                  17         Y          
## ================================================================================
## Total params: 3,218
## Trainable params: 3,201
## Non-trainable params: 17
## ________________________________________________________________________________
model_nn5 |> summary()
## Model: "model5"
## ________________________________________________________________________________
##  Layer (type)                  Output Shape               Param #    Trainable  
## ================================================================================
##  normalization (Normalization)  (None, 8)                 17         Y          
##  dense_9 (Dense)               (None, 32)                 288        Y          
##  dense_8 (Dense)               (None, 16)                 528        Y          
##  dense_7 (Dense)               (None, 1)                  17         Y          
## ================================================================================
## Total params: 850
## Trainable params: 833
## Non-trainable params: 17
## ________________________________________________________________________________
Fitting model
if (file.exists("model/model_nn3")) {
  # model_nn3 <- load_model_tf("model/model_nn3")
  # model_nn3 <- load_model_hdf5("model/model_nn3.h5")
  model_nn3 |> load_model_weights_hdf5("model/model_nn3_weights.h5")
  history_nn3 <- readRDS("model/history_nn3.RDS")
} else {
  set.seed(41608481)
  print("FITTING model_nn3")
  history_nn3 <- model_nn3 |> fit(
    as.matrix(train_features),
    as.matrix(train_target),
    validation_split = 0.2,
    verbose = 0,
    epochs = 100
  )
  model_nn3 |> save_model_tf("model/model_nn3")
  model_nn3 |> save_model_weights_tf("model/model_nn3_weights")
  model_nn3 |> save_model_hdf5("model/model_nn3.h5")
  model_nn3 |> save_model_weights_hdf5("model/model_nn3_weights.h5")
  history_nn3 |> saveRDS("model/history_nn3.RDS")
}

if (file.exists("model/model_nn4")) {
  # model_nn4 <- load_model_tf("model/model_nn4")
  # model_nn4 <- load_model_hdf5("model/model_nn4.h5")
  model_nn4 |> load_model_weights_hdf5("model/model_nn4_weights.h5")
  history_nn4 <- readRDS("model/history_nn4.RDS")
} else {
  set.seed(41608481)
  print("FITTING model_nn4")
  history_nn4 <- model_nn4 |> fit(
    as.matrix(train_features),
    as.matrix(train_target),
    validation_split = 0.2,
    verbose = 0,
    epochs = 100
  )
  model_nn4 |> save_model_tf("model/model_nn4")
  model_nn4 |> save_model_weights_tf("model/model_nn4_weights")
  model_nn4 |> save_model_hdf5("model/model_nn4.h5")
  model_nn4 |> save_model_weights_hdf5("model/model_nn4_weights.h5")
  history_nn4 |> saveRDS("model/history_nn4.RDS")
}

if (file.exists("model/model_nn5")) {
  # model_nn5 <- load_model_tf("model/model_nn5")
  # model_nn5 <- load_model_hdf5("model/model_nn5.h5")
  model_nn5 |> load_model_weights_hdf5("model/model_nn5_weights.h5")
  history_nn5 <- readRDS("model/history_nn5.RDS")
} else {
  set.seed(41608481)
  print("FITTING model_nn5")
  history_nn5 <- model_nn5 |> fit(
    as.matrix(train_features),
    as.matrix(train_target),
    validation_split = 0.2,
    verbose = 0,
    epochs = 100
  )
  model_nn5 |> save_model_tf("model/model_nn5")
  model_nn5 |> save_model_weights_tf("model/model_nn5_weights")
  model_nn5 |> save_model_hdf5("model/model_nn5.h5")
  model_nn5 |> save_model_weights_hdf5("model/model_nn5_weights.h5")
  history_nn5 |> saveRDS("model/history_nn5.RDS")
}

Seluruh model yang telah dibuat akan dibandingkan dan dilihat mengenai performanya berdasarkan dataset validation yang sudah dibuat sebelumnya.

5.4 Komparasi model

Bagian ini akan membandingkan antara hasil model berdasarkan input data yang berbeda dengan perbandingan antara arsitektur yang digunakan.

5.4.1 Regresi Linear

Pada bagian Bab 5.3.1, dilakukan tiga model dengan tiga jenis input data yang berbeda. Perbandingan performa tiap modelnya bisa dilihat di Tabel 5.2.

Tabel 5.2: Perbandingan antar model regresi linear
Name Model AIC AIC_wt AICc AICc_wt BIC BIC_wt R2 R2_adjusted RMSE Sigma
model_lm0 lm 3590.233 0 3590.656 0 3632.981 0 0.8173908 0.8145922 6.9787025 7.0386066
model_lm1 lm 3590.233 0 3590.656 0 3632.981 0 0.8173908 0.8145922 6.9787025 7.0386066
model_lm2 lm -1055.751 1 -1055.328 1 -1013.004 1 0.8173908 0.8145922 0.0878708 0.0886251

Dari Tabel 5.2, diketahui bahwa nilai skor R2 maupun Adjusted R2, sama saja karena perubahan normalisasi maupun standarisasi tidak mempengaruhi di model regresi linear. Seperti yang diketahui sebelumnya, ketika variabel umur beton (age) tidak ditransformasikan dengan log() hubungan korelasinya dengan kuat tekan beton (strength) tidak begitu baik. Meski, bisa dilakukan pemodelan dengan input data yang tanpa transformasi. Bisa diperkirakan bahwa hasil tanpa transformasi akan jauh lebih buruk dibandingkan setelah membuat independent variable baru dengan transformasi log().

Nilai estimasi parameternya model linear bisa disajikan dalam grafik yang dapat dilihat di Gambar 5.3 menggunakan plot_summs().

Gambar 5.3: Nilai estimasi parameter setiap variabel di model linear

Dari Gambar 5.3 diatas, dapat diperoleh beberapa informasi sebagai berikut:

  • Di model_lm2, estimasi parameter setiap variabel mendekati \(0\), dikarenakan pada model_lm2 menggunakan set data yang variabel target di normalisasikan. Sehingga nilai yang dihasilkan pun estimasinya sangat kecil.
  • Di model_lm0, terlihat hanya variabel age yang memiliki estimasi parameter yang terbesar. Bisa diasumsikan bahwa, paramter tersebut yang memiliki pengaruh lebih besar dibandingkan model lainnya. Tapi hal tersebut bisa juga keliru karena variabel age yang digunakan telah ditransformasi.
  • Pada model_lm1 dimana variabel target yang tidak ditransformasi, estimasinya bernilai besar karena untuk mengkompensasi perubahan yang perlu dilakukan dari variabel prediktor menjadi nilai yang berskala sama dengan target.

Sebagai catatan juga, bahwa nilai estimasi tersebut merupakan nilai yang disajikan ketika menggunakan fungsi summary() di objek model linear. Berikut visualisasi R2 tiap model menggunakan data validation-nya di Gambar 5.4.

(a) model_lm0

(b) model_lm1

(c) model_lm2

Gambar 5.4: Grafik R2 setiap model untuk data validation

Dari Gambar 5.4 tidak ada perbedaan sama sekali dari perbedaan set input data yang saling berbeda, asalkan skala nya tetap sama. Untuk perbandingan selanjutnya digunakan model_lm0. Nilai metrik MAE dan R2 dengan data validation bisa dilihat di Tabel 5.3.

Tabel 5.3: Metrik model linear dengan data validation
model MAE R2
model_lm0 5.2259559 0.852366
model_lm1 5.2259559 0.852366
model_lm2 0.0658015 0.852366

5.4.2 Random Forest

Untuk random forest juga ditemukan bahwa tidak ada perbedaan antara set input data *0 dan *1, sedangkan saat melakukan transformasi pada target (*2), ditemukan perbedaan. Karena visualisasinya cukup terbatas, digunakan R2 untuk melihat perbedaan antar model. Visualisasi R2 untuk model random forest dengan data training dapat dilihat di Gambar 5.5.

(a) model_rf0

(b) model_rf1

(c) model_rf2

Gambar 5.5: Grafik R2 setiap model untuk data training

Sudah jelas untuk data training diperoleh nilai \(R2\) yang mendekati \(1\). Visualiasi yang serupa untuk data validation dapat dilihat di Gambar 5.6.

Pada proses pemodelan random forest, data menggunakan validasi sendiri jika digunakan input keseluruhan data training. Untuk mengatasi model “curang” mengetahui data validation, dilakukan pemodelan ulang. Dibuat model random forest baru yang dinamai model_rf3 dimana data validation tidak terlibat saat pemodelan.

Pemodelan model_rf3
if (file.exists("model/model_rf3.RDS")) {
  model_rf3 <- readRDS("model/model_rf3.RDS")
} else {
  set.seed(41608481)
  model_rf3 <- train(strength ~ ., data = train0 |> select(-id), method = "rf", trControl = ctrlconfig)
  model_rf3 |> saveRDS("model/model_rf3.RDS")
}

(a) model_rf0

(b) model_rf1

(c) model_rf2

(d) model_rf3

Gambar 5.6: Grafik R2 setiap model untuk data validation

Pada Gambar 5.6, model terakhir model_rf3 tidak mendekati sempurna karena model belum pernah mengenali dataset itu sama sekali, berbeda dengan model lainnya. Di Tabel 5.4, bisa dilihat nilai MAE dan R2 menggunakan data validation yang sudah dipisahkan pada tahap prapemrosesan input data.

Tabel 5.4: Metrik model random forest dengan data validation
model MAE R2
model_rf0 1.7657292 0.9828440
model_rf1 1.7570869 0.9830868
model_rf2 0.0220582 0.9825537
model_rf3 4.0071168 0.9080548

Jadi untuk model yang akan digunakan untuk pengujian data test adalah model_rf3.

5.4.3 Artificial Neural Networks

Pada ANN, terdapat tiga model yaitu model_nn3, model_nn4, model_nn5 dengan perbedaan hidden layer. Pemilihan hidden layer dan epoch dilakukan secara sembarang sehingga pemodelan dengan ANN bisa jadi belum mencapai optimal. Untuk memperoleh hyper parameter yang optimal, dapat dilakukan Grid Search. Karena keterbatasan waktu, metode tersebut tidak diterapkan, dan jika mengutak-ngatik dengan library keras atau tensorflow, pribadi, cenderung langsung dilakukan di python.

Grafik loss vs. epoch dapat dilihat pada Gambar 5.7. Dan sebagai catatan, target variabel tidak ditransformasi sama sekali.

(a) model_nn3

(b) model_nn4

(c) model_nn5

Gambar 5.7: Grafik loss setiap epochnya.

Sama halnya dengan sebelumnya, grafik R2 digambarkan juga untuk model neural networks. Hasilnya dapat dilihat di Gambar 5.8.

(a) model_nn3

(b) model_nn4

(c) model_nn5

Gambar 5.8: Grafik R2 setiap model untuk data validation

Hasilnya masih belum cukup memuaskan, terlebih lagi dataset ini ikut serta saat pemodelan. Sehingga, dimungkinkan untuk melakukan model tuning untuk memperoleh hasil yang lebih baik. Metrik R2 dan MAE dapat dilihat di Tabel 5.5.

Tabel 5.5: Metrik model linear dengan data validation
model MAE R2
model_nn3 4.305340 0.8680602
model_nn4 4.253055 0.8757949
model_nn5 4.781307 0.8537945

Dari Tabel 5.5, diperoleh model_nn4 yang terbaik dan akan digunakan sebagai perbandingan.

5.5 Evaluasi model

Setelah memperoleh tiga model yang terbaik, akan dibandingkan antar model untuk memilih model mana yang akan digunakan untuk testing. Perbandingannya dapat dilihat di Gambar 5.9 dan Tabel 5.6.

(a) model_lm0

(b) model_rf3

(c) model_nn4

Gambar 5.9: Grafik R2 setiap model untuk data validation

Tabel 5.6: Metrik model untuk prediksi validation
model MAE R2
model_lm0 5.225956 0.8523660
model_rf3 4.007117 0.9080548
model_nn4 4.253055 0.8757949

Dari semua model yang memenuhi kriteria dimana MAE <= 4 dengan R2 >= 90% yaitu model model_rf3 dan model_nn4. Dan model_rf3 merupakan model yang lebih baik dibandingkan model lainnya.

5.5.1 Prediksi dataset testing

Dialihkan ke 7

6 Penutup

Berikut kesimpulan/ringkasan dan saran yang bisa disampaikan setelah mengerjakan lembar kerja ini.

6.1 Kesimpulan

  • Model yang telah dicoba ada tiga yaitu regresi linear, random forest, dan artificial neural networks. Dengan tiga jenis set input data yang digunakan untuk beberapa model.
  • [REDACTED]
  • Terlepas pernyataan sebelumnya, model machine learning ini bisa membantu pengguna untuk memprediksikan kuat tekan beton berdasarkan komponen dan umur betonnya. Dari model tersebut juga bisa di eksplor lagi lebih lanjut mengenai komponen manakah yang cukup signifikan ketika ingin mencapa kuat tekan beton tertentu.
  • Pembelajaran ini bisa digunakan untuk memahami hubungan kuat tekan beton dan umur dan komponen campurannya. Akan tetapi sebelum menyentuh machine learning, masih bisa dieksplorasi lagi lebih lanjut mengenai dataset ini menggunakan visualisasi maupun uji statistik.

6.2 Saran

  • Transformasi dataset bisa dieksperimenkan lebih lanjut lagi untuk memperoleh pemahaman mengenai terapan machine learning di kasus prediksi kuat tekan beton.
  • Model untuk ANN dan Random Forest masih bisa dikonfigurasi sedemikian rupa untuk meningkatkan performa model lebih baik.

7 Revisi

Beberapa bagian yang telah dihapus akan dilakukan dibagian Bab 7. Dan untuk penambahan seperti variasi model lainnya maupun diskusi terkait akan dilakukan di bab ini atau setelahnya.

7.1 Evaluasi Model

Dari Tabel 5.6, diketahui hanya model_rf3 saja yang memiliki nilai MAE <= 4 dengan R2 >= 90%. Sedangkan untuk model_lm0 dan model_nn4 nilai R2 tidak mencapai sampai 90%. Pada bagian revisi ini, akan dilakukan prediksi dengan dataset testing yang pada bagian sebelumnya telah di hilangkan.

7.1.1 Prediksi dataset testing

Prediksi menggunakan data dari test0 dengan nilai aktualnya diperoleh dari kolom strength atau test0$strength. Hasil disajikan serupa menggunakan grafik R2 untuk setiap modelnya yang dapat dilihat di Gambar 7.1.

(a) model_lm0

(b) model_rf3

(c) model_nn4

Gambar 7.1: Grafik R2 setiap model untuk data test

Dari Gambar 7.1, model terbaik diperoleh oleh model model_rf3 dan model_nn4 yang diketahui nilai \(R\) sebesar \(0.94\) (Untuk memperoleh nilai \(R^2\), tinggal dikuadratkan saja). Berikut hasilnya dalam bentuk tabel Tabel 7.1.

Tabel 7.1: Metrik model untuk prediksi validation
model MAE R2
model_lm0 5.586597 0.8070323
model_rf3 4.414370 0.8797033
model_nn4 4.219878 0.8866720

Dari Tabel 7.1 diperoleh bahwa model_nn4 lah yang memperoleh nilai terbaik dengan nilai \(R^2 = 0.886672\) dan \(\text{MAE} = 4.2198782\). Target awal dari capstone tidak tercapai dari semua model yaitu MAE <= 4 dan R2 >= 90%. Sehingga masih dapat dilakukan peningkatan model untuk memperoleh hasil yang ingin dicapai. Saran yang disampaikan di Bab 6 akan diterapkan nantinya.


Changelog

  • 2022-12-31
    • Versi open-source dokumen ini dirilis di GitHub taruma/concrete-prediction. Modelnya juga telah disertakan.
    • Ditambah bagian Bab 7 untuk melanjutkan lembar kerja ini.
  • 2022-12-22
    • Koreksi koding untuk pemodelan random forest.
    • Pada Gambar 5.1, koreksi testing menjadi validation.
  • 2022-12-20
    • Koreksi penulisan (data training yang seharusnya data validation pada grafik).
    • Menyimpan model ANN dengan berbagai format (HDF5 dan bobotnya).
    • Informasi mengenai open source dokumen ini.