Credit risk adalah bentuk resiko kegagalan bayar oleh debitur yang ditanggung oleh creditur. Resiko ini bisa berdampak pada : * Penurunan income dari bunga * Gangguan modal kerja yang tidak kembali * Meningkatnya biaya yang berasal dari collection Untuk memperkecil resiko tersebut, sebuah praktik yang wajar di seluruh perusahaan keuangan untuk melakukan credit scoring dan credit rating pada calon debiturnya. Output dari sistem scoring akan menjadi tolak ukur apakah pengajuan pinjaman bisa diproses atau tidak.
Credit score adalah nilai yang diberikan pada calon debitur berdasarkan history dan/atau parameter-parameter tertentu. Proses dari pemberian credit score ini disebut sebagai credit scoring
Terdapat beberapa model scoring yang diterapkan lembaga-lembaga, namun kebanyakan mereka menggunakan model FICO sebagai standart. Model FICO memiliki rentang penilaian 300-850, di mana semakin tinggi nilai score, berarti calon debitur dinilai layak untuk diberi pembiayaan atau pinjaman. (Karena dianggap mampu mengembalikan pinjaman)
Risk rating; kadang banyak lembaga yang juga menggunakan risk rating. Berbanding terbalik dengan credit scoring, semakin tinggi nilai risk rating menunjukkan bahwa debitur semakin berisiko.
Sebagai gambaran, berikut adalah contoh data risk scoring
risk_data <- read_xlsx("risk-scoring-dataset-example.xlsx")
head(risk_data)
data untuk mengukur risk rating di atas terdiri dari 7 variabel: * kode_kontrak * pendapatan_setahun_juta (pendapatan tahunan dalam satuan juta) * kpr_aktif (status kepemilikan KPR yang masih berjalan) * durasi_pinjaman_bulan (tenor pinjaman) * jumlah_tanggungan (jumlah anggota keluarga yang dihidupi) * rata_rata_overdue (rata-rata keterlambatan; dikelompokkan dalam beberapa kategori) * risk_rating (rating resiko debitur)
Seorang analis akan mengolah data di atas, menemukan pola dan kecenderungan, juga hubungan-hubungan tertentu yang berdampak pada risk_rating. Inilah yang disebut analisa eskplorasi data; Sebagai contoh : 1. Jika jumlah tanggungan di atas 4, kecenderungan resiko semakin tinggi (rating 4 atau 5) 2. Jika durasi pinjaman semakin lama dari 24 bulan, kecenderungan resiko meningkat. Dari dua temuan pattern tersebut, analis kemudian membentuk aturan-aturan yang menuntun pengambilan keputusan (decision-making model) sebagai berikut : 1. Jika jumlah tanggungan kurang dari 5, dan durasi pinjaman kurang dari 24 bulan, maka rating resiko diberikan nilai 2 dan pengajuan diterima. 2. Jika jumlah tanggungan lebih dari 4, dan durasi pinjaman di atas 24 bulan maka rating bernilai 5, dan pinjaman ditolak. 3. Jika jumlah tanggungan kurang dari 5, dan durasi pinjaman kurang dari 36 bulan, maka rating bernilai 3, dan pinjaman diterima.
3 aturan di atas disebut adalah bentuk dari model untuk memprediksi nilai risk rating dan menjadi basis pengambilan keputusan terhadap aplikasi pinjaman baru.
Untuk model pengambilan keputusan seperti contoh di atas, kita akan menggunakan alat bernama ‘desison tree’. Ini adalah alat yang paling powerful dan populer untuk keperluan klasifikasi dan prediksi. Struktur decision tree terbagi dalam 3 elemen utama : root node, leaf node, dan branch.
Root node atau node akar. adalah attribute paling awal yang diestimasi. leaf node adalah hasil akhir yang menyimpan label atribute branch adalah kemungkinan output dari estimasi attribute pada root node dan internal node.
Decision tree lebih pantas digunakan untuk mengeksplorasi dan menemukan pengetahuan baru. Stuktur analisanya dimulai dari ‘akar’ atau root node yang menspesifikasi attribute pertama, dan kemudian dilanjutkan dengan spesifikasi attribute kedua berdasarkan output dari attribute pertam, dan begitu seterusnya.
Decision tree sebenarnya sedikit mengigatkan kita pada serangkaian proses logika kondisional oleh ‘if…else…’.
Merujuk pada kursus DQLab, kita akan menggunakan sistem otomasi model decision tree menggunakan algoritma R bernama C5.0
Untuk sementara, kita running kode di bawah ini, tanpa mempertanyakan apapun.
install.packages("C50")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:
https://cran.rstudio.com/bin/windows/Rtools/
Installing package into ‘C:/Users/Galih Dwika Putra R/Documents/R/win-library/4.1’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.1/C50_0.1.5.zip'
Content type 'application/zip' length 476472 bytes (465 KB)
downloaded 465 KB
package ‘C50’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\Galih Dwika Putra R\AppData\Local\Temp\Rtmp8meAp5\downloaded_packages
# load library C50
library(C50)
Warning: package ‘C50’ was built under R version 4.1.2
library(tidyverse)
Warning: package ‘tidyverse’ was built under R version 4.1.2
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
-- Attaching packages ----------------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.5 v purrr 0.3.4
v tibble 3.1.4 v dplyr 1.0.7
v tidyr 1.1.4 v stringr 1.4.0
v readr 2.0.2 v forcats 0.5.1
Warning: package ‘tidyr’ was built under R version 4.1.2
Warning: package ‘dplyr’ was built under R version 4.1.2
-- Conflicts -------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
# siapkan data. Pada contoh kali ini, kita secara abritrari hanya memasukkan variabel jumlah_tanggungan, dan durasi_pinjaman_bulan
datafeed <- select(risk_data, jumlah_tanggungan, durasi_pinjaman_bulan)
head(datafeed)
# Model C5.0 Decision Tree
risk_model <- C5.0(datafeed, as.factor(risk_data$risk_rating))
summary(risk_model)
Call:
C5.0.default(x = datafeed, y = as.factor(risk_data$risk_rating))
C5.0 [Release 2.07 GPL Edition] Sun Jan 23 18:44:55 2022
-------------------------------
Class specified by attribute `outcome'
Read 900 cases (3 attributes) from undefined.data
Decision tree:
jumlah_tanggungan > 4:
:...durasi_pinjaman_bulan <= 24: 4 (112/30)
: durasi_pinjaman_bulan > 24: 5 (140/55)
jumlah_tanggungan <= 4:
:...jumlah_tanggungan > 2: 3 (246/22)
jumlah_tanggungan <= 2:
:...durasi_pinjaman_bulan <= 36: 1 (294/86)
durasi_pinjaman_bulan > 36:
:...jumlah_tanggungan <= 0: 2 (41/8)
jumlah_tanggungan > 0: 3 (67/4)
Evaluation on training data (900 cases):
Decision Tree
----------------
Size Errors
6 205(22.8%) <<
(a) (b) (c) (d) (e) <-classified as
---- ---- ---- ---- ----
208 2 5 6 6 (a): class 1
86 33 21 6 13 (b): class 2
4 287 (c): class 3
2 82 36 (d): class 4
18 85 (e): class 5
Attribute usage:
100.00% jumlah_tanggungan
72.67% durasi_pinjaman_bulan
Time: 0.0 secs
Model di atas adalah bentuk dari output decision tree yang telah dipermudah dengan algoritma C5.0 dalam R. fungsi C5.0(data training, target variabel)
C5.0 adalah nama algoritma untuk decision tree. Banyak algoritma lain seperti random forest, CART, CHAID, MARS, dll. Namun C5.0 adalah algoritma yang sangat populer akan kecepatan dan akurasinya.
Algortitma ini termasuk dalam kategori klasifikator, yang bertujuan untuk mengkategorikan sesuatu (Berdasar data training, dan variabel kategorik target).
Setelah mengetahui bentuk dari decision tree menggunakan dua variabel yang kita pilih secara abritrari, sekarang tujuan kita adalah benar-benar mengeksplorasi data untuk menemukan variabel yang tepat untuk estimasi menggunakan decision tree.
Kembali pada risk_data, sekarang kita bisa tahu bahwa, sama seperti model lainnya, decision tree membutuhkan dua jenis variabel : variabel eksplanator dan respon. Untuk kasus ini (decision tree), kedua variabel itu disebut juga sebagai class variable (variabel yang menjadi target klasifikasi), dan input variables (variabel yang menjadi data training). Untuk risk_data, class variable adalah risk_rating, dan lainnya termasuk input variables.
Algoritma C5.0 mengharuskan class variable selalu berupa factor.
dalam data untuk membuat decision tree, tidak semua input variable perlu digunakan, satu variabel yang perlu dibuang adalah variabel yang berkaitan sangat kuat dan ekuivalen dengan variabel target. Dalam risk_data, variabel itu adalah ‘rata_rata_overdue’. Hal ini karena value dari average overdue sendiri menjadi klasifikator untuk labeling class variable ‘risk_rating’. Variabel seperti ini kita sebut sebagai feature selection
Yang menarik pada algoritma C5.0 adalah kemampuannya untuk membuang variabel yang tidak relevan, jadi meski nanti kita ada satu kesalahan, C5.0 akan membuang variabel tersebut secara otomatis.
Untuk proses pembentukan model machine learning dan melihat akurasinya, kita perlu membagi data set menjadi 2 (pada tulisan kita sebelumnya dataset dibagi 3, dengan tambahan query set; tapi pada dasarnya partisi data ini sesuai dengan kebutuhan saja)
Data yang dipergunakan untuk training dan test saat ini berasal dari datafeed. Kita akan menggunakan 800 obs sebagai training dan 100 obs sebagai testing.
Langkah pertama, kita perlu menyusun index untuk training set.
Catatan samping : Saat kita menggunakan rnorm() untuk memproduksi nilai random di R, yang kita dapatkan sebenarnya adalah pseudo random number. Angka-angka itu tidak benar-benar random karena di generate melalui sebuah algoritma yang membutuhkan acuan atau parameter. Artinya, saat kita bisa mengatur parameter tersebut, kita bisa mereproduksi pseudo number yang sama. Itulah guna dari set.seed().
Bahasa mudahnya, saat R memproduksi random number, R melibatkan generator dan seed, di mana secara default, seed = NULL, dan nilainya akan diambil oleh generator berdasarkan sistem jam. Nah, dengan mensetting seed = “any integer”, dan me restatenya setiap kali kita memanggil objek random, nilai yang dihasilkan akan tetap sama
# random number
rnorm(10)
[1] 0.01635036 0.20714175 0.72004229 1.07751375 0.64244461 0.58729807 1.52729825
[8] -0.54100001 0.09143561 0.91157439
# random number with seed
set.seed(1)
random_x <- rnorm(10)
# Call it again with set.seed
set.seed(1)
random_x
[1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291
[8] 0.7383247 0.5757814 -0.3053884
# Call it again without set.seed
random_x
[1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291
[8] 0.7383247 0.5757814 -0.3053884
rnorm(10)
[1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078 -0.8204684 0.4874291
[8] 0.7383247 0.5757814 -0.3053884
Oke, kembali lagi pada persiapan training set, kita bisa melakukannya dengan memanfaatkan set.seed ini
# menyiapkan indeks
set.seed(2)
indeks_training_set <- sample(900,800)
# mengambil sample data secara random
input_training_set <- datafeed[indeks_training_set,]
class_training_set <- as.factor(risk_data[indeks_training_set,]$risk_rating)
test_set <- datafeed[-indeks_training_set,]
Seluruh data sudah siap; class variable sudah dikonvert menjadi factor, input variabel sudah dipisahkan, dan sample sudah diambil secara acak. Sekarang, kita bisa menerapkan model decision tree menggunakan algoritma C5.0()
ingat :
C5.0(input_variable, class_variable)
Jadi :
risk_model <- C5.0(input_training_set,class_training_set)
# Hasil model
summary(risk_model)
Call:
C5.0.default(x = input_training_set, y = class_training_set)
C5.0 [Release 2.07 GPL Edition] Sun Jan 23 18:58:47 2022
-------------------------------
Class specified by attribute `outcome'
Read 800 cases (3 attributes) from undefined.data
Decision tree:
jumlah_tanggungan > 4:
:...durasi_pinjaman_bulan <= 24: 4 (92/26)
: durasi_pinjaman_bulan > 24: 5 (127/51)
jumlah_tanggungan <= 4:
:...jumlah_tanggungan > 2: 3 (223/21)
jumlah_tanggungan <= 2:
:...durasi_pinjaman_bulan <= 36: 1 (261/76)
durasi_pinjaman_bulan > 36:
:...jumlah_tanggungan <= 0: 2 (36/8)
jumlah_tanggungan > 0: 3 (61/4)
Evaluation on training data (800 cases):
Decision Tree
----------------
Size Errors
6 186(23.3%) <<
(a) (b) (c) (d) (e) <-classified as
---- ---- ---- ---- ----
185 2 5 5 6 (a): class 1
76 28 20 5 12 (b): class 2
4 259 (c): class 3
2 66 33 (d): class 4
16 76 (e): class 5
Attribute usage:
100.00% jumlah_tanggungan
72.13% durasi_pinjaman_bulan
Time: 0.0 secs
Untuk memudahkan user dalam melihat hasilnya, kita bisa membuat visualisasi dari hasil decision tree di atas. Caranya sangat sederhana, dan memungkinkan untuk elaborasi. Tapi untuk saat ini, cukup gunakan plot() sudah memadai.
plot(risk_model)
Seperti yang telah kita pelajari, C5.0 decistion tree memerlukan dua variabel; input variable dan class variable yang menjadi target klasifikasi. Pada output model, di bagian awal, kita bisa melihat tulisan berikut :
Class specified by attribute `outcome'
Ini artinya, class variable kita sekarang diidentifikasikan dengan nama ‘outcome’.
Jika kita ingin mengubah label class tersebut, kita perlu menambahkan parameter ‘control’ dengan input berupa C5.0Control
control = C5.0Control(label = "risk_rating")
risk_model <- C5.0(input_training_set,class_training_set, control = C5.0Control(label = "Risk Rating"))
summary(risk_model)
Call:
C5.0.default(x = input_training_set, y = class_training_set, control
= C5.0Control(label = "Risk Rating"))
C5.0 [Release 2.07 GPL Edition] Sun Jan 23 19:13:53 2022
-------------------------------
Class specified by attribute `Risk Rating'
Read 800 cases (3 attributes) from undefined.data
Decision tree:
jumlah_tanggungan > 4:
:...durasi_pinjaman_bulan <= 24: 4 (92/26)
: durasi_pinjaman_bulan > 24: 5 (127/51)
jumlah_tanggungan <= 4:
:...jumlah_tanggungan > 2: 3 (223/21)
jumlah_tanggungan <= 2:
:...durasi_pinjaman_bulan <= 36: 1 (261/76)
durasi_pinjaman_bulan > 36:
:...jumlah_tanggungan <= 0: 2 (36/8)
jumlah_tanggungan > 0: 3 (61/4)
Evaluation on training data (800 cases):
Decision Tree
----------------
Size Errors
6 186(23.3%) <<
(a) (b) (c) (d) (e) <-classified as
---- ---- ---- ---- ----
185 2 5 5 6 (a): class 1
76 28 20 5 12 (b): class 2
4 259 (c): class 3
2 66 33 (d): class 4
16 76 (e): class 5
Attribute usage:
100.00% jumlah_tanggungan
72.13% durasi_pinjaman_bulan
Time: 0.0 secs
Bagian berikutnya, pada :
Read 800 cases (3 attributes) from undefined.data
Model membaca 800 cases karena itulah jumlah sample data yang kita gunakan untuk training. Sedangkan untuk 3 attributes di sini yang dimaksud adalah : * 2 input_training_set (jumlah_tanggungan, dan durasi_pinjaman_bulan) * 1 class_training_set (risk_rating)
Bagian inti dari decision tree estimasi:
Decision tree:
jumlah_tanggungan > 4:
:...durasi_pinjaman_bulan <= 24: 4 (92/26)
: durasi_pinjaman_bulan > 24: 5 (127/51)
jumlah_tanggungan <= 4:
:...jumlah_tanggungan > 2: 3 (223/21)
jumlah_tanggungan <= 2:
:...durasi_pinjaman_bulan <= 36: 1 (261/76)
durasi_pinjaman_bulan > 36:
:...jumlah_tanggungan <= 0: 2 (36/8)
jumlah_tanggungan > 0: 3 (61/4)
kata-kata seperti “jumlah_tanggungan”, “durasi..”, dan seterusnya, adalah node dan kondisi splitnya. Connector tree digambarkan dengan awalan “:…”. Angka-angka yang berada di sebelah titik dua masing-masing node adalah leaf node atau klasifikasinya. Dua angka di dalam tanda kurung () adalah statistik error dalam bentuk (jumlah_klasifikasi/jumlah_error), Kita bisa melihat kualitas model decision tree dari rasio error dan jumlah klasifikasinya.
errortree <- c(26/92,
51/127,
21/223,
76/261,
8/36,
4/61)
mean(errortree)
[1] 0.2262229
Sekedar tambahan, rata-rata error pada model tree ini sebesar 22.62%. Kita akan bahas ini lebih lanjut di bagian berikutnya.
Sekarang, kita fokus pada bagian evaluasi model berikut
Evaluation on training data (800 cases):
Decision Tree
----------------
Size Errors
6 186(23.3%)
800 cases artinya ada 800 observasi yang kita evaluasi pada model ini (jumlah sample) size = 6 artinya ada 6 leaf node yang menyimpan klasifikasi model error artinya jumlah kesalahan klasifikasi dari seluruh sample; di model ini, ada 186 error yang artinya 23.3% dari total sample.
Bagian selanjutnya : confusion matrix
(a) (b) (c) (d) (e) <-classified as
---- ---- ---- ---- ----
185 2 5 5 6 (a): class 1
76 28 20 5 12 (b): class 2
4 259 (c): class 3
2 66 33 (d): class 4
16 76 (e): class 5
Confusion Matrix atau error matrix adalah matrix berdimensi sama yang berisi hasil klasifikasi model dibandingkan dengan klasifikasi pada data sebenarnya. Konsepnya sama seperti y_data vs y_model.
Header kolom dan row adalah representasi dari value class variable. Kenapa 5? karena klasifikasi pada data ini memiliki 5 kategori klasifikasi (1-5). Secara detail, matrix di atas bisa dijelaskan sebagai berikut : * header kolom menunjukkan nilai class_rating prediksi * header baris menunjukkan nilai class_rating data asli
Cara membacanya seperti ini : pada nilai 185(1x1), angka itu menunjukkan bahwa ada 185 obs yang dengan diklasifikasikan dalam class1, di sebelahnya (1x2) angka 2 menunjukkan bahwa model salah memprediksi 2 observasi sebagai klasifikasi kedua, meskipun pada data riil obs tersebut masuk dalam class 1.
Bagian berikutnya adalah :
Attribute usage:
100.00% jumlah_tanggungan
72.13% durasi_pinjaman_bulan
Ini adalah daftar variabel yang digunakan oleh model decision tree. Output ini menceritakan tingkat signifikasi tiap variabel bagi model. Di sini jumlah_tanggungan mencapai usage 100% yang menjadi alasan kenapa variabel ini menjadi root node dalam model.
Pada bagian sebelumnya, kita sudah melakukan evaluasi model decision tree menggunakan data training. Sekarang, kita perlu melakukan evaluasi akurasi model menggunakan data training(test_set)
Pertama, kita buat nilai prediksi menggunakan risk_model dan test_set. Untuk ini, kita bisa menggunakan fungsi yang sudah include dalam package C5.0, yaitu ‘predict()’.
predict(model,testing_dataframe)
Karena tujuan kita adalah untuk melakukan uji akurasi model, kita perlu menyiapkan objek untuk menyimpan hasil prediksi ini.
hasil_prediksi <- predict(risk_model,test_set)
hasil_prediksi
[1] 3 1 4 1 1 5 4 1 4 3 2 1 5 1 5 5 5 1 1 1 3 4 3 1 3 3 1 5 1 1 3 3 3 4 1 5 4 1 1 1 3
[42] 3 4 1 3 1 1 1 1 3 3 4 1 3 1 4 4 3 3 1 3 1 1 1 5 2 5 5 5 4 1 2 4 3 1 3 2 5 5 3 3 2
[83] 4 3 3 3 4 1 4 4 4 3 1 4 3 3 4 3 4 1
Levels: 1 2 3 4 5
Tujuan kita di sini adalah menggabungkan data hasil prediksi di atas dengan dataframe test_set()
head(test_set)
Gabungkan nilai risk_rating dari risk_data dan hasil_prediksi
Setelah terbangun dataframe seperti ini, kita buat pembanding seperti confusion matrix. Caranya, pastikan kita sudah load library reshape2, lalu gunakan dcast yang berfungsi untuk mengonvert bentuk data.
dcast(kolom~baris, data)
library(reshape2)
dcast(hasil_prediksi~risk_rating, data = test_set)
Using hasil_prediksi as value column: use value.var to override.
Aggregation function missing: defaulting to length
Pada model ini, kita cukup mengkhawatirkan kualitas model untuk mengestimasi kategori risk ke dua.
Setelah membuat confusion matrix, kita tinggal menghitung berapa jumlah klasifikasi yang benar (risk_rating = hasil_prediksi)
test_set %>% filter(risk_rating == hasil_prediksi) %>% nrow()
[1] 81
Ini artinya, ada model mampu memberikan 81% klasifikasi yang tepat dengan tingkat error 19%.
Setelah pembangunan, pengujian,dan kita akhirnya memiliki model yang cukup menyakinkan untuk digunakan. Sekarang, mari kita berandai-andai, ada sebuah aplikasi baru yang masuk. Kita akan simulasikan penggunaan model kita dengan input data yang benar-benar baru ini. Beberapa hal yang harus diingat : data baru harus dibentuk jadi data frame dengan nama variabel inputan yang benar-benar sama, yaitu jumlah_tanggungan & durasi_pinjaman_bulan
new_app <- data.frame(jumlah_tanggungan = 6, durasi_pinjaman_bulan = 12)
new_app
Data new_app ini akan diprediksi risk_rating nya menggunakan fungsi predict().
predict(risk_model, new_app)
[1] 4
Levels: 1 2 3 4 5
Inilah contoh datanya. Sekarang, kita berandai-andai lagi; apa yang terjadi pada model kita jika seandainya kita memasukan value yang tidak pernah ada dalam data training?
contoh : kita buat durasi_pinjaman_bulan menjadi 64
new_app <- data.frame(jumlah_tanggungan = 6, durasi_pinjaman_bulan = 64)
predict(risk_model, new_app)
[1] 5
Levels: 1 2 3 4 5
# Coba kita turunkan jumlah tanggungannya
new_app <- data.frame(jumlah_tanggungan = 2,durasi_pinjaman_bulan = 64)
predict(risk_model, new_app)
[1] 3
Levels: 1 2 3 4 5
Sebenarnya tidak banyak berpengaruh, karena model ini berakar dari nilai jumlah_tanggungan. Jadi, selama model masih bisa melogika variabel jumlah_tanggungan, model akan bisa memprediksi risk_rating.
Beberapa catatan :
Sebenarnya, untuk melakukan uji kualitas model, kita menggunakan ROC curve. Tapi kita akan menambah pembahasan ini lain waktu.
Source : Module “Data Science in Finance : Credit Risk Analysis” by DQLab,2022