Perkembangan teknologi pengolahan data mendorong penggunaan metode machine learning untuk menghasilkan prediksi dan klasifikasi yang lebih akurat. Salah satu pendekatan yang banyak digunakan adalah metode ensemble learning, yaitu teknik yang menggabungkan beberapa model untuk meningkatkan kemampuan prediksi. Salah satu metode ensemble berbasis decision tree yang dapat digunakan untuk klasifikasi dan regresi adalah Random Forest (Hasanah et al., 2024).
Metode Random Forest dikembangkan dengan menggabungkan sejumlah pohon keputusan yang dibentuk melalui proses bootstrap sampling dan pemilihan atribut secara acak untuk menghasilkan prediksi akhir. Pengembangan dari metode tersebut adalah Double Random Forest, yang menerapkan proses bootstrap pada setiap simpul pohon sehingga dapat menghasilkan pohon keputusan yang lebih besar dan beragam. Kedua metode tersebut dapat digunakan untuk membangun model prediksi serta dibandingkan berdasarkan kemampuan dan karakteristik masing-masing dalam menangani data (Khairunnisa et al., 2024).
Penerapan Random Forest dan Double Random Forest memerlukan tahapan implementasi yang disesuaikan dengan tujuan analisis, baik untuk klasifikasi maupun regresi. Evaluasi performa model dilakukan menggunakan ukuran ketepatan prediksi, sedangkan Out-of-Bag (OOB) error digunakan untuk memperkirakan kesalahan prediksi melalui data yang tidak terpilih dalam proses bootstrap. Oleh karena itu, pemahaman mengenai konsep, implementasi, evaluasi, serta perbandingan kedua metode diperlukan untuk mengetahui kemampuan masing-masing model dalam menghasilkan prediksi yang optimal (Purwanto et al., 2025).
Berdasarkan latar belakang di atas, masalah yang dapat disimpulkan adalah:
Apa yang dimaksud dengan Random Forest dan Double Random Forest sebagai metode ensemble berbasis decision tree?
Bagaimana mengimplementasikan Random Forest untuk klasifikasi dan regresi, serta Double Random Forest untuk klasifikasi dan regresi?
Bagaimana mengevaluasi performa model, memahami Out-of-Bag (OOB) error, dan membandingkan Random Forest dengan Double Random Forest?
Berdasarkan rumusan masalah pada penelitian ini, tujuan yang dapat disimpulkan adalah:
Mahasiswa dapat memahami Random Forest dan Double Random Forest sebagai metode ensemble berbasis decision tree.
Mahasiswa dapat mengimplementasikan Random Forest untuk klasifikasi dan regresi, serta Double Random Forest untuk klasifikasi dan regresi.
Mahasiswa dapat mengevaluasi performa model, memahami Out-of-Bag (OOB) error, dan membandingkan Random Forest dengan Double Random Forest.
Random Forest merupakan salah satu metode ensemble learning berbasis decision tree yang digunakan untuk menyelesaikan permasalahan klasifikasi dan regresi. Metode ini bekerja dengan membentuk sejumlah pohon keputusan (decision tree) menggunakan sampel data dan pemilihan variabel prediktor secara acak. Hasil prediksi dari seluruh pohon kemudian digabungkan untuk memperoleh prediksi akhir yang lebih stabil dibandingkan penggunaan satu pohon keputusan (Khairunnisa et al., 2024).
Secara sederhana, proses Random Forest dilakukan sebagai berikut (Fransiska, 2026):
Mengambil sampel bootstrap dari data latih untuk membentuk data bagi tree ke-b.
Pada setiap node, memilih mtry prediktor secara acak dari seluruh p prediktor.
Menentukan split terbaik hanya dari mtry prediktor yang terpilih.
Menumbuhkan decision tree hingga memenuhi aturan penghentian, misalnya minimum node size.
Mengulangi proses sampai diperoleh B tree, kemudian menggabungkan prediksi seluruh tree.
Untuk klasifikasi, hasil akhir diperoleh melalui majority voting:
\[ \widehat{G}_{RF}(x)= \operatorname{mode} \{G_1(x),G_2(x),\ldots,G_B(x)\} \] Untuk regresi, hasil akhir diperoleh dengan merata-ratakan prediksi semua tree:
\[ { \hat{f}_{RF}(x)= \left(\frac{1}{B}\right) \sum_{b=1}^{B}T_b(x) } \] Dengan demikian, Random Forest tetap merupakan metode parallel ensemble, dengan setiap tree dapat dibentuk secara relatif independen, berbeda dari Boosting yang bersifat sequential.
Pada proses bootstrap dengan pengembalian, sebagian observasi dapat terambil lebih dari satu kali, sedangkan sebagian lainnya tidak terambil. Observasi yang tidak terpilih dalam pembentukan suatu pohon disebut Out-of-Bag (OOB) observations, dengan proporsi rata-rata sekitar 36,8% dari keseluruhan observasi. Prediksi OOB diperoleh dari pohon-pohon yang tidak menggunakan observasi tersebut dalam proses pembentukannya. Prediksi ini digunakan untuk menghitung OOB error sebagai ukuran evaluasi internal pada metode Random Forest. Pada pemrograman R menggunakan paket ranger, OOB error dihitung secara otomatis, yaitu berupa proporsi kesalahan klasifikasi (prediction.error) untuk klasifikasi dan nilai OOB Mean Squared Error (MSE) untuk regresi (Fransiska, 2026).
Double Random Forest (DRF) merupakan pengembangan dari metode Random Forest yang digunakan untuk meningkatkan kemampuan model dalam menghasilkan prediksi. Metode ini menerapkan proses bootstrap sampling tidak hanya pada awal pembentukan pohon, tetapi juga pada setiap simpul (node) selama proses pembentukan pohon keputusan. Penggunaan pengambilan sampel secara berulang tersebut bertujuan menghasilkan pohon-pohon yang lebih beragam dan mengatasi permasalahan underfitting yang dapat terjadi pada metode Random Forest (Purwanto et al., 2025).
Pada Random Forest standar, setiap tree dibentuk menggunakan satu bootstrap sample pada awal tree. Karena satu bootstrap sample hanya mengandung sekitar 63,2% observasi unik, jumlah observasi unik yang tersedia untuk membentuk tree lebih sedikit dari pada seluruh data training. Setiap tree DRF dibangun menggunakan seluruh data training, sedangkan bootstrap digunakan sementara pada setiap node untuk mencari aturan split.
Secara sederhana, proses Double Random Forest dilakukan sebagai berikut (Fransiska, 2026):
Memulai setiap tree dengan seluruh data training, bukan satu bootstrap sample untuk seluruh tree.
Pada node yang sedang diproses, mengambil bootstrap sample dari observasi yang mencapai node tersebut.
Memilih mtry prediktor secara acak dan mencari split terbaik menggunakan bootstrap sample pada node.
Setelah split terbaik ditemukan, bootstrap sample tidak diteruskan. Split tersebut diterapkan kembali pada data asli yang mencapai node, kemudian observasi asli dikirim ke child nodes.
Mengulangi proses pada node berikutnya sampai aturan penghentian tercapai, lalu mengulangi untuk seluruh tree.
Menggabungkan prediksi seluruh tree. Pada klasifikasi, hasil akhir diperoleh melalui majority voting, sedangkan pada regresi prediksi akhir diperoleh dengan merata-ratakan prediksi seluruh tree.
Jenis data pada penelitian ini adalah data kuantitatif dan data kualitatif. Data kuantitatif merupakan data atau informasi yang didapatkan dalam bentuk angka atau numerik. Data kuantitatif dapat diproses menggunakan rumus matematika atau dapat juga dianalisis dengan sistem statistik. Data kualitatif adalah suatu data yang tidak bisa diukur dengan angka. Data kualitatif adalah data yang dinyatakan dalam bentuk deskriptif atau naratif, bukan dalam bentuk angka.
Sumber data yang digunakan oleh penulis merupakan data sekunder. Data sekunder adalah sumber data yang diperoleh secara tidak langsung atau melalui media perantara. Data yang digunakan pada batasan masalah laporan ini merupakan data BreastCancer yang diperoleh langsung dari program R.
Variabel penelitian adalah karakter atau segala sesuatu yang menjadi perhatian dalam suatu penelitian. Pada laporan ini terdapat 10 variabel yang digunakan pada data. Variabel tersebut, yaitu Cl.thickness, Cell.size, Cell.shape, Marg.adhesion, Epith.c.size, Bare.nuclei, Bl,cromatin, Normal.nucleoli, Mitoses sebagai variabel prediktor, dan Class sebagai variabel respon.
Input data.
Preprocessing data.
Pembagian data training dan data testing.
Menentukan kombinasi parameter mtry dan num.trees yang akan digunakan.
Membentuk model Random Forest dengan sembilan kombinasi parameter yang berbeda.
Menghitung nilai Out-of-Bag (OOB) error pada setiap model.
Melakukan prediksi menggunakan data testing dan membentuk confusion matrix.
Menghitung metrik evaluasi.
Membandingkan performa model, menentukan model terbaik, serta menganalisis variable importance.
Output dan interpretasi.
Langkah pertama yang dilakukan adalah memanggil library dan meng-import data
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
packages <- c("ranger", "mlbench", "caret", "knitr",
"ggplot2", "dplyr", "tidyr")
for (p in packages) {
if (!requireNamespace(p, quietly = TRUE)) {
install.packages(p, repos = "https://cloud.r-project.org")
}
}
library(ranger)
library(mlbench)
library(caret)## Loading required package: ggplot2
## Loading required package: lattice
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyr)
data("BreastCancer", package = "mlbench")
bc <- BreastCancer
# Menghapus variabel identitas
bc$Id <- NULL
# Menghapus observasi dengan missing value
bc <- na.omit(bc)
# Mengubah variabel prediktor menjadi numerik
kolom_prediktor <- setdiff(names(bc), "Class")
bc[kolom_prediktor] <- lapply(bc[kolom_prediktor], function(x) {
as.numeric(as.character(x))
})
# Menetapkan urutan kategori variabel respon
bc$Class <- factor(as.character(bc$Class),
levels = c("benign", "malignant"))
# Pemeriksaan awal data
ringkasan_data <- data.frame(
Keterangan = c("Jumlah observasi setelah pembersihan",
"Jumlah prediktor",
"Jumlah nilai hilang setelah pembersihan"),
Nilai = c(nrow(bc),
length(kolom_prediktor),
sum(is.na(bc)))
)
kable(ringkasan_data,
caption = "Ringkasan Dataset BreastCancer")| Keterangan | Nilai |
|---|---|
| Jumlah observasi setelah pembersihan | 683 |
| Jumlah prediktor | 9 |
| Jumlah nilai hilang setelah pembersihan | 0 |
# Distribusi kelas
tabel_kelas <- as.data.frame(table(Class = bc$Class))
names(tabel_kelas)[2] <- "Jumlah"
kable(tabel_kelas,
caption = "Distribusi Kelas pada Dataset BreastCancer")| Class | Jumlah |
|---|---|
| benign | 444 |
| malignant | 239 |
Berdasarkan hasil statistik deskriptif pada data BreastCancer, diperoleh sebanyak 683 observasi dan 10 variabel yang terdiri atas 9 variabel prediktor dan 1 variabel respon, yaitu Class. Data telah melalui proses pembersihan dengan menghapus kolom ID dan observasi yang memiliki missing value, sehingga tidak terdapat nilai yang hilang pada seluruh variabel. Variabel respon Class terdiri atas 444 data benign (jinak) atau sebesar 65,01% dan 239 data malignant (ganas) atau sebesar 34,99%. Hasil tersebut menunjukkan bahwa data didominasi oleh kelas benign. Data ini selanjutnya digunakan untuk membangun model Random Forest Classification dengan variasi mtry = 2, 3, dan 5 dan num.trees = 200, 500, dan 1000 untuk membandingkan kinerja klasifikasi berdasarkan metrik evaluasi, yaitu Accuracy, Precision, Recall, Specificity, dan F1-Score.
set.seed(234)
idx_train <- createDataPartition(
bc$Class,
p = 0.70,
list = FALSE
)
bc.train <- bc[idx_train, , drop = FALSE]
bc.test <- bc[-idx_train, , drop = FALSE]
# Ringkasan pembagian data
ringkasan_split <- data.frame(
Data = c("Training", "Testing", "Total"),
Jumlah_Observasi = c(
nrow(bc.train),
nrow(bc.test),
nrow(bc)
)
)
kable(ringkasan_split,
caption = "Pembagian Data Training dan Testing")| Data | Jumlah_Observasi |
|---|---|
| Training | 479 |
| Testing | 204 |
| Total | 683 |
# Distribusi kelas data training
distribusi_train <- as.data.frame(
table(Kelas = bc.train$Class)
)
names(distribusi_train) <- c("Kelas", "Jumlah")
kable(distribusi_train,
caption = "Distribusi Kelas pada Data Training")| Kelas | Jumlah |
|---|---|
| benign | 311 |
| malignant | 168 |
# Distribusi kelas data testing
distribusi_test <- as.data.frame(
table(Kelas = bc.test$Class)
)
names(distribusi_test) <- c("Kelas", "Jumlah")
kable(distribusi_test,
caption = "Distribusi Kelas pada Data Testing")| Kelas | Jumlah |
|---|---|
| benign | 133 |
| malignant | 71 |
Berdasarkan hasil pembagian data BreastCancer, diperoleh sebanyak 479 observasi sebagai data training (70%) dan 204 observasi sebagai data testing (30%) dari total 683 observasi. Pada data testing, terdapat 133 observasi kelas benign (jinak) atau sebesar 65,20% dan 71 observasi kelas malignant (ganas) atau sebesar 34,80%. Hasil tersebut menunjukkan bahwa kelas benign memiliki proporsi lebih besar dibandingkan kelas malignant pada data testing. Data training ini digunakan untuk membangun model Random Forest Classification, sedangkan data testing digunakan untuk mengevaluasi kinerja model.
# Kombinasi parameter model
kombinasi <- expand.grid(
mtry = c(2, 3, 5),
num.trees = c(200, 500, 1000),
KEEP.OUT.ATTRS = FALSE,
stringsAsFactors = FALSE
)
# Membentuk sembilan model Random Forest
model_rf <- vector("list", nrow(kombinasi))
nama_model <- paste0(
"mtry", kombinasi$mtry,
"_trees", kombinasi$num.trees
)
names(model_rf) <- nama_model
for (i in seq_len(nrow(kombinasi))) {
model_rf[[i]] <- ranger(
formula = Class ~ .,
data = bc.train,
num.trees = kombinasi$num.trees[i],
mtry = kombinasi$mtry[i],
min.node.size = 1,
replace = TRUE,
sample.fraction = 1,
importance = "permutation",
seed = 234
)
}
# Menghitung OOB Error setiap model
hasil_oob <- data.frame(
Model = names(model_rf),
mtry = kombinasi$mtry,
Num_Trees = kombinasi$num.trees,
OOB_Error = vapply(
model_rf,
function(m) as.numeric(m$prediction.error),
numeric(1)
)
)
kable(hasil_oob, digits = 4,
caption = "Perbandingan OOB Error pada Sembilan Model")| Model | mtry | Num_Trees | OOB_Error | |
|---|---|---|---|---|
| mtry2_trees200 | mtry2_trees200 | 2 | 200 | 0.0292 |
| mtry3_trees200 | mtry3_trees200 | 3 | 200 | 0.0271 |
| mtry5_trees200 | mtry5_trees200 | 5 | 200 | 0.0292 |
| mtry2_trees500 | mtry2_trees500 | 2 | 500 | 0.0292 |
| mtry3_trees500 | mtry3_trees500 | 3 | 500 | 0.0292 |
| mtry5_trees500 | mtry5_trees500 | 5 | 500 | 0.0292 |
| mtry2_trees1000 | mtry2_trees1000 | 2 | 1000 | 0.0292 |
| mtry3_trees1000 | mtry3_trees1000 | 3 | 1000 | 0.0271 |
| mtry5_trees1000 | mtry5_trees1000 | 5 | 1000 | 0.0271 |
Berdasarkan tabel perbandingan Out-of-Bag (OOB) Error pada sembilan model Random Forest, diperoleh nilai OOB Error yang berkisar antara 0,0271 hingga 0,0292. Nilai OOB Error terendah sebesar 0,0271 diperoleh pada model mtry3_trees200, mtry3_trees1000, dan mtry5_trees1000, sedangkan nilai tertinggi sebesar 0,0292 diperoleh pada enam model lainnya. Hal ini menunjukkan bahwa ketiga model dengan nilai OOB Error sebesar 0,0271 memiliki tingkat kesalahan prediksi yang lebih rendah dibandingkan model lainnya berdasarkan evaluasi OOB. Sehingga model mtry3_trees200, mtry3_trees1000, dan mtry5_trees1000 menjadi kandidat model terbaik berdasarkan nilai OOB Error, meskipun penentuan model terbaik secara keseluruhan tetap perlu mempertimbangkan hasil evaluasi pada data pengujian.
# Fungsi menghitung metrik evaluasi
hitung_evaluasi <- function(aktual, prediksi) {
aktual <- factor(
aktual,
levels = c("benign", "malignant")
)
prediksi <- factor(
prediksi,
levels = c("benign", "malignant")
)
tab <- table(
Aktual = aktual,
Prediksi = prediksi
)
TN <- unname(tab["benign", "benign"])
FP <- unname(tab["benign", "malignant"])
FN <- unname(tab["malignant", "benign"])
TP <- unname(tab["malignant", "malignant"])
pembagi <- function(a, b) {
if (b == 0) NA_real_ else a / b
}
precision <- pembagi(TP, TP + FP)
recall <- pembagi(TP, TP + FN)
specificity <- pembagi(TN, TN + FP)
f1 <- if (is.na(precision) ||
is.na(recall) ||
precision + recall == 0) {
NA_real_
} else {
2 * precision * recall / (precision + recall)
}
list(
confusion = tab,
metrics = data.frame(
Accuracy = (TP + TN) / sum(tab),
Precision = precision,
Recall = recall,
Specificity = specificity,
F1_Score = f1
)
)
}
# Menyiapkan tempat penyimpanan hasil
prediksi_rf <- vector("list", length(model_rf))
names(prediksi_rf) <- names(model_rf)
confusion_rf <- vector("list", length(model_rf))
names(confusion_rf) <- names(model_rf)
daftar_evaluasi <- vector("list", length(model_rf))
# Prediksi dan evaluasi seluruh model
for (i in seq_along(model_rf)) {
pred <- predict(
model_rf[[i]],
data = bc.test
)$predictions
pred <- factor(
as.character(pred),
levels = c("benign", "malignant")
)
prediksi_rf[[i]] <- pred
ev <- hitung_evaluasi(bc.test$Class, pred)
confusion_rf[[i]] <- ev$confusion
daftar_evaluasi[[i]] <- data.frame(
Model = names(model_rf)[i],
mtry = kombinasi$mtry[i],
Num_Trees = kombinasi$num.trees[i],
ev$metrics,
check.names = FALSE
)
}
# Menggabungkan hasil evaluasi
hasil_metrik <- bind_rows(daftar_evaluasi)
kolom_metrik <- c(
"Accuracy", "Precision", "Recall",
"Specificity", "F1_Score"
)
hasil_metrik[kolom_metrik] <- lapply(
hasil_metrik[kolom_metrik],
as.numeric
)
# Menyusun confusion matrix seluruh model
tabel_confusion <- bind_rows(
lapply(names(confusion_rf), function(nm) {
tab <- confusion_rf[[nm]]
data.frame(
Model = nm,
Aktual = rownames(tab),
Prediksi_benign = as.integer(tab[, "benign"]),
Prediksi_malignant = as.integer(tab[, "malignant"]),
row.names = NULL
)
})
)
kable(
tabel_confusion,
caption = "Confusion Matrix Seluruh Model (baris = kelas aktual)"
)| Model | Aktual | Prediksi_benign | Prediksi_malignant |
|---|---|---|---|
| mtry2_trees200 | benign | 130 | 3 |
| mtry2_trees200 | malignant | 1 | 70 |
| mtry3_trees200 | benign | 130 | 3 |
| mtry3_trees200 | malignant | 3 | 68 |
| mtry5_trees200 | benign | 129 | 4 |
| mtry5_trees200 | malignant | 4 | 67 |
| mtry2_trees500 | benign | 129 | 4 |
| mtry2_trees500 | malignant | 1 | 70 |
| mtry3_trees500 | benign | 130 | 3 |
| mtry3_trees500 | malignant | 3 | 68 |
| mtry5_trees500 | benign | 129 | 4 |
| mtry5_trees500 | malignant | 4 | 67 |
| mtry2_trees1000 | benign | 129 | 4 |
| mtry2_trees1000 | malignant | 2 | 69 |
| mtry3_trees1000 | benign | 129 | 4 |
| mtry3_trees1000 | malignant | 3 | 68 |
| mtry5_trees1000 | benign | 129 | 4 |
| mtry5_trees1000 | malignant | 5 | 66 |
# Tabel metrik evaluasi
kable(
hasil_metrik,
digits = 4,
caption = "Perbandingan Metrik Evaluasi pada Data Testing"
)| Model | mtry | Num_Trees | Accuracy | Precision | Recall | Specificity | F1_Score |
|---|---|---|---|---|---|---|---|
| mtry2_trees200 | 2 | 200 | 0.9804 | 0.9589 | 0.9859 | 0.9774 | 0.9722 |
| mtry3_trees200 | 3 | 200 | 0.9706 | 0.9577 | 0.9577 | 0.9774 | 0.9577 |
| mtry5_trees200 | 5 | 200 | 0.9608 | 0.9437 | 0.9437 | 0.9699 | 0.9437 |
| mtry2_trees500 | 2 | 500 | 0.9755 | 0.9459 | 0.9859 | 0.9699 | 0.9655 |
| mtry3_trees500 | 3 | 500 | 0.9706 | 0.9577 | 0.9577 | 0.9774 | 0.9577 |
| mtry5_trees500 | 5 | 500 | 0.9608 | 0.9437 | 0.9437 | 0.9699 | 0.9437 |
| mtry2_trees1000 | 2 | 1000 | 0.9706 | 0.9452 | 0.9718 | 0.9699 | 0.9583 |
| mtry3_trees1000 | 3 | 1000 | 0.9657 | 0.9444 | 0.9577 | 0.9699 | 0.9510 |
| mtry5_trees1000 | 5 | 1000 | 0.9559 | 0.9429 | 0.9296 | 0.9699 | 0.9362 |
Berdasarkan hasil confusion matrix dan evaluasi model, model mtry2_trees200 menunjukkan kinerja klasifikasi terbaik dibandingkan delapan model lainnya. Model tersebut berhasil mengklasifikasikan 130 data benign dan 70 data malignant dengan benar, serta hanya menghasilkan 4 kesalahan klasifikasi. Hal ini ditunjukkan oleh nilai accuracy sebesar 0,9804, precision sebesar 0,9589, recall sebesar 0,9859, specificity sebesar 0,9774, dan F1-score sebesar 0,9722. Nilai OOB Error model tersebut sebesar 0,0292, sedikit lebih tinggi dibandingkan beberapa model lain yang memiliki OOB Error sebesar 0,0271. Meskipun demikian, berdasarkan evaluasi pada data pengujian, mtry2_trees200 tetap menjadi model terbaik karena menghasilkan nilai accuracy, precision, recall, dan F1-score tertinggi, sehingga dipilih sebagai model dengan kinerja klasifikasi paling baik.
# Membuat label konfigurasi model
hasil_metrik$Konfigurasi <- paste0(
"mtry=", hasil_metrik$mtry,
", trees=", hasil_metrik$Num_Trees
)
# Mengubah data menjadi format long
hasil_long <- tidyr::pivot_longer(
hasil_metrik,
cols = all_of(kolom_metrik),
names_to = "Metrik",
values_to = "Nilai"
)
# Membuat grafik perbandingan
ggplot(
hasil_long,
aes(x = Konfigurasi, y = Nilai)
) +
geom_point(size = 2) +
facet_wrap(~ Metrik, scales = "free_y") +
labs(
title = "Perbandingan Metrik Random Forest pada Data Testing",
x = "Konfigurasi Model",
y = "Nilai Metrik"
) +
theme_minimal() +
theme(
axis.text.x = element_text(
angle = 45,
hjust = 1
)
)Berdasarkan grafik perbandingan metrik evaluasi pada data testing, model mtry2_trees200 menunjukkan kinerja terbaik dengan nilai accuracy sebesar 0,9804, precision sebesar 0,9589, recall sebesar 0,9859, specificity sebesar 0,9774, dan F1-score sebesar 0,9722. Model tersebut memiliki nilai accuracy, precision, recall, dan F1-score tertinggi dibandingkan model lainnya, sedangkan nilai specificity-nya juga termasuk yang tertinggi. Secara umum, peningkatan jumlah pohon (num.trees) tidak selalu menghasilkan peningkatan kinerja model, begitu pula penggunaan nilai mtry yang lebih besar cenderung menghasilkan nilai metrik yang lebih rendah pada beberapa konfigurasi. Hal ini menunjukkan bahwa pemilihan kombinasi parameter mtry dan num.trees berpengaruh terhadap hasil klasifikasi. Sehingga model mtry2_trees200 dipilih sebagai model terbaik karena memberikan kinerja klasifikasi paling optimal berdasarkan keseluruhan metrik evaluasi pada data testing.
# Menggabungkan permutation importance seluruh model
importance_all <- bind_rows(
lapply(names(model_rf), function(nm) {
imp <- model_rf[[nm]]$variable.importance
data.frame(
Model = nm,
Variabel = names(imp),
Permutation_Importance = as.numeric(imp),
row.names = NULL
)
})
)
# Menampilkan tabel variable importance
kable(
importance_all %>%
arrange(Model, desc(Permutation_Importance)),
digits = 4,
caption = "Permutation Variable Importance untuk Seluruh Model"
)| Model | Variabel | Permutation_Importance |
|---|---|---|
| mtry2_trees1000 | Bare.nuclei | 0.0817 |
| mtry2_trees1000 | Cell.size | 0.0779 |
| mtry2_trees1000 | Cell.shape | 0.0626 |
| mtry2_trees1000 | Cl.thickness | 0.0263 |
| mtry2_trees1000 | Bl.cromatin | 0.0205 |
| mtry2_trees1000 | Normal.nucleoli | 0.0199 |
| mtry2_trees1000 | Marg.adhesion | 0.0189 |
| mtry2_trees1000 | Epith.c.size | 0.0140 |
| mtry2_trees1000 | Mitoses | 0.0033 |
| mtry2_trees200 | Bare.nuclei | 0.0839 |
| mtry2_trees200 | Cell.size | 0.0787 |
| mtry2_trees200 | Cell.shape | 0.0610 |
| mtry2_trees200 | Cl.thickness | 0.0245 |
| mtry2_trees200 | Bl.cromatin | 0.0215 |
| mtry2_trees200 | Normal.nucleoli | 0.0204 |
| mtry2_trees200 | Marg.adhesion | 0.0193 |
| mtry2_trees200 | Epith.c.size | 0.0117 |
| mtry2_trees200 | Mitoses | 0.0038 |
| mtry2_trees500 | Bare.nuclei | 0.0805 |
| mtry2_trees500 | Cell.size | 0.0773 |
| mtry2_trees500 | Cell.shape | 0.0630 |
| mtry2_trees500 | Cl.thickness | 0.0267 |
| mtry2_trees500 | Bl.cromatin | 0.0219 |
| mtry2_trees500 | Normal.nucleoli | 0.0218 |
| mtry2_trees500 | Marg.adhesion | 0.0191 |
| mtry2_trees500 | Epith.c.size | 0.0132 |
| mtry2_trees500 | Mitoses | 0.0031 |
| mtry3_trees1000 | Bare.nuclei | 0.1003 |
| mtry3_trees1000 | Cell.size | 0.0855 |
| mtry3_trees1000 | Cell.shape | 0.0593 |
| mtry3_trees1000 | Cl.thickness | 0.0248 |
| mtry3_trees1000 | Marg.adhesion | 0.0195 |
| mtry3_trees1000 | Bl.cromatin | 0.0192 |
| mtry3_trees1000 | Normal.nucleoli | 0.0165 |
| mtry3_trees1000 | Epith.c.size | 0.0119 |
| mtry3_trees1000 | Mitoses | 0.0032 |
| mtry3_trees200 | Bare.nuclei | 0.0972 |
| mtry3_trees200 | Cell.size | 0.0917 |
| mtry3_trees200 | Cell.shape | 0.0628 |
| mtry3_trees200 | Cl.thickness | 0.0278 |
| mtry3_trees200 | Marg.adhesion | 0.0191 |
| mtry3_trees200 | Bl.cromatin | 0.0180 |
| mtry3_trees200 | Normal.nucleoli | 0.0160 |
| mtry3_trees200 | Epith.c.size | 0.0099 |
| mtry3_trees200 | Mitoses | 0.0037 |
| mtry3_trees500 | Bare.nuclei | 0.0991 |
| mtry3_trees500 | Cell.size | 0.0853 |
| mtry3_trees500 | Cell.shape | 0.0651 |
| mtry3_trees500 | Cl.thickness | 0.0260 |
| mtry3_trees500 | Marg.adhesion | 0.0193 |
| mtry3_trees500 | Bl.cromatin | 0.0188 |
| mtry3_trees500 | Normal.nucleoli | 0.0148 |
| mtry3_trees500 | Epith.c.size | 0.0109 |
| mtry3_trees500 | Mitoses | 0.0032 |
| mtry5_trees1000 | Bare.nuclei | 0.1214 |
| mtry5_trees1000 | Cell.size | 0.0911 |
| mtry5_trees1000 | Cell.shape | 0.0438 |
| mtry5_trees1000 | Cl.thickness | 0.0227 |
| mtry5_trees1000 | Normal.nucleoli | 0.0208 |
| mtry5_trees1000 | Marg.adhesion | 0.0189 |
| mtry5_trees1000 | Bl.cromatin | 0.0162 |
| mtry5_trees1000 | Epith.c.size | 0.0097 |
| mtry5_trees1000 | Mitoses | 0.0032 |
| mtry5_trees200 | Bare.nuclei | 0.1259 |
| mtry5_trees200 | Cell.size | 0.0898 |
| mtry5_trees200 | Cell.shape | 0.0427 |
| mtry5_trees200 | Cl.thickness | 0.0233 |
| mtry5_trees200 | Normal.nucleoli | 0.0217 |
| mtry5_trees200 | Marg.adhesion | 0.0209 |
| mtry5_trees200 | Bl.cromatin | 0.0142 |
| mtry5_trees200 | Epith.c.size | 0.0086 |
| mtry5_trees200 | Mitoses | 0.0026 |
| mtry5_trees500 | Bare.nuclei | 0.1243 |
| mtry5_trees500 | Cell.size | 0.0909 |
| mtry5_trees500 | Cell.shape | 0.0460 |
| mtry5_trees500 | Cl.thickness | 0.0217 |
| mtry5_trees500 | Normal.nucleoli | 0.0203 |
| mtry5_trees500 | Marg.adhesion | 0.0195 |
| mtry5_trees500 | Bl.cromatin | 0.0153 |
| mtry5_trees500 | Epith.c.size | 0.0093 |
| mtry5_trees500 | Mitoses | 0.0030 |
# Membuat grafik variable importance
ggplot(
importance_all,
aes(
x = reorder(Variabel, Permutation_Importance),
y = Permutation_Importance
)
) +
geom_col() +
coord_flip() +
facet_wrap(~ Model, scales = "free_y") +
labs(
title = "Variable Importance pada Sembilan Model Random Forest",
x = "Variabel",
y = "Permutation Importance"
) +
theme_minimal()Berdasarkan grafik Variable Importance pada sembilan model Random Forest, terlihat bahwa variabel Bare.nuclei memiliki tingkat kepentingan tertinggi pada seluruh model, diikuti oleh Cell.size dan Cell.shape. Hal ini menunjukkan bahwa ketiga variabel tersebut memberikan kontribusi paling besar dalam proses klasifikasi kelas benign dan malignant, karena perubahan atau pengacakan nilai pada variabel tersebut menyebabkan penurunan kinerja model yang relatif lebih besar. Variabel Cl.thickness, Marg.adhesion, Normal.nucleoli, dan Bl.cromatin memiliki tingkat kepentingan yang lebih rendah, sedangkan Epith.c.size dan Mitoses cenderung menjadi variabel dengan tingkat kepentingan paling rendah. Pola tingkat kepentingan variabel tersebut relatif konsisten pada kesembilan model, meskipun terdapat perbedaan besarnya nilai permutation importance. Sehingga, Bare.nuclei, Cell.size, dan Cell.shape merupakan variabel yang paling berkontribusi dalam membedakan kelas kanker pada dataset BreastCancer.
# Menggabungkan hasil metrik dan OOB Error
peringkat <- hasil_metrik %>%
left_join(
hasil_oob %>% select(Model, OOB_Error),
by = "Model"
) %>%
mutate(
Rank_Accuracy = rank(-Accuracy, ties.method = "min"),
Rank_Precision = rank(-Precision, ties.method = "min"),
Rank_Recall = rank(-Recall, ties.method = "min"),
Rank_Specificity = rank(-Specificity, ties.method = "min"),
Rank_F1 = rank(-F1_Score, ties.method = "min"),
Rank_OOB = rank(OOB_Error, ties.method = "min"),
Rata_Rata_Peringkat = rowMeans(
cbind(
Rank_Accuracy,
Rank_Precision,
Rank_Recall,
Rank_Specificity,
Rank_F1,
Rank_OOB
),
na.rm = TRUE
)
) %>%
arrange(
Rata_Rata_Peringkat,
desc(Recall),
OOB_Error
)
# Menampilkan peringkat seluruh model
kable(
peringkat,
digits = 4,
caption = "Peringkat Model Berdasarkan Metrik Testing dan OOB Error"
)| Model | mtry | Num_Trees | Accuracy | Precision | Recall | Specificity | F1_Score | Konfigurasi | OOB_Error | Rank_Accuracy | Rank_Precision | Rank_Recall | Rank_Specificity | Rank_F1 | Rank_OOB | Rata_Rata_Peringkat |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| mtry2_trees200 | 2 | 200 | 0.9804 | 0.9589 | 0.9859 | 0.9774 | 0.9722 | mtry=2, trees=200 | 0.0292 | 1 | 1 | 1 | 1 | 1 | 4 | 1.5000 |
| mtry3_trees200 | 3 | 200 | 0.9706 | 0.9577 | 0.9577 | 0.9774 | 0.9577 | mtry=3, trees=200 | 0.0271 | 3 | 2 | 4 | 1 | 4 | 1 | 2.5000 |
| mtry2_trees500 | 2 | 500 | 0.9755 | 0.9459 | 0.9859 | 0.9699 | 0.9655 | mtry=2, trees=500 | 0.0292 | 2 | 4 | 1 | 4 | 2 | 4 | 2.8333 |
| mtry3_trees500 | 3 | 500 | 0.9706 | 0.9577 | 0.9577 | 0.9774 | 0.9577 | mtry=3, trees=500 | 0.0292 | 3 | 2 | 4 | 1 | 4 | 4 | 3.0000 |
| mtry2_trees1000 | 2 | 1000 | 0.9706 | 0.9452 | 0.9718 | 0.9699 | 0.9583 | mtry=2, trees=1000 | 0.0292 | 3 | 5 | 3 | 4 | 3 | 4 | 3.6667 |
| mtry3_trees1000 | 3 | 1000 | 0.9657 | 0.9444 | 0.9577 | 0.9699 | 0.9510 | mtry=3, trees=1000 | 0.0271 | 6 | 6 | 4 | 4 | 6 | 1 | 4.5000 |
| mtry5_trees200 | 5 | 200 | 0.9608 | 0.9437 | 0.9437 | 0.9699 | 0.9437 | mtry=5, trees=200 | 0.0292 | 7 | 7 | 7 | 4 | 7 | 4 | 6.0000 |
| mtry5_trees500 | 5 | 500 | 0.9608 | 0.9437 | 0.9437 | 0.9699 | 0.9437 | mtry=5, trees=500 | 0.0292 | 7 | 7 | 7 | 4 | 7 | 4 | 6.0000 |
| mtry5_trees1000 | 5 | 1000 | 0.9559 | 0.9429 | 0.9296 | 0.9699 | 0.9362 | mtry=5, trees=1000 | 0.0271 | 9 | 9 | 9 | 4 | 9 | 1 | 6.8333 |
# Menentukan model terbaik
model_pilihan <- peringkat[1, ]
cat(
"Berdasarkan rata-rata peringkat seluruh metrik testing dan OOB error, konfigurasi dengan peringkat pertama adalah ",
model_pilihan$Model,
" (mtry = ", model_pilihan$mtry,
", num.trees = ", model_pilihan$Num_Trees,
"). Penetapan ini merupakan ringkasan perbandingan dari sembilan konfigurasi yang diuji.",
sep = ""
)## Berdasarkan rata-rata peringkat seluruh metrik testing dan OOB error, konfigurasi dengan peringkat pertama adalah mtry2_trees200 (mtry = 2, num.trees = 200). Penetapan ini merupakan ringkasan perbandingan dari sembilan konfigurasi yang diuji.
# Mengidentifikasi lima variabel terpenting
importance_pilihan <- importance_all %>%
filter(Model == model_pilihan$Model) %>%
arrange(desc(Permutation_Importance))
kable(
head(importance_pilihan, 5),
digits = 4,
caption = paste(
"Lima Variabel Terpenting pada Model",
model_pilihan$Model
)
)| Model | Variabel | Permutation_Importance |
|---|---|---|
| mtry2_trees200 | Bare.nuclei | 0.0839 |
| mtry2_trees200 | Cell.size | 0.0787 |
| mtry2_trees200 | Cell.shape | 0.0610 |
| mtry2_trees200 | Cl.thickness | 0.0245 |
| mtry2_trees200 | Bl.cromatin | 0.0215 |
Berdasarkan tabel Permutation Importance pada model terbaik mtry2_trees200, variabel Bare.nuclei memiliki tingkat kepentingan tertinggi dengan nilai sebesar 0,0839, diikuti oleh Cell.size sebesar 0,0787 dan Cell.shape sebesar 0,0610. Selanjutnya, variabel Cl.thickness dan Bl.cromatin memiliki nilai kepentingan masing-masing sebesar 0,0245 dan 0,0215. Hasil tersebut menunjukkan bahwa Bare.nuclei, Cell.size, dan Cell.shape merupakan tiga variabel yang paling berkontribusi dalam proses klasifikasi pada model terbaik. Sedangkan, Bl.cromatin menjadi variabel dengan tingkat kepentingan terendah di antara lima variabel yang ditampilkan. Semakin tinggi nilai Permutation Importance, semakin besar kontribusi variabel tersebut terhadap kemampuan model dalam melakukan klasifikasi.
Random Forest dan Double Random Forest merupakan metode ensemble learning berbasis decision tree yang menggabungkan sejumlah pohon keputusan untuk menghasilkan prediksi yang lebih baik. Kedua metode tersebut memanfaatkan proses pengacakan dalam pembentukan model untuk mengurangi kesalahan prediksi. Perbedaannya terletak pada mekanisme pembentukan pohon dan penerapan pengacakan dalam proses pemodelannya.
Implementasi Random Forest dan Double Random Forest dapat dilakukan untuk permasalahan klasifikasi maupun regresi dengan menyesuaikan jenis variabel respon dan hasil prediksi yang diharapkan. Pada klasifikasi, hasil prediksi ditentukan berdasarkan suara mayoritas pohon, sedangkan pada regresi diperoleh melalui rata-rata prediksi seluruh pohon. Penerapan kedua metode dilakukan melalui tahapan persiapan data, pembentukan model, prediksi, dan evaluasi.
Evaluasi performa model dapat dilakukan menggunakan metrik yang sesuai dengan jenis permasalahan, seperti accuracy, precision, recall, specificity, dan F1-score untuk klasifikasi serta metrik kesalahan prediksi untuk regresi. Nilai Out-of-Bag (OOB) error digunakan untuk memperkirakan tingkat kesalahan model menggunakan data yang tidak terpilih dalam proses pembentukan setiap pohon. Perbandingan nilai evaluasi dan OOB error dapat digunakan untuk menentukan metode yang memberikan performa prediksi lebih baik.
Berdasarkan hasil analisis dapat disimpulkan bahwa model Random Forest terbaik diperoleh pada konfigurasi mtry2_trees200 dengan nilai accuracy sebesar 98,04%, Precision sebesar 95,89%, Recall sebesar 98,59%, Specificity sebesar 97,74%, dan F1-score sebesar 97,22%. Model tersebut juga mampu menghasilkan tingkat kesalahan klasifikasi yang rendah serta menunjukkan kinerja yang baik dalam mengklasifikasikan kelas benign dan malignant. Variabel yang paling berkontribusi terhadap hasil klasifikasi adalah Bare.nuclei, Cell.size, dan Cell.shape.
Fransiska, H. (2026). Modul Praktikum Machine Learning dan Modern Prediction. Laboratorium Matematika Fakultas Matematika dan Ilmu Pengetahuan Alam Universitas Bengkulu.
Hasanah, U., Soleh, A. M., & Sadik, K. (2024). Pengaruh Random Undersampling, Oversampling, dan SMOTE terhadap Kinerja Model Prediksi Penyakit Kardiovaskular. Jurnal Matematika, Statistika Dan Komputasi, 21(1), 88–102. https://doi.org/10.20956/j.v21i1.35552
Khairunnisa, A., Notodiputro, K. A., & Sartono, B. (2024). A Comparative Study of Random Forest and Double Random Forest Models from View Points of Their Interpretability. Scientific Journal of Informatics, 11(1), 207–218. https://doi.org/10.15294/sji.v11i1.48721
Purwanto, A., Sartono, B., & Notodiputro, K. A. (2025). a Comparison of Random Forest and Double Random Forest: Dropout Rates of Madrasah Students in Indonesia. Barekeng, 19(1), 227–236. https://doi.org/10.30598/barekengvol19iss1pp227-236