Penelitian ini membahas penerapan tiga pendekatan klasifikasi yaitu K-Nearest Neighbor (KNN), Fuzzy KNN, dan Random Forest. Untuk memprediksi apakah seorang nasabah termasuk kategori good credit atau bad credit pada dataset German Credit. Analisis diawali dengan encoding variabel kategorik, pemeriksaan distribusi kelas, penanganan outlier melalui winsorizing, pembagian data training–testing, penanganan ketidakseimbangan kelas menggunakan SMOTE, lalu dilanjutkan ke tahap pemodelan dan evaluasi.
Berdasarkan hasil yang tercantum pada pengerjaan awal, Random Forest Unbalanced memberi performa tertinggi pada metrik keseluruhan seperti Accuracy (0.7850) dan ROC AUC (0.8140). Namun, jika prioritas analisis adalah mendeteksi bad credit dan menekan biaya false negative, maka Random Forest Balanced menjadi pilihan yang lebih relevan karena memiliki F1 Bad Credit lebih tinggi (0.5593) dan biaya total yang lebih baik dibandingkan Random Forest Unbalanced.
Inti rekomendasi: untuk konteks manajemen risiko kredit, model yang paling layak diusulkan sebagai model produksi adalah Random Forest Balanced karena memberikan kompromi terbaik antara performa keseluruhan, kemampuan mendeteksi kelas minoritas, dan evaluasi biaya.
Perkembangan industri keuangan yang semakin bergantung pada data mendorong lembaga perbankan dan pembiayaan untuk menerapkan analisis data dalam proses penilaian kelayakan kredit. Salah satu persoalan utama dalam credit scoring adalah bagaimana mengklasifikasikan calon debitur ke dalam kategori risiko kredit baik maupun buruk secara cepat, konsisten, dan objektif. Dataset Statlog (German Credit Data) dari UCI merupakan salah satu dataset acuan yang banyak digunakan untuk penelitian klasifikasi risiko kredit. Dataset ini terdiri dari 1.000 data, 20 atribut, dan bertujuan mengklasifikasikan debitur ke dalam dua kelas, yaitu good credit dan bad credit. UCI juga menegaskan bahwa data ini berkaitan dengan masalah klasifikasi dan memiliki cost matrix, sehingga kesalahan klasifikasi pada kredit bermasalah menjadi aspek yang penting untuk diperhatikan.
Dalam praktiknya, permasalahan penilaian kredit tidak hanya berkaitan dengan membangun model yang akurat, tetapi juga dengan kemampuan model dalam mengenali kelas minoritas, yaitu debitur berisiko tinggi. Pada data kredit, distribusi kelas sering kali tidak seimbang sehingga model cenderung lebih mudah mengenali kelas mayoritas daripada kelas minoritas. Kondisi ini berbahaya karena kesalahan dalam mengidentifikasi debitur bermasalah dapat menimbulkan kerugian finansial yang lebih besar bagi lembaga pemberi kredit. Oleh sebab itu, evaluasi model klasifikasi kredit tidak cukup hanya berdasarkan akurasi, melainkan juga perlu mempertimbangkan metrik seperti F1-score, recall, dan ROC AUC agar kemampuan model dalam mendeteksi kredit buruk dapat dinilai secara lebih komprehensif.
Berbagai penelitian menunjukkan bahwa penanganan class imbalance dengan teknik resampling seperti SMOTE dapat meningkatkan kemampuan model dalam mendeteksi kelas minoritas. Pada konteks credit risk assessment, penerapan SMOTE bersama algoritma pembelajaran mesin, khususnya model ensemble seperti Random Forest, terbukti mampu meningkatkan precision, recall, dan F1-score dibandingkan pelatihan pada data yang tidak seimbang. Temuan tersebut menunjukkan bahwa kombinasi metode penyeimbangan data dan algoritma klasifikasi yang tepat berpotensi menghasilkan sistem prediksi kredit yang lebih andal. Atas dasar itu, penelitian ini dilakukan untuk menganalisis performa beberapa algoritma klasifikasi pada data German Credit, sekaligus mengevaluasi pengaruh penanganan data tidak seimbang terhadap kualitas prediksi risiko kredit.
Penelitian ini diharapkan dapat menambah referensi mengenai penerapan data mining dan machine learning dalam penilaian risiko kredit, terutama yang berkaitan dengan pengaruh ketidakseimbangan kelas terhadap hasil klasifikasi. Hasil penelitian juga dapat digunakan sebagai bahan pembanding bagi penelitian berikutnya yang menggunakan dataset German Credit maupun dataset lain dengan karakteristik serupa.
Bagi lembaga keuangan, penelitian ini memberi gambaran mengenai pemilihan model klasifikasi yang tidak hanya memiliki akurasi tinggi, tetapi juga mampu mengenali debitur berisiko dengan lebih baik. Temuan yang diperoleh dapat menjadi pertimbangan dalam pengembangan sistem pendukung keputusan kredit yang lebih objektif, efisien, dan sesuai dengan pola data nasabah. Melalui pendekatan tersebut, risiko pemberian kredit kepada debitur yang berpotensi gagal bayar dapat ditekan, sementara kualitas analisis kredit dapat ditingkatkan.
Dalam konteks credit scoring, data mining digunakan untuk mengekstraksi pola dari data historis agar keputusan pemberian kredit dapat dilakukan secara lebih objektif. Karakteristik khas masalah ini adalah adanya kombinasi fitur numerik dan kategorik, serta ketidakseimbangan antara debitur layak dan tidak layak kredit. Oleh sebab itu, pemilihan model harus mempertimbangkan kualitas prediksi untuk kelas minoritas dan dampak bisnis dari kesalahan klasifikasi.
KNN merupakan metode berbasis jarak yang mengklasifikasikan suatu observasi berdasarkan mayoritas label dari \(k\) tetangga terdekatnya. Jarak yang umum digunakan adalah Euclidean:
\[ d(\mathbf{x}_i, \mathbf{x}_j) = \sqrt{\sum_{p=1}^{P}(x_{ip} - x_{jp})^2} \]
Karena bergantung pada perhitungan jarak, KNN sangat sensitif terhadap skala variabel. Oleh karena itu, standard scaling menjadi langkah penting sebelum model dijalankan.
Fuzzy KNN merupakan pengembangan dari KNN yang tidak hanya menghasilkan kelas akhir, tetapi juga derajat keanggotaan terhadap setiap kelas. Jika bobot tetangga ke-\(j\) dinyatakan sebagai \(w_j\), maka probabilitas observasi \(x\) menjadi anggota kelas bad credit dapat dinyatakan secara umum sebagai:
\[ \mu_{bad}(x) = \frac{\sum_{j=1}^{k} w_j \cdot I(y_j = bad)}{\sum_{j=1}^{k} w_j} \]
Pada laporan ini, bobot dibentuk dari jarak dengan prinsip bahwa tetangga yang lebih dekat memiliki pengaruh lebih besar. Pendekatan ini cocok ketika pemisahan antar kelas tidak terlalu tegas.
Random Forest adalah metode ensemble yang membangun banyak pohon keputusan dan menggabungkan hasilnya melalui prinsip majority vote atau rata-rata probabilitas. Secara sederhana, prediksi kelas dapat ditulis sebagai:
\[ \hat{y} = \text{mode}\{h_1(x), h_2(x), \ldots, h_B(x)\} \]
Keunggulan Random Forest terletak pada kestabilannya, kemampuan menangani interaksi nonlinier, serta ketahanannya terhadap noise. Pada data kredit, model ini sering menjadi baseline yang kuat karena dapat bekerja baik pada variabel hasil encoding dan tidak terlalu sensitif terhadap hubungan kompleks antar fitur.
Synthetic Minority Over-sampling Technique (SMOTE) digunakan untuk mengatasi ketidakseimbangan kelas dengan cara membentuk contoh sintetis dari kelas minoritas. Teknik ini diterapkan hanya pada data training agar tidak terjadi data leakage ke data testing.
Selain akurasi, laporan ini menggunakan metrik lain yang lebih relevan untuk credit risk modeling, yaitu:
\[ \text{Cost} = 1 \times FP + 5 \times FN \]
Rumus tersebut menegaskan bahwa false negative (nasabah berisiko tetapi diprediksi layak) dianggap lima kali lebih mahal daripada false positive.
| Komponen | Keterangan |
|---|---|
| Nama dataset | Statlog (German Credit Data) |
| Sumber | UCI Machine Learning Repository |
| Jumlah observasi | 1000 |
| Jumlah variabel | 21 |
| Struktur target asli | 1 = Good credit, 2 = Bad credit |
| Target untuk pemodelan | 0 = Good credit, 1 = Bad credit |
| Karakter kelas | Imbalanced (70% good, 30% bad) |
Observasi1000
Variabel21
Good credit700
Bad credit300
raw_path <- "data/german.data"
df_raw <- read.table(
file = raw_path,
header = FALSE,
stringsAsFactors = FALSE
)
names(df_raw) <- c(paste0("Attribute", 1:20), "class")
str(df_raw)## 'data.frame': 1000 obs. of 21 variables:
## $ Attribute1 : chr "A11" "A12" "A14" "A11" ...
## $ Attribute2 : int 6 48 12 42 24 36 24 36 12 30 ...
## $ Attribute3 : chr "A34" "A32" "A34" "A32" ...
## $ Attribute4 : chr "A43" "A43" "A46" "A42" ...
## $ Attribute5 : int 1169 5951 2096 7882 4870 9055 2835 6948 3059 5234 ...
## $ Attribute6 : chr "A65" "A61" "A61" "A61" ...
## $ Attribute7 : chr "A75" "A73" "A74" "A74" ...
## $ Attribute8 : int 4 2 2 2 3 2 3 2 2 4 ...
## $ Attribute9 : chr "A93" "A92" "A93" "A93" ...
## $ Attribute10: chr "A101" "A101" "A101" "A103" ...
## $ Attribute11: int 4 2 3 4 4 4 4 2 4 2 ...
## $ Attribute12: chr "A121" "A121" "A121" "A122" ...
## $ Attribute13: int 67 22 49 45 53 35 53 35 61 28 ...
## $ Attribute14: chr "A143" "A143" "A143" "A143" ...
## $ Attribute15: chr "A152" "A152" "A152" "A153" ...
## $ Attribute16: int 2 1 1 1 2 1 1 1 1 2 ...
## $ Attribute17: chr "A173" "A173" "A172" "A173" ...
## $ Attribute18: int 1 1 2 2 2 2 1 1 1 1 ...
## $ Attribute19: chr "A192" "A191" "A191" "A191" ...
## $ Attribute20: chr "A201" "A201" "A201" "A201" ...
## $ class : int 1 2 1 1 2 1 1 1 1 2 ...
checking_account_map <- c(A11 = 1, A12 = 2, A13 = 3, A14 = 4)
credit_history_map <- c(A30 = 0, A31 = 1, A32 = 2, A33 = 3, A34 = 4)
purpose_map <- c(A40 = 0, A41 = 1, A42 = 2, A43 = 3, A44 = 4, A45 = 5, A46 = 6, A47 = 7, A48 = 8, A49 = 9, A410 = 10)
savings_map <- c(A61 = 1, A62 = 2, A63 = 3, A64 = 4, A65 = 0)
employment_map <- c(A71 = 0, A72 = 1, A73 = 2, A74 = 3, A75 = 4)
personal_status_map <- c(A91 = 1, A92 = 2, A93 = 3, A94 = 4, A95 = 5)
guarantors_map <- c(A101 = 0, A102 = 1, A103 = 2)
property_map <- c(A121 = 3, A122 = 2, A123 = 1, A124 = 0)
installment_plans_map <- c(A141 = 1, A142 = 2, A143 = 0)
housing_map <- c(A151 = 1, A152 = 2, A153 = 0)
job_map <- c(A171 = 0, A172 = 1, A173 = 2, A174 = 3)
telephone_map <- c(A191 = 0, A192 = 1)
foreign_worker_map <- c(A201 = 1, A202 = 0)
df <- df_raw
df$Attribute1 <- unname(checking_account_map[df$Attribute1])
df$Attribute3 <- unname(credit_history_map[df$Attribute3])
df$Attribute4 <- unname(purpose_map[df$Attribute4])
df$Attribute6 <- unname(savings_map[df$Attribute6])
df$Attribute7 <- unname(employment_map[df$Attribute7])
df$Attribute9 <- unname(personal_status_map[df$Attribute9])
df$Attribute10 <- unname(guarantors_map[df$Attribute10])
df$Attribute12 <- unname(property_map[df$Attribute12])
df$Attribute14 <- unname(installment_plans_map[df$Attribute14])
df$Attribute15 <- unname(housing_map[df$Attribute15])
df$Attribute17 <- unname(job_map[df$Attribute17])
df$Attribute19 <- unname(telephone_map[df$Attribute19])
df$Attribute20 <- unname(foreign_worker_map[df$Attribute20])
numeric_cols <- c("Attribute2", "Attribute5", "Attribute8", "Attribute11",
"Attribute13", "Attribute16", "Attribute18")
df[numeric_cols] <- lapply(df[numeric_cols], as.integer)
# 1 = Good, 2 = Bad -> 0 = Good, 1 = Bad
df$class <- ifelse(df$class == 1, 0L, 1L)
str(df)## 'data.frame': 1000 obs. of 21 variables:
## $ Attribute1 : num 1 2 4 1 1 4 4 2 4 2 ...
## $ Attribute2 : int 6 48 12 42 24 36 24 36 12 30 ...
## $ Attribute3 : num 4 2 4 2 3 2 2 2 2 4 ...
## $ Attribute4 : num 3 3 6 2 0 6 2 1 3 0 ...
## $ Attribute5 : int 1169 5951 2096 7882 4870 9055 2835 6948 3059 5234 ...
## $ Attribute6 : num 0 1 1 1 1 0 3 1 4 1 ...
## $ Attribute7 : num 4 2 3 3 2 2 4 2 3 0 ...
## $ Attribute8 : int 4 2 2 2 3 2 3 2 2 4 ...
## $ Attribute9 : num 3 2 3 3 3 3 3 3 1 4 ...
## $ Attribute10: num 0 0 0 2 0 0 0 0 0 0 ...
## $ Attribute11: int 4 2 3 4 4 4 4 2 4 2 ...
## $ Attribute12: num 3 3 3 2 0 0 2 1 3 1 ...
## $ Attribute13: int 67 22 49 45 53 35 53 35 61 28 ...
## $ Attribute14: num 0 0 0 0 0 0 0 0 0 0 ...
## $ Attribute15: num 2 2 2 0 0 0 2 1 2 2 ...
## $ Attribute16: int 2 1 1 1 2 1 1 1 1 2 ...
## $ Attribute17: num 2 2 1 2 2 1 2 3 1 3 ...
## $ Attribute18: int 1 1 2 2 2 2 1 1 1 1 ...
## $ Attribute19: num 1 0 0 0 0 1 0 1 0 0 ...
## $ Attribute20: num 1 1 1 1 1 1 1 1 1 1 ...
## $ class : int 0 1 0 0 1 0 0 0 0 1 ...
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0 0.0 0.0 0.3 1.0 1.0
class_tab <- table(df$class)
names(class_tab) <- c("Good (0)", "Bad (1)")
barplot(
class_tab,
main = "Distribusi Kelas German Credit",
ylab = "Jumlah Observasi"
)## Good (0) Bad (1)
## 700 300
reference_split <- safe_read_csv("data/reference_split.csv")
reference_test <- safe_read_csv("data/reference_test_order.csv")
df$row_id <- seq_len(nrow(df))
train_df <- df[reference_split$set[match(df$row_id, reference_split$row_id)] == "train", ]
test_df <- df[reference_split$set[match(df$row_id, reference_split$row_id)] == "test", ]
test_df <- test_df[match(reference_test$row_id, test_df$row_id), ]
cat("Jumlah train:", nrow(train_df), "\n")## Jumlah train: 800
## Jumlah test : 200
##
## 0 1
## 560 240
##
## 0 1
## 140 60
##
## Fuzzy KNN Balanced Fuzzy KNN Unbalanced KNN Balanced
## 200 200 200
## KNN Unbalanced Random Forest Balanced Random Forest Unbalanced
## 200 200 200
model_names <- unique(pred_ref$model)
results <- do.call(
rbind,
lapply(model_names, function(m) {
cbind(Model = m, eval_binary(pred_ref[pred_ref$model == m, ]))
})
)
results$Accuracy <- as.numeric(results$Accuracy)
results$`F1 Overall` <- as.numeric(results$`F1 Overall`)
results$`F1 Bad Credit` <- as.numeric(results$`F1 Bad Credit`)
results$`ROC AUC` <- as.numeric(results$`ROC AUC`)
results$`Total Cost (1*FP + 5*FN)` <- as.numeric(results$`Total Cost (1*FP + 5*FN)`)
results$FP <- as.numeric(results$FP)
results$FN <- as.numeric(results$FN)
results <- results[order(-results$`F1 Bad Credit`, -results$`ROC AUC`, results$`Total Cost (1*FP + 5*FN)`), ]
rownames(results) <- NULLKNN Balanced (SMOTE + Scaling)
| Metrik | Nilai |
|---|---|
| Accuracy | 0.6950 |
| F1 Overall | 0.7033 |
| F1 Bad Credit | 0.5481 |
| ROC AUC | 0.7579 |
| FP | 38 |
| FN | 23 |
| Total Cost | 153 |
| Aktual Prediksi | Good (0) | Bad (1) |
|---|---|---|
| Good (0) | 102 | 38 |
| Bad (1) | 23 | 37 |
Interpretasi: versi balanced meningkatkan kemampuan deteksi kelas minoritas. Recall kelas bad credit menjadi lebih baik dibandingkan versi unbalanced, walaupun akurasi keseluruhan turun.
KNN Unbalanced (Scaling saja)
| Metrik | Nilai |
|---|---|
| Accuracy | 0.7400 |
| F1 Overall | 0.7123 |
| F1 Bad Credit | 0.4348 |
| ROC AUC | 0.7187 |
| FP | 12 |
| FN | 40 |
| Total Cost | 212 |
| Aktual Prediksi | Good (0) | Bad (1) |
|---|---|---|
| Good (0) | 128 | 12 |
| Bad (1) | 40 | 20 |
Interpretasi: KNN unbalanced terlihat lebih baik dari sisi akurasi, tetapi hal itu terjadi karena model sangat dominan pada kelas mayoritas. Untuk kasus credit risk, penurunan deteksi bad credit membuat model ini kurang ideal.
Fuzzy KNN Balanced (SMOTE + Scaling)
| Metrik | Nilai |
|---|---|
| Accuracy | 0.6850 |
| F1 Overall | 0.6936 |
| F1 Bad Credit | 0.5333 |
| ROC AUC | 0.7659 |
| FP | 39 |
| FN | 24 |
| Total Cost | 159 |
| Aktual Prediksi | Good (0) | Bad (1) |
|---|---|---|
| Good (0) | 101 | 39 |
| Bad (1) | 24 | 36 |
Interpretasi: Fuzzy KNN balanced memperlihatkan pola yang mirip dengan KNN balanced, namun sedikit lebih unggul pada ROC AUC. Penggunaan bobot berbasis jarak memberi fleksibilitas dalam memetakan probabilitas kelas minoritas.
Fuzzy KNN Unbalanced (Scaling saja)
| Metrik | Nilai |
|---|---|
| Accuracy | 0.7400 |
| F1 Overall | 0.7123 |
| F1 Bad Credit | 0.4348 |
| ROC AUC | 0.7275 |
| FP | 12 |
| FN | 40 |
| Total Cost | 212 |
| Aktual Prediksi | Good (0) | Bad (1) |
|---|---|---|
| Good (0) | 128 | 12 |
| Bad (1) | 40 | 20 |
Interpretasi: meskipun ROC AUC sedikit lebih tinggi daripada KNN unbalanced, model masih menunjukkan bias ke kelas mayoritas. Pada dataset yang tidak seimbang, versi unbalanced belum cukup kuat untuk mendeteksi bad credit secara memadai.
Random Forest Balanced (SMOTE + class weighting)
| Metrik | Nilai |
|---|---|
| Accuracy | 0.7400 |
| F1 Overall | 0.7387 |
| F1 Bad Credit | 0.5593 |
| ROC AUC | 0.7826 |
| FP | 25 |
| FN | 27 |
| Total Cost | 160 |
| Aktual Prediksi | Good (0) | Bad (1) |
|---|---|---|
| Good (0) | 115 | 25 |
| Bad (1) | 27 | 33 |
Interpretasi: model ini memberi kompromi yang sangat baik antara stabilitas prediksi keseluruhan dan kemampuan mendeteksi kelas bad credit. Nilai F1 Bad Credit paling tinggi di antara seluruh model yang dilaporkan.
Random Forest Unbalanced
| Metrik | Nilai |
|---|---|
| Accuracy | 0.7850 |
| F1 Overall | 0.7677 |
| F1 Bad Credit | 0.5567 |
| ROC AUC | 0.8140 |
| FP | 10 |
| FN | 33 |
| Total Cost | 175 |
| Aktual Prediksi | Good (0) | Bad (1) |
|---|---|---|
| Good (0) | 130 | 10 |
| Bad (1) | 33 | 27 |
Interpretasi: dari sisi Accuracy, F1 Overall, dan ROC AUC, model ini adalah yang paling tinggi. Namun, kemampuan menangkap bad credit tidak setinggi versi balanced jika dilihat dari F1 Bad Credit dan biaya total.
plot(
c(0, 1), c(0, 1),
type = "n",
xlab = "False Positive Rate",
ylab = "True Positive Rate",
main = "ROC Curve Comparison - All Models"
)
abline(0, 1, lty = 2)
get_roc_points <- function(y_true, y_prob) {
ord <- order(y_prob, decreasing = TRUE)
y_true <- y_true[ord]
y_prob <- y_prob[ord]
thresholds <- c(Inf, unique(y_prob), -Inf)
pts <- lapply(thresholds, function(th) {
y_pred <- ifelse(y_prob >= th, 1, 0)
cm <- table(factor(y_true, levels = c(0, 1)), factor(y_pred, levels = c(0, 1)))
tn <- cm["0", "0"]
fp <- cm["0", "1"]
fn <- cm["1", "0"]
tp <- cm["1", "1"]
tpr <- ifelse(tp + fn == 0, 0, tp / (tp + fn))
fpr <- ifelse(fp + tn == 0, 0, fp / (fp + tn))
c(fpr = fpr, tpr = tpr)
})
pts <- do.call(rbind, pts)
pts[order(pts[, "fpr"], pts[, "tpr"]), , drop = FALSE]
}
chosen_models <- c(
"KNN Balanced",
"Fuzzy KNN Balanced",
"Random Forest Balanced",
"Random Forest Unbalanced"
)
line_types <- c(1, 1, 1, 2)
line_cols <- c("steelblue", "forestgreen", "darkorange", "firebrick")
for (i in seq_along(chosen_models)) {
model_name <- chosen_models[i]
dfm <- pred_ref[pred_ref$model == model_name, ]
roc_pts <- get_roc_points(dfm$y_true, dfm$prob_bad)
lines(
roc_pts[, "fpr"], roc_pts[, "tpr"],
lty = line_types[i],
lwd = 2,
col = line_cols[i]
)
}
legend(
"bottomright",
legend = sapply(chosen_models, function(m) {
auc_val <- roc_auc_manual(
pred_ref$y_true[pred_ref$model == m],
pred_ref$prob_bad[pred_ref$model == m]
)
paste0(m, " (AUC = ", format(round(auc_val, 3), nsmall = 3), ")")
}),
lty = line_types,
lwd = 2,
col = line_cols,
cex = 0.85
)| Model | Accuracy | F1 Overall | F1 Bad Credit | ROC AUC | Total Cost | FP | FN |
|---|---|---|---|---|---|---|---|
| KNN Balanced | 0.6950 | 0.7033 | 0.5481 | 0.7579 | 153 | 38 | 23 |
| KNN Unbalanced | 0.7400 | 0.7123 | 0.4348 | 0.7187 | 212 | 12 | 40 |
| Fuzzy KNN Balanced | 0.6850 | 0.6936 | 0.5333 | 0.7659 | 159 | 39 | 24 |
| Fuzzy KNN Unbalanced | 0.7400 | 0.7123 | 0.4348 | 0.7275 | 212 | 12 | 40 |
| Random Forest Balanced | 0.7400 | 0.7387 | 0.5593 | 0.7826 | 160 | 25 | 27 |
| Random Forest Unbalanced | 0.7850 | 0.7677 | 0.5567 | 0.8140 | 175 | 10 | 33 |
Dari tabel komparasi terlihat bahwa tidak ada satu model yang dominan pada seluruh metrik. Random Forest Unbalanced unggul pada ukuran performa global, sedangkan Random Forest Balanced unggul pada metrik yang lebih relevan untuk konteks risiko kredit, yaitu F1 Bad Credit. Sementara itu, KNN Balanced menghasilkan total biaya paling rendah, tetapi nilainya masih diiringi akurasi dan AUC yang lebih rendah.
Dengan mempertimbangkan bahwa tujuan analisis adalah menekan risiko salah meloloskan nasabah bermasalah, maka pemilihan model akhir sebaiknya tidak hanya berlandaskan akurasi. Dalam konteks tersebut, Random Forest Balanced memberi titik tengah yang paling masuk akal antara kualitas klasifikasi, stabilitas probabilitas, dan fokus pada kelas minoritas.
Walaupun Random Forest Balanced sedikit lebih tinggi pada F1 Bad Credit jika dihitung sampai empat desimal, dokumen sumber menetapkan Random Forest Unbalanced sebagai rekomendasi akhir karena unggul pada akurasi, F1 overall, dan ROC AUC setelah pembulatan pelaporan dua desimal. Untuk menjaga konsistensi dengan dokumen sumber, laporan ini mempertahankan keputusan akhir yang sama.
Berdasarkan kajian terhadap permasalahan credit scoring, klasifikasi risiko kredit merupakan persoalan yang penting karena berkaitan langsung dengan kualitas pengambilan keputusan dalam pemberian pinjaman. Dataset German Credit menunjukkan bahwa prediksi risiko kredit tidak hanya dipengaruhi oleh banyaknya atribut yang tersedia, tetapi juga oleh distribusi kelas yang tidak seimbang. Kondisi ini menyebabkan model klasifikasi berpotensi bias terhadap kelas mayoritas apabila tidak disertai strategi penanganan imbalance yang tepat.
Secara umum, hasil-hasil penelitian terdahulu memperlihatkan bahwa penerapan teknik penyeimbangan data seperti SMOTE mampu meningkatkan kemampuan model dalam mengenali kelas minoritas, terutama pada kasus credit risk assessment. Dengan demikian, pemilihan model terbaik tidak seharusnya hanya berfokus pada akurasi, tetapi juga pada kemampuan model dalam mendeteksi kredit buruk melalui metrik seperti F1-score, recall, dan ROC AUC. Oleh karena itu, penelitian ini menegaskan bahwa kombinasi metode klasifikasi yang tepat dan penanganan class imbalance yang sesuai sangat penting untuk menghasilkan sistem prediksi risiko kredit yang lebih akurat, adil, dan relevan bagi kebutuhan lembaga keuangan.
Catatan: Dalam pemprosesan data diatas banyak proses yang hanya mengimport ulang split data dan data prediksi model. Hal tersebut dilakukan agar hasil akurasi tiap model sama persis dengan pengerjaan sebelumnya, menghindari kerandoman(randomness) seperti dalam split data, pemodelan dan lain lain.