Perkembangan teknologi digital menyebabkan data yang dihasilkan semakin besar dan kompleks, sehingga dibutuhkan model prediksi yang tidak hanya akurat, tetapi juga stabil. Model prediksi tunggal, seperti pohon keputusan (decision tree), umumnya mudah dibangun tetapi rawan mengalami overfitting sehingga kemampuan generalisasinya terbatas (Ilmi dkk., 2025). Salah satu pendekatan untuk mengatasi keterbatasan tersebut adalah ensemble learning, yaitu pendekatan yang menggabungkan banyak model dasar (base learner) agar diperoleh model gabungan yang lebih akurat dan stabil (Fransiska, 2026).
Random Forest (RF) merupakan algoritma ensemble learning berbasis pohon yang membangun banyak pohon keputusan, kemudian menggabungkan prediksinya untuk meningkatkan akurasi dan mengurangi overfitting. RF merupakan pengembangan dari bagging (bootstrap aggregating) yang menambahkan pengacakan pada pemilihan prediktor di setiap node, sehingga pohon-pohon dalam forest tidak berkorelasi terlalu tinggi satu sama lain (Fransiska, 2026). Dengan kata lain, RF menerapkan teknik bagging sekaligus pemilihan fitur secara acak (random feature selection), dan dapat digunakan baik untuk kasus klasifikasi maupun regresi (Wicaksono dkk., 2024; Ilmi dkk., 2025). Selain RF, terdapat Double Random Forest (DRF) yang dikembangkan untuk situasi ketika RF masih mengalami underfitting karena pohon yang terbentuk belum cukup besar. Pada DRF, setiap pohon dibangun menggunakan seluruh data training, sedangkan bootstrap digunakan sementara pada setiap node untuk mencari aturan pemisahan (split) (Fransiska, 2026).
Berdasarkan hal tersebut, praktikum ini dilakukan untuk memahami RF
dan DRF sebagai metode ensemble berbasis decision
tree, mengimplementasikan RF untuk kasus regresi menggunakan R pada
data Friedman dengan membandingkan nilai mtry dan
num.trees, serta mengevaluasi kinerjanya menggunakan
OOB error, MSE, RMSE, MAE, dan \(R^2\) (Fransiska, 2026)..
Adapun batasan masalah yang ditentukan pada penelitian ini, yaitu
lakukan analisis Random Forest secara lengkap mulai dari
persiapan data, pembentukan model, prediksi, evaluasi, visualisasi, dan
interpretasi dengan menggunakan set.seed(234) agar hasil
dapat direproduksi, lakukan Random Forest Regression pada data
Friedman. Bandingkan mtry = 2, 3, dan 5 dengan
num.trees = 200, 500, dan 1000. Bandingkan performa data
testing berdasarkan MSE, RMSE, MAE, \(R^2\), residual plot, dan
variable importance. Tampilkan pula OOB MSE sebagai evaluasi
internal model.
Ensemble learning merupakan pendekatan yang menggabungkan beberapa model dasar agar diperoleh model gabungan dengan kemampuan prediksi yang lebih baik. Random Forest adalah algoritma ensemble learning berbasis tree yang membangun banyak decision tree dan menggabungkan prediksinya untuk meningkatkan akurasi dan mengurangi overfitting. Menurut James, Witten, Hastie, dan Tibshirani dalam An Introduction to Statistical Learning (ISL), Random Forest merupakan pengembangan dari metode bagging (Bootstrap Aggregating) yang menggunakan kumpulan pohon keputusan (decision trees) sebagai model dasar. Metode ini dirancang untuk mengurangi variansi model dan meningkatkan kemampuan generalisasi (Fransiska, 2026).
Seperti bagging, RF membentuk banyak pohon dari proses resampling kemudian menggabungkan hasil prediksinya. Perbedaannya, RF menambahkan pengacakan pada pemilihan prediktor di setiap node, sehingga pohon-pohon dalam forest tidak hanya dibangun dari sampel yang berbeda, tetapi juga tidak selalu mempertimbangkan prediktor yang sama ketika mencari split terbaik. Tujuan pengacakan prediktor adalah mengurangi korelasi antar-pohon, sebab apabila semua pohon terlalu mirip maka manfaat agregasi menjadi terbatas (Fransiska, 2026). RF juga dikembangkan dari metode Classification and Regression Tree (CART) dengan menerapkan bagging dan random feature selection (Wicaksono dkk., 2024). Perbedaan bagging dan RF dirangkum pada Tabel 1.
Tabel 1. Perbedaan Bagging dan Random Forest
| Aspek | Bagging | Random Forest |
|---|---|---|
| Data tiap tree | Umumnya sampel bootstrap | Umumnya sampel bootstrap |
| Prediktor pada split | Semua prediktor dapat dipertimbangkan | Hanya mtry prediktor yang dipilih secara
acak |
| Korelasi antar-tree | Dapat relatif tinggi | Ditekan melalui random feature selection |
| Agregasi klasifikasi | Majority voting | Majority voting |
| Agregasi regresi | Rata-rata prediksi | Rata-rata prediksi |
| Fokus utama | Mengurangi variance melalui agregasi | Mengurangi variance sekaligus mendekorelasi tree |
Misalkan tersedia data latih \(D = (x_i, y_i)\), \(i = 1, 2, \dots, n\) dan akan dibentuk \(B\) pohon. Secara sederhana, proses RF dilakukan sebagai berikut (Fransiska, 2026; Wicaksono dkk., 2024):
mtry prediktor
secara acak dari seluruh \(p\)
prediktor.mtry
prediktor yang terpilih.Untuk regresi, hasil akhir diperoleh dengan merata-ratakan prediksi semua tree:
\[ \hat{f}_{RF}(x) = \frac{1}{B} \sum_{b=1}^{B} T_b(x) \]
sedangkan untuk klasifikasi, hasil akhir diperoleh melalui majority voting:
\[ \hat{G}_{RF}(x) = \text{mode}\{G_1(x), G_2(x), \dots, G_B(x)\} \]
dengan \(T_b(x)\) merupakan prediksi tree ke-\(b\) dan \(B\) merupakan banyaknya pohon yang dibangun. RF merupakan metode parallel ensemble, sehingga setiap tree dapat dibentuk secara relatif independen, berbeda dari boosting yang bersifat sequential (Fransiska, 2026).
Pada bootstrap berukuran \(n\) yang diambil dengan pengembalian dari \(n\) observasi, sebagian observasi dapat terambil lebih dari sekali dan sebagian lainnya tidak terambil. Secara rata-rata, proporsi observasi unik yang masuk ke satu sampel bootstrap mendekati \(1 - e^{-1} \approx 0{,}632\), sehingga sekitar 36,8% observasi tidak digunakan untuk membentuk tree tertentu dan disebut Out-of-Bag (OOB) observations (Fransiska, 2026).
Untuk setiap observasi, prediksi OOB diperoleh hanya dari tree-tree yang tidak menggunakan observasi tersebut ketika dibentuk. Prediksi ini digunakan untuk menghitung OOB prediction error sebagai ukuran evaluasi internal RF (Fransiska, 2026). Pada kasus regresi, OOB error dinyatakan sebagai OOB Mean Squared Error (MSE):
\[ \text{OOB MSE} = \frac{1}{n} \sum_{i=1}^{n} \left( y_i - \hat{y}_i^{OOB} \right)^2 \]
dengan \(\hat{y}_i^{OOB}\) merupakan
prediksi observasi ke-\(i\) yang
diperoleh hanya dari tree yang tidak memuat observasi tersebut.
Semakin rendah kesalahan OOB, semakin baik kinerja model (Hasna dkk.,
2024; Ilmi dkk., 2025). Pada paket ranger, OOB
error dihitung secara otomatis; untuk regresi,
prediction.error menyatakan OOB MSE dan
r.squared menyatakan \(R^2\) berbasis OOB (Fransiska, 2026).
Double Random Forest (DRF) diperkenalkan oleh Han, Kim, dan Lee pada tahun 2020 untuk situasi ketika RF masih mengalami underfitting karena pohon yang dihasilkan belum cukup besar (Fransiska, 2026). Aldania dkk. (2023) juga menempatkan DRF sebagai pengembangan RF yang baik digunakan ketika model RF yang dihasilkan mengalami underfitting.
Pada RF standar, setiap pohon dibentuk menggunakan satu sampel bootstrap pada awal pohon yang hanya memuat sekitar 63,2% observasi unik. Pada DRF, setiap pohon dibangun menggunakan seluruh data training, sedangkan bootstrap digunakan sementara pada setiap node untuk mencari aturan split. Secara sederhana, proses DRF dilakukan sebagai berikut (Fransiska, 2026):
mtry prediktor secara acak dan mencari
split terbaik menggunakan sampel bootstrap pada
node.Tabel 2. Perbedaan Random Forest dan Double Random Forest
| Aspek | Random Forest | Double Random Forest |
|---|---|---|
| Penggunaan data | Setiap pohon dibentuk dari data berbeda, yaitu hasil bootstrap pada data latih | Setiap pohon dibentuk dari data yang sama, yaitu keseluruhan data latih |
| Jumlah observasi unik | Sekitar \(1 - e^{-1} \approx 0{,}63\) kali data latih | Seluruh data latih; bootstrap hanya sementara pada setiap node untuk mencari split |
| Proses pemisahan | Random feature subset | Bootstrap sampling pada setiap node dan random feature subset |
| Ukuran pohon | Pohon lebih kecil dibandingkan DRF | Cenderung menghasilkan pohon yang lebih besar dan beragam |
| Waktu komputasi | Lebih cepat | Lebih lama karena bootstrap diulang pada banyak node |
| Prediksi akhir | Klasifikasi: majority voting; regresi: rata-rata | Klasifikasi: majority voting; regresi: rata-rata |
Tiga hyperparameter utama yang berpengaruh pada kinerja RF
adalah ntree, mtry, dan nodesize.
ntree menyatakan banyak pohon yang dibangun dalam
ensemble, mtry menyatakan banyak variabel yang
tersedia untuk dipecah pada setiap node sehingga menentukan
keragaman antar pohon, sedangkan nodesize merupakan ukuran
minimal node yang menjadi kriteria penghentian dan mengontrol
kedalaman pohon (Ilmi dkk., 2025). Parameter tersebut beserta argumen
pada fungsi ranger() dirangkum pada Tabel 3.
Tabel 3. Parameter Penting Random Forest dan DRF
| Parameter | Peran | Argumen pada ranger() |
|---|---|---|
| Jumlah tree | Menentukan jumlah tree yang dibentuk dalam ensemble | num.trees |
| Jumlah prediktor kandidat | Menentukan banyak prediktor kandidat yang dipilih secara acak pada setiap node | mtry |
| Ukuran minimum node | Mengatur ukuran minimum node dan secara tidak langsung kompleksitas tree | min.node.size |
| Mekanisme sampling | Mengatur mekanisme dan proporsi sampling | replace, sample.fraction |
| Aturan split | Menentukan aturan split, misalnya variance untuk regresi | splitrule |
| Variable importance | Menentukan apakah dan bagaimana variable importance dihitung | importance |
Jenis data yang digunakan dalam penelitian ini adalah data
kuantitatif, yaitu data berbentuk angka yang dapat diolah dan dianalisis
secara statistik. Sumber data yang digunakan merupakan data simulasi
yang dibangkitkan melalui fungsi mlbench.friedman1() pada
package mlbench dalam perangkat lunak R. Dataset
ini terdiri dari 200 pengamatan dengan satu variabel respon (y) dan
sepuluh variabel prediktor yang digunakan untuk membangun model prediksi
menggunakan metode Random Forest Regression dengan
mtry = 2, 3, dan 5 serta num.trees = 200, 500,
dan 1000.
Tabel 4. Variabel Penelitian
| No | Variabel | Keterangan | Tipe Data | Peran |
|---|---|---|---|---|
| 1 | y | Variabel respon hasil simulasi Friedman, dibangkitkan dari fungsi \(10\sin(\pi x_1 x_2) + 20(x_3 - 0{,}5)^2 + 10x_4 + 5x_5 + \varepsilon\) | Numerik | Respon |
| 2 | x.1 | Variabel prediktor ke-1, berdistribusi seragam pada interval [0, 1] | Numerik | Prediktor |
| 3 | x.2 | Variabel prediktor ke-2, berdistribusi seragam pada interval [0, 1] | Numerik | Prediktor |
| 4 | x.3 | Variabel prediktor ke-3, berdistribusi seragam pada interval [0, 1] | Numerik | Prediktor |
| 5 | x.4 | Variabel prediktor ke-4, berdistribusi seragam pada interval [0, 1] | Numerik | Prediktor |
| 6 | x.5 | Variabel prediktor ke-5, berdistribusi seragam pada interval [0, 1] | Numerik | Prediktor |
| 7 | x.6 | Variabel prediktor ke-6, berdistribusi seragam pada interval [0, 1] dan tidak memengaruhi respon (noise) | Numerik | Prediktor |
| 8 | x.7 | Variabel prediktor ke-7, berdistribusi seragam pada interval [0, 1] dan tidak memengaruhi respon (noise) | Numerik | Prediktor |
| 9 | x.8 | Variabel prediktor ke-8, berdistribusi seragam pada interval [0, 1] dan tidak memengaruhi respon (noise) | Numerik | Prediktor |
| 10 | x.9 | Variabel prediktor ke-9, berdistribusi seragam pada interval [0, 1] dan tidak memengaruhi respon (noise) | Numerik | Prediktor |
| 11 | x.10 | Variabel prediktor ke-10, berdistribusi seragam pada interval [0, 1] dan tidak memengaruhi respon (noise) | Numerik | Prediktor |
ranger untuk membangun model Random Forest,
mlbench untuk membangkitkan data Friedman,
caret untuk membagi data, dan knitr untuk
menampilkan tabel.mlbench.friedman1() yang diawali
set.seed(234), kemudian mengubahnya menjadi data
frame.createDataPartition()
dengan set.seed(234).mtry (2, 3, 5) dan
num.trees (200, 500, 1000) sehingga terbentuk 9 model.ranger() dengan min.node.size = 5,
replace = TRUE, sample.fraction = 1, dan
importance = “permutation” pada setiap kombinasi.Tahap awal adalah memanggil package yang dibutuhkan, yaitu
ranger untuk membangun model Random Forest,
mlbench untuk membangkitkan data Friedman,
caret untuk membagi data, dan knitr untuk
menampilkan tabel. Kemudian data Friedman #1 dibangkitkan sebanyak 200
pengamatan dengan set.seed(234) agar hasil dapat
direproduksi.
library(ranger)
library(mlbench)
library(caret)
library(knitr)
set.seed(234)
reg.data <- as.data.frame(mlbench.friedman1(200))
dim(reg.data)## [1] 200 11
## 'data.frame': 200 obs. of 11 variables:
## $ x.1 : num 0.7456 0.7817 0.02 0.7761 0.0669 ...
## $ x.2 : num 0.575 0.316 0.765 0.229 0.172 ...
## $ x.3 : num 0.0289 0.9375 0.7978 0.668 0.5974 ...
## $ x.4 : num 0.72 0.185 0.534 0.553 0.755 ...
## $ x.5 : num 0.875 0.704 0.952 0.478 0.533 ...
## $ x.6 : num 0.276 0.643 0.987 0.843 0.733 ...
## $ x.7 : num 0.9332 0.4018 0.0874 0.893 0.1024 ...
## $ x.8 : num 0.60746 0.00369 0.0106 0.44639 0.83494 ...
## $ x.9 : num 0.756 0.405 0.247 0.144 0.187 ...
## $ x.10: num 0.718 0.534 0.667 0.68 0.595 ...
## $ y : num 24.35 18.05 12.02 12.1 9.91 ...
## x.1 x.2 x.3 x.4 x.5 x.6 x.7
## 1 0.74562000 0.5754994 0.02885590 0.7201653 0.8748022 0.2761835 0.93319087
## 2 0.78171242 0.3157821 0.93745388 0.1849746 0.7039934 0.6426889 0.40177800
## 3 0.02003711 0.7646459 0.79777294 0.5338609 0.9515834 0.9873938 0.08742998
## 4 0.77608539 0.2289793 0.66797951 0.5534984 0.4780999 0.8425175 0.89302195
## 5 0.06691009 0.1715219 0.59740948 0.7547957 0.5332404 0.7327976 0.10244557
## 6 0.64479512 0.6473963 0.01351334 0.7894812 0.2376348 0.4302338 0.88236742
## x.8 x.9 x.10 y
## 1 0.607462891 0.7560942 0.7179672 24.349507
## 2 0.003687496 0.4046106 0.5338439 18.046792
## 3 0.010598118 0.2473974 0.6669937 12.018651
## 4 0.446393069 0.1443539 0.6802987 12.101870
## 5 0.834936006 0.1874371 0.5950115 9.911772
## 6 0.843509237 0.6166422 0.1081932 21.874286
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 3.082 10.593 13.810 14.270 18.063 26.146
Interpretasi:
Berdasarkan hasil pemeriksaan data, data Friedman #1 terdiri atas 200
pengamatan dan 11 variabel, yaitu 10 variabel prediktor
(x.1 hingga x.10) dan satu variabel respons
(y). Seluruh variabel bertipe numerik sehingga dapat
digunakan dalam analisis regresi Random Forest.
Hasil ringkasan variabel respons menunjukkan nilai minimum sebesar 3,082, kuartil pertama sebesar 10,593, median sebesar 13,810, rata-rata sebesar 14,270, kuartil ketiga sebesar 18,063, dan nilai maksimum sebesar 26,146. Nilai rata-rata yang sedikit lebih besar daripada median menunjukkan bahwa distribusi variabel respons cenderung sedikit menceng ke kanan.
Kemudian data dibagi menjadi 70% data training dan 30% data
testing menggunakan fungsi createDataPartition()
dengan set.seed(234). Karena variabel respon berupa data
numerik, pembagian dilakukan berdasarkan kelompok nilai respon sehingga
sebaran y pada kedua data relatif serupa.
set.seed(234)
idx.reg <- createDataPartition(reg.data$y, p = 0.70, list = FALSE)
reg.train <- reg.data[idx.reg, ]
reg.test <- reg.data[-idx.reg, ]
dim(reg.train)## [1] 140 11
## [1] 60 11
Interpretasi:
Berdasarkan hasil pembagian data, sebanyak 200 pengamatan dibagi menjadi 140 pengamatan data training dan 60 pengamatan data testing. Data training mencakup 70% dari keseluruhan data, sedangkan data testing mencakup 30%. Masing-masing kelompok terdiri atas 11 variabel, yaitu 10 variabel prediktor dan satu variabel respons. Data training digunakan untuk membangun model regresi Random Forest, sedangkan data testing digunakan untuk mengukur kemampuan model dalam memprediksi data yang belum pernah digunakan selama proses pelatihan.
Model Random Forest Regression dibangun dengan fungsi
ranger(). Model dibuat untuk setiap kombinasi
mtry = 2, 3, dan 5 dengan num.trees = 200,
500, dan 1000, sehingga diperoleh 9 model. Parameter lainnya dibuat sama
pada seluruh model, yaitu min.node.size = 5,
replace = TRUE, sample.fraction = 1, dan
importance = “permutation”. Fungsi
set.seed(234) dan argumen seed = 234 digunakan
agar hasil dapat direproduksi.
mtry_set <- c(2, 3, 5)
ntree_set <- c(200, 500, 1000)
grid <- expand.grid(num.trees = ntree_set, mtry = mtry_set)
grid$Model <- paste0("mtry=", grid$mtry, ", ntree=", grid$num.trees)
rf_list <- vector("list", nrow(grid))
names(rf_list) <- grid$Model
for (i in seq_len(nrow(grid))) {
set.seed(234)
rf_list[[i]] <- ranger(
y ~ ., data = reg.train,
num.trees = grid$num.trees[i],
mtry = grid$mtry[i],
min.node.size = 5,
replace = TRUE,
sample.fraction = 1,
importance = "permutation",
seed = 234
)
}
# Contoh keluaran salah satu model (mtry = 3, num.trees = 500)
rf_list[["mtry=3, ntree=500"]]## Ranger result
##
## Call:
## ranger(y ~ ., data = reg.train, num.trees = grid$num.trees[i], mtry = grid$mtry[i], min.node.size = 5, replace = TRUE, sample.fraction = 1, importance = "permutation", seed = 234)
##
## Type: Regression
## Number of trees: 500
## Sample size: 140
## Number of independent variables: 10
## Mtry: 3
## Target node size: 5
## Variable importance mode: permutation
## Splitrule: variance
## OOB prediction error (MSE): 7.442423
## R squared (OOB): 0.7198089
Interpretasi:
Berdasarkan hasil pemodelan menggunakan fungsi ranger(),
dibentuk 9 model Random Forest Regression dari kombinasi tiga
nilai mtry dan tiga nilai num.trees. Setiap
pohon dibangun dari sampel bootstrap (replace =
TRUE dan sample.fraction = 1) dengan ukuran node
minimum 5, dan pada setiap node hanya mtry
prediktor yang dipilih secara acak sebagai kandidat split.
Keluaran model pada contoh di atas memuat jenis pohon
(Regression), jumlah pohon, ukuran sampel, jumlah variabel
independen, nilai mtry, ukuran node target, serta
evaluasi internal berupa OOB prediction error (MSE) dan \(R^2\).
Evaluasi internal model dilakukan menggunakan Out-of-Bag
(OOB) error yang dihitung otomatis oleh ranger.
Pada regresi, prediction.error menyatakan OOB MSE dan
r.squared menyatakan \(R^2\) berbasis OOB. Evaluasi ini tidak
memerlukan data testing karena menggunakan observasi yang tidak
ikut membentuk suatu pohon.
oob_df <- data.frame(
Model = grid$Model,
mtry = grid$mtry,
num.trees = grid$num.trees,
OOB_MSE = sapply(rf_list, function(m) m$prediction.error),
OOB_R2 = sapply(rf_list, function(m) m$r.squared),
row.names = NULL
)
kable(oob_df, digits = 4, align = "c",
format.args = list(decimal.mark = ","),
caption = "Tabel 5. OOB MSE dan R-Square OOB pada Setiap Kombinasi mtry dan num.trees")| Model | mtry | num.trees | OOB_MSE | OOB_R2 |
|---|---|---|---|---|
| mtry=2, ntree=200 | 2 | 200 | 8,2222 | 0,6905 |
| mtry=2, ntree=500 | 2 | 500 | 8,1267 | 0,6940 |
| mtry=2, ntree=1000 | 2 | 1000 | 8,0553 | 0,6967 |
| mtry=3, ntree=200 | 3 | 200 | 7,7097 | 0,7097 |
| mtry=3, ntree=500 | 3 | 500 | 7,4424 | 0,7198 |
| mtry=3, ntree=1000 | 3 | 1000 | 7,3547 | 0,7231 |
| mtry=5, ntree=200 | 5 | 200 | 7,0632 | 0,7341 |
| mtry=5, ntree=500 | 5 | 500 | 6,8750 | 0,7412 |
| mtry=5, ntree=1000 | 5 | 1000 | 6,8260 | 0,7430 |
Interpretasi:
Berdasarkan Tabel 5, nilai OOB MSE terkecil sebesar 6,8260 diperoleh
pada model mtry=5, ntree=1000 dengan \(R^2\) OOB sebesar 0,7430, sedangkan OOB MSE
terbesar sebesar 8,2222 diperoleh pada model mtry=2, ntree=200. Selisih
antara OOB MSE terbesar dan terkecil adalah 1,3962 (sekitar 20,5% dari
OOB MSE terkecil), sehingga perbedaan kombinasi parameter memberikan
perbedaan kinerja internal yang cukup terlihat. Jika dirata-ratakan, OOB
MSE terkecil diperoleh pada mtry = 5 dan pada
num.trees = 1000. Semakin rendah OOB MSE, semakin baik
kinerja internal model.
cols <- c("steelblue", "darkorange", "forestgreen")
plot(NULL, xlim = range(ntree_set), ylim = range(oob_df$OOB_MSE),
xlab = "Jumlah pohon (num.trees)", ylab = "OOB MSE", xaxt = "n",
main = "OOB MSE menurut mtry dan num.trees")
axis(1, at = ntree_set)
for (j in seq_along(mtry_set)) {
d <- oob_df[oob_df$mtry == mtry_set[j], ]
lines(d$num.trees, d$OOB_MSE, type = "b", pch = 19, lwd = 2, col = cols[j])
}
legend("topright", legend = paste("mtry =", mtry_set),
col = cols, lty = 1, pch = 19, lwd = 2, cex = 0.8)Interpretasi:
Plot di atas memperlihatkan perubahan OOB MSE terhadap
jumlah pohon pada masing-masing nilai mtry. Pada umumnya,
penambahan jumlah pohon membuat kurva semakin mendatar karena prediksi
rata-rata dari semakin banyak pohon menjadi lebih stabil, sedangkan
perbedaan antar garis menunjukkan pengaruh nilai mtry
terhadap galat internal model.
Setiap model digunakan untuk memprediksi nilai respon pada data
testing dengan fungsi predict(), lalu hasilnya
dibandingkan dengan nilai aktual.
actual <- reg.test$y
pred_list <- lapply(rf_list, function(m) predict(m, data = reg.test)$predictions)
hasil_pred <- data.frame(
Aktual = actual,
Pred_mtry2 = pred_list[["mtry=2, ntree=500"]],
Pred_mtry3 = pred_list[["mtry=3, ntree=500"]],
Pred_mtry5 = pred_list[["mtry=5, ntree=500"]]
)
kable(head(hasil_pred, 10), digits = 3, align = "c",
format.args = list(decimal.mark = ","),
caption = "Tabel 6. Perbandingan Nilai Aktual dan Prediksi (10 Pengamatan Pertama, num.trees = 500)")| Aktual | Pred_mtry2 | Pred_mtry3 | Pred_mtry5 |
|---|---|---|---|
| 10,232 | 12,875 | 12,455 | 12,413 |
| 11,845 | 10,866 | 10,618 | 10,345 |
| 10,336 | 13,115 | 13,229 | 12,773 |
| 16,727 | 13,981 | 13,368 | 13,614 |
| 25,077 | 18,842 | 19,528 | 20,427 |
| 15,447 | 14,133 | 14,255 | 14,504 |
| 15,643 | 13,308 | 12,625 | 12,844 |
| 7,111 | 12,420 | 12,824 | 12,853 |
| 13,351 | 15,379 | 15,389 | 15,482 |
| 12,872 | 14,394 | 14,621 | 14,807 |
Interpretasi:
Berdasarkan Tabel 6, nilai prediksi dari ketiga model pada umumnya
mengikuti nilai aktual, tetapi ketepatannya berbeda pada setiap
pengamatan. Pada 10 pengamatan pertama dengan num.trees =
500, rata-rata selisih absolut antara nilai aktual dan prediksi adalah
2,789 untuk mtry = 2, 2,896 untuk mtry = 3,
dan 2,743 untuk mtry = 5. Selisih terbesar terjadi pada
pengamatan ke-8 dengan nilai aktual 7,111, sedangkan prediksi ketiga
model berkisar antara 12,420 sampai 12,853. Karena perbandingan pada 10
pengamatan belum mewakili seluruh data, kinerja yang lebih tepat perlu
dilihat dari metrik evaluasi pada seluruh data testing.
Kinerja model dievaluasi dengan MSE, RMSE, MAE, dan R-Square yang dihitung dari nilai aktual dan prediksi pada seluruh data testing. Nilai OOB MSE dari Tabel 5 ditampilkan kembali sebagai pembanding.
hitung_metrik <- function(actual, pred) {
MSE <- mean((actual - pred)^2)
RMSE <- sqrt(MSE)
MAE <- mean(abs(actual - pred))
R2 <- 1 - sum((actual - pred)^2) / sum((actual - mean(actual))^2)
c(MSE = MSE, RMSE = RMSE, MAE = MAE, R2 = R2)
}
metrik <- t(sapply(pred_list, function(p) hitung_metrik(actual, p)))
metrik_df <- data.frame(Model = grid$Model,
mtry = grid$mtry,
num.trees = grid$num.trees,
OOB_MSE = oob_df$OOB_MSE,
metrik, row.names = NULL)
kable(metrik_df, digits = 4, align = "c",
format.args = list(decimal.mark = ","),
caption = "Tabel 7. Perbandingan Metrik Evaluasi Random Forest Regression pada Data Testing")| Model | mtry | num.trees | OOB_MSE | MSE | RMSE | MAE | R2 |
|---|---|---|---|---|---|---|---|
| mtry=2, ntree=200 | 2 | 200 | 8,2222 | 7,8700 | 2,8054 | 2,3414 | 0,6717 |
| mtry=2, ntree=500 | 2 | 500 | 8,1267 | 8,1774 | 2,8596 | 2,3832 | 0,6589 |
| mtry=2, ntree=1000 | 2 | 1000 | 8,0553 | 8,1181 | 2,8492 | 2,3794 | 0,6613 |
| mtry=3, ntree=200 | 3 | 200 | 7,7097 | 7,8139 | 2,7953 | 2,2981 | 0,6740 |
| mtry=3, ntree=500 | 3 | 500 | 7,4424 | 7,8278 | 2,7978 | 2,3058 | 0,6734 |
| mtry=3, ntree=1000 | 3 | 1000 | 7,3547 | 7,7780 | 2,7889 | 2,2996 | 0,6755 |
| mtry=5, ntree=200 | 5 | 200 | 7,0632 | 7,6596 | 2,7676 | 2,2726 | 0,6805 |
| mtry=5, ntree=500 | 5 | 500 | 6,8750 | 7,3826 | 2,7171 | 2,2312 | 0,6920 |
| mtry=5, ntree=1000 | 5 | 1000 | 6,8260 | 7,1925 | 2,6819 | 2,2054 | 0,6999 |
Interpretasi:
Berdasarkan Tabel 7, nilai MSE terkecil pada data testing diperoleh pada model mtry=5, ntree=1000, yaitu 7,1925 dengan RMSE 2,6819 dan MAE 2,2054. Nilai R-Square terbesar sebesar 0,6999 diperoleh pada model mtry=5, ntree=1000, artinya model mampu menjelaskan sekitar 69,99% keragaman nilai respon pada data testing. Keempat metrik menunjukkan model terbaik yang sama, sehingga pemilihan model terbaik konsisten. Selisih MSE antara model terbaik dan terburuk adalah 0,9849 (sekitar 13,7% dari MSE terkecil), sehingga perbedaan kombinasi mtry dan num.trees memberikan perbedaan kinerja yang cukup terlihat.
Jika dirata-ratakan, MSE terkecil berdasarkan mtry
diperoleh pada mtry = 5, sedangkan berdasarkan jumlah pohon
diperoleh pada num.trees = 1000. Sebagai pembanding, galat
acak pada data Friedman #1 memiliki varians sekitar 1, sehingga MSE
terbaik berada sekitar 7,19 kali di atas batas tersebut. Berdasarkan
evaluasi internal, model terbaik menurut OOB MSE adalah mtry=5,
ntree=1000, yang sama dengan model terbaik pada data testing, sehingga
evaluasi internal (OOB) konsisten dengan hasil pengujian.
plot(NULL, xlim = range(ntree_set), ylim = range(metrik_df$MSE),
xlab = "Jumlah pohon (num.trees)", ylab = "MSE data testing", xaxt = "n",
main = "MSE Data Testing menurut mtry dan num.trees")
axis(1, at = ntree_set)
for (j in seq_along(mtry_set)) {
d <- metrik_df[metrik_df$mtry == mtry_set[j], ]
lines(d$num.trees, d$MSE, type = "b", pch = 19, lwd = 2, col = cols[j])
}
legend("topright", legend = paste("mtry =", mtry_set),
col = cols, lty = 1, pch = 19, lwd = 2, cex = 0.8)Plot dibuat untuk melihat kesesuaian nilai prediksi terhadap
nilai aktual pada setiap kombinasi mtry dan
num.trees. Baris pertama hingga ketiga berturut-turut
menunjukkan mtry = 2, 3, dan 5, sedangkan kolom pertama
hingga ketiga menunjukkan num.trees = 200, 500, dan 1000.
Garis merah putus-putus menunjukkan kondisi ideal, yaitu nilai prediksi
sama dengan nilai aktual.
par(mfrow = c(3, 3), mar = c(4, 4, 3, 1))
for (i in seq_along(pred_list)) {
plot(actual, pred_list[[i]], pch = 19, col = "steelblue",
xlab = "Nilai Aktual", ylab = "Nilai Prediksi",
main = grid$Model[i], cex.main = 0.95)
abline(a = 0, b = 1, lty = 2, lwd = 2, col = "red")
}Interpretasi:
Pada kesembilan plot, titik-titik menyebar mengikuti garis diagonal, yang menunjukkan bahwa model mampu menangkap pola data Friedman. Korelasi antara nilai aktual dan prediksi berkisar antara 0,8445 sampai 0,8946, dengan korelasi terbesar pada model mtry=2, ntree=200. Pada model terbaik, kemiringan hubungan prediksi terhadap nilai aktual sebesar 0,578, yang berarti prediksi cenderung tertarik ke nilai tengah sehingga nilai aktual yang ekstrem sulit ditangkap sepenuhnya. Hal ini wajar pada RF karena prediksi merupakan rata-rata dari banyak pohon.
Plot residual dibuat untuk memeriksa selisih antara nilai aktual dan prediksi terhadap nilai prediksi. Residual yang baik tersebar acak di sekitar nol tanpa pola tertentu.
par(mfrow = c(3, 3), mar = c(4, 4, 3, 1))
for (i in seq_along(pred_list)) {
res <- actual - pred_list[[i]]
plot(pred_list[[i]], res, pch = 19, col = "steelblue",
xlab = "Nilai Prediksi", ylab = "Residual",
main = grid$Model[i], cex.main = 0.95)
abline(h = 0, lty = 2, lwd = 2, col = "red")
}Interpretasi:
Pada model terbaik (mtry=5, ntree=1000), rata-rata residual sebesar -0,2726 dengan simpangan baku 2,6905. Rata-rata residual yang dekat dengan nol menunjukkan bahwa model tidak cenderung memprediksi terlalu tinggi atau terlalu rendah secara sistematis. Residual terbesar bernilai -5,761, yaitu selisih terjauh antara nilai aktual dan prediksi pada data testing. Sebaran residual pada kesembilan plot perlu dicermati secara visual, karena sebaran acak di sekitar garis nol menunjukkan model telah menangkap pola yang ada, sedangkan pola melengkung atau melebar menunjukkan masih ada struktur yang belum tertangkap.
Variable importance pada model terbaik dihitung menggunakan
importance = "permutation" pada ranger, yaitu
penurunan kinerja prediksi OOB ketika nilai suatu variabel diacak.
Semakin besar nilainya, semakin besar kontribusi variabel tersebut
terhadap prediksi.
info_vars <- paste0("x.", 1:5)
noise_vars <- paste0("x.", 6:10)
imp_best <- sort(rf_list[[best_idx]]$variable.importance, decreasing = TRUE)
imp_df <- data.frame(
Variabel = names(imp_best),
Importance = as.numeric(imp_best),
Jenis = ifelse(names(imp_best) %in% info_vars, "Informatif", "Noise"),
row.names = NULL
)
kable(imp_df, digits = 4, align = "c",
format.args = list(decimal.mark = ","),
caption = "Tabel 8. Permutation Importance Variabel pada Model Terbaik")| Variabel | Importance | Jenis |
|---|---|---|
| x.4 | 12,9314 | Informatif |
| x.1 | 9,3875 | Informatif |
| x.2 | 3,8211 | Informatif |
| x.3 | 1,8255 | Informatif |
| x.5 | 0,9720 | Informatif |
| x.6 | 0,1000 | Noise |
| x.10 | 0,0976 | Noise |
| x.8 | -0,0096 | Noise |
| x.9 | -0,0802 | Noise |
| x.7 | -0,1430 | Noise |
barplot(imp_best, las = 2,
col = ifelse(names(imp_best) %in% info_vars, "steelblue", "grey70"),
ylab = "Permutation Importance",
main = paste("Variable Importance - Random Forest Regression\n(", best_lab, ")"))
legend("topright", legend = c("Informatif (x.1-x.5)", "Noise (x.6-x.10)"),
fill = c("steelblue", "grey70"), cex = 0.8)Interpretasi:
Berdasarkan Tabel 8, variabel yang paling berpengaruh adalah x.4 dengan nilai importance sebesar 12,9314, diikuti oleh x.1 sebesar 9,3875 dan x.2 sebesar 3,8211. Pada data Friedman #1, hanya variabel x.1 sampai x.5 yang benar-benar membentuk respon, sedangkan x.6 sampai x.10 merupakan noise. Rata-rata nilai importance variabel x.1 sampai x.5 sebesar 5,7875, sedangkan rata-rata variabel noise hanya -0,0071. Lima variabel dengan importance tertinggi pada model terbaik tepat sama dengan variabel informatif (x.1 sampai x.5), dan pola yang sama juga ditemukan pada seluruh sembilan model. Hal ini menunjukkan bahwa Random Forest berhasil membedakan variabel yang informatif dari variabel noise.
Random Forest (RF) adalah metode ensemble learning
berbasis decision tree yang membangun banyak pohon dari sampel
bootstrap dan memilih sejumlah mtry prediktor
secara acak pada setiap node. Dengan cara ini pohon-pohon yang
terbentuk tidak terlalu berkorelasi, sehingga variansi model berkurang
dan kemampuan generalisasi meningkat. Prediksi akhir diperoleh melalui
majority voting pada klasifikasi dan rata-rata prediksi seluruh
pohon pada regresi. Double Random Forest (DRF) merupakan
pengembangan RF yang dirancang untuk kondisi ketika RF mengalami
underfitting. Setiap pohon DRF dibangun dari seluruh data
training, sedangkan bootstrap hanya digunakan
sementara pada setiap node untuk mencari aturan split.
Akibatnya DRF cenderung menghasilkan pohon yang lebih besar dan beragam,
dengan waktu komputasi yang lebih lama dibandingkan RF.
RF dan DRF dapat diimplementasikan menggunakan R untuk kasus
klasifikasi maupun regresi dengan tahapan yang sama, yaitu persiapan
data, pembagian data training dan testing, pembentukan
model, prediksi, evaluasi, dan interpretasi. RF diimplementasikan
menggunakan paket ranger dengan parameter penting seperti
num.trees, mtry, dan
min.node.size, sedangkan DRF dijalankan menggunakan sintaks
khusus yang disediakan pada modul. Pada klasifikasi, kinerja model
dievaluasi menggunakan confusion matrix beserta
Accuracy, Precision, Recall,
Specificity, dan F1-score, sedangkan pada regresi
menggunakan MSE, RMSE, MAE, dan \(R^2\).
Performa model dievaluasi secara internal melalui Out-of-Bag (OOB) error dan secara eksternal melalui data testing. OOB error dihitung dari observasi yang tidak ikut membentuk suatu pohon (sekitar 36,8% data), sehingga dapat menjadi ukuran kinerja tanpa memerlukan data testing. Pada klasifikasi OOB error berupa proporsi salah klasifikasi, sedangkan pada regresi berupa OOB MSE, dan semakin kecil nilainya semakin baik model. Jika dibandingkan, RF lebih cepat secara komputasi, sedangkan DRF lebih sesuai ketika RF menghasilkan pohon yang terlalu kecil dan model masih underfitting, dengan konsekuensi waktu komputasi yang lebih besar. Pemilihan model terbaik sebaiknya mempertimbangkan hasil evaluasi pada data testing dan OOB error secara bersama-sama.
Berdasarkan hasil analisis Random Forest Regression pada
data Friedman #1, diperoleh sembilan model dari kombinasi
mtry = 2, 3, dan 5 dengan num.trees = 200,
500, dan 1000. Berdasarkan evaluasi internal, OOB MSE terkecil sebesar
6,8260 diperoleh pada model mtry=5, ntree=1000. Berdasarkan data
testing, model terbaik adalah mtry=5, ntree=1000 dengan MSE
sebesar 7,1925, RMSE sebesar 2,6819, MAE sebesar 2,2054, dan \(R^2\) sebesar 0,6999. Analisis variable
importance menunjukkan bahwa variabel x.4, x.1, dan x.2 memberikan
kontribusi terbesar, sedangkan variabel x.1 hingga
x.5 merupakan variabel informatif yang membentuk respons
dan x.6 hingga x.10 merupakan variabel
noise. Dengan demikian, Random Forest Regression dapat
digunakan untuk memodelkan hubungan nonlinier antara prediktor dan
respons serta mengidentifikasi kontribusi variabel prediktor. Pemilihan
model terbaik perlu mempertimbangkan hasil evaluasi pada data
testing dan OOB error secara bersama-sama, bukan hanya
salah satunya.
Pada praktikum Machine Learning berikutnya, disarankan agar praktikan
lebih teliti dalam memasukkan dan mengolah data menggunakan RStudio,
terutama dalam penggunaan sintaks serta interpretasi Random
Forest. Selain itu, pemilihan nilai mtry,
num.trees, dan min.node.size perlu
diperhatikan agar model tidak mengalami underfitting maupun
overfitting dan waktu komputasi tetap wajar. Untuk penelitian
selanjutnya, perbandingan dapat diperluas dengan mencoba nilai
min.node.size yang berbeda, menerapkan Double Random
Forest pada data yang sama untuk membandingkan kinerja dan waktu
komputasinya dengan RF, serta membandingkan hasilnya dengan metode
ensemble lain seperti bagging atau
boosting.
Aldania, A. N. A., Soleh, A. M., & Notodiputro, K. A. (2023). A comparative study of CatBoost and double random forest for multi-class classification. Jurnal RESTI (Rekayasa Sistem dan Teknologi Informasi), 7(1), 129–137.
Fransiska, H. (2026). Modul Praktikum Machine Learning. Universitas Bengkulu.
Hasna, H., Amalita, N., Permana, D., & Salma, A. (2024). Random forest implementation for air pollution standard index classification in DKI Jakarta 2022. UNP Journal of Statistics and Data Science, 2(2), 226–233.
Ilmi, I. N., Mustafid, & Suparti. (2025). Penerapan model regresi random forest untuk prediksi harga laptop berdasarkan fitur laptop. Jurnal Gaussian, 14(2), 269–279.
Wicaksono, A. S., Godjali, M. R., Indriyany, I. A., Budiaji, W., & Ikhsan, A. (2024). Pemodelan klasifikasi preferensi ideologi partai politik pada pemilih pemula di Provinsi Banten. Jurnal Gaussian, 13(2), 421–430.