Pemanfaatan data analitik untuk pengembangan kasus kredit dan perbankan telah meningkatkan serta merevolusi pengambilan keputusan oleh departemen kredit dalam meningkatkan efisiensi pengambilan kebijakan.
Pemanfaatan bidang analitik telah digunakan selama bertahun-tahun. Namun, karena sistem yang dimiliki oleh perbankan itu sendiri bersifat dinamis, pengumpulan, pemrosesan dan analisa terhadap data yang digunakan sebagian besar bersifat manual. Pendekatan yang bersifat manual ini memberikan kesulitan tersendiri untuk tim. Untuk mengatasi permasalahan ini, dibutuhkan suatu metode yang bersifat cepat dan dinamis dan mampu memanfaatkan informasi yang dimiliki secara optimal. Metode Machine Learning menjadi salah satu jawaban untuk mengatasi problem tersebut.
Application vs Behavior Scorecard
Terdapat 2 jenis scorecard yang biasa dikembangkan oleh suatu institusi perbankan maupun kredit:
Application Scoring dalam konteks kredit merujuk pada metode evaluasi penentuan keputusan pengajuan aplikasi terhadap individu atau peminjam. Skor aplikasi (Application score) digunakan oleh lembaga keuangan sebagai acuan dasar pemberian kredit berdasarkan kriteria yang ada.Skor ini dapat digunakan sebagai awal penetapan pemberian pinjamann.
Faktor-faktor yang dapat dipertimbangkan dalam application scoring melibatkan pengamatan atas kebiasaan sehari-hari. Beberapa contoh faktor yang dapat diperhitungkan dalam behavior scoring meliputi:
Berikut beberapa library yang digunakan selama pemodelan klasifikasi dan pembentukan scorecard
# Memuat Semua Package yang Diperlukan:
library(tidyverse)
library(UBL) #For SMOTE
library(dplyr) # Wrangling data
library(inspectdf) # add on wrangling data
library(caret) # classification & regression training
library(scorecard) # credit risk scorecard
library(rsample) # resampling data, Train - Test
library(gtools) # programming tools
library(readxl)
library(GGally) # plot heatmap correlation
library(knitr) # reporting in R
library(scales) # manipulasi skala data untuk visualisasi
library(car) # check multicollinearityIstilah scorecard atau ‘predictive scorecard’ mengacu pada sebuah model kredit kuantitatif yang digunakan untuk menilai kelayakan dan kemampuan bayar calon pemilik kartu kredit berdasarkan credit score yang dihasilkan.
Denggan menggunakan data yang berasal dari: https://www.kaggle.com/datasets/rohit265/credit-card-eligibility-data-determining-factors dengan judul ‘Description of the Credit Card Eligibility Data: Determining Factors’
#read data
dataset <- read.csv("data_input/dataset.csv")
datasetDataset memiliki 20 kolom dan 9,709 baris data dengan penjelasan sebagai berikut:
id = id calon pemilik kartuGender = jenis kelamin
Own_car = Memiliki kendaraan atau tidak. 0 = Tidak, 1 = IyaOwn_property = Memiliki unit properti sendiri atau tidak. 0 = Tidak, 1 = IyaWork_phone = Kepemilikan telepon kantor. 0 = Tidak, 1 = IyaEmail = Kepemilikan Email. 0 = Tidak, 1 = IyaUnemployed = Status pekerjaan. 0 = Tidak memiliki kerja, 1 = Memiliki kerjaNum_children = Jumlah anakNum_family = Jumlah anggota keluargaAccount_length = Jumlah kepemilikan akun bank atau institusi keuangan lainTotal_income = Jumlah pendapatanAge = UmurYears_employed = Lama bekerjaIncome_type = Jenis pendapatanEducation_type = Jenjang pendidikanFamily_status = Status pernikahanHousing_type = Jenis tempat tinggalOccupation_type = Jenis pekerjaanTarget = Variabel target untuk klasifikasi, apakah individu masuk kriteria untuk memiliki kartu kredit atau tidak. 0 = Tidak, 1 = Iyasummary(dataset)## ID Gender Own_car Own_property
## Min. :5008804 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:5036955 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000
## Median :5069449 Median :0.0000 Median :0.0000 Median :1.0000
## Mean :5076105 Mean :0.3487 Mean :0.3677 Mean :0.6715
## 3rd Qu.:5112986 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :5150479 Max. :1.0000 Max. :1.0000 Max. :1.0000
## Work_phone Phone Email Unemployed
## Min. :0.0000 Min. :0.0000 Min. :0.00000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.00000 1st Qu.:0.0000
## Median :0.0000 Median :0.0000 Median :0.00000 Median :0.0000
## Mean :0.2174 Mean :0.2877 Mean :0.08755 Mean :0.1747
## 3rd Qu.:0.0000 3rd Qu.:1.0000 3rd Qu.:0.00000 3rd Qu.:0.0000
## Max. :1.0000 Max. :1.0000 Max. :1.00000 Max. :1.0000
## Num_children Num_family Account_length Total_income
## Min. : 0.0000 Min. : 1.000 Min. : 0.00 Min. : 27000
## 1st Qu.: 0.0000 1st Qu.: 2.000 1st Qu.:13.00 1st Qu.: 112500
## Median : 0.0000 Median : 2.000 Median :26.00 Median : 157500
## Mean : 0.4228 Mean : 2.183 Mean :27.27 Mean : 181228
## 3rd Qu.: 1.0000 3rd Qu.: 3.000 3rd Qu.:41.00 3rd Qu.: 225000
## Max. :19.0000 Max. :20.000 Max. :60.00 Max. :1575000
## Age Years_employed Income_type Education_type
## Min. :20.50 Min. : 0.0000 Length:9709 Length:9709
## 1st Qu.:34.06 1st Qu.: 0.9282 Class :character Class :character
## Median :42.74 Median : 3.7619 Mode :character Mode :character
## Mean :43.78 Mean : 5.6647
## 3rd Qu.:53.57 3rd Qu.: 8.2000
## Max. :68.86 Max. :43.0207
## Family_status Housing_type Occupation_type Target
## Length:9709 Length:9709 Length:9709 Min. :0.0000
## Class :character Class :character Class :character 1st Qu.:0.0000
## Mode :character Mode :character Mode :character Median :0.0000
## Mean :0.1321
## 3rd Qu.:0.0000
## Max. :1.0000
glimpse(dataset)## Rows: 9,709
## Columns: 20
## $ ID <int> 5008804, 5008806, 5008808, 5008812, 5008815, 5008819, …
## $ Gender <int> 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, …
## $ Own_car <int> 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, …
## $ Own_property <int> 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ Work_phone <int> 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ Phone <int> 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, …
## $ Email <int> 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, …
## $ Unemployed <int> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, …
## $ Num_children <int> 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 0, 2, 1, 0, 2, 0, 0, …
## $ Num_family <int> 2, 2, 1, 1, 2, 2, 2, 2, 2, 5, 3, 2, 4, 3, 2, 4, 1, 1, …
## $ Account_length <int> 15, 29, 4, 20, 5, 17, 25, 31, 44, 24, 39, 43, 39, 24, …
## $ Total_income <dbl> 427500, 112500, 270000, 283500, 270000, 135000, 130500…
## $ Age <dbl> 32.86857, 58.79382, 52.32140, 61.50434, 46.19397, 48.6…
## $ Years_employed <dbl> 12.435574, 3.104787, 8.353354, 0.000000, 2.105450, 3.2…
## $ Income_type <chr> "Working", "Working", "Commercial associate", "Pension…
## $ Education_type <chr> "Higher education", "Secondary / secondary special", "…
## $ Family_status <chr> "Civil marriage", "Married", "Single / not married", "…
## $ Housing_type <chr> "Rented apartment", "House / apartment", "House / apar…
## $ Occupation_type <chr> "Other", "Security staff", "Sales staff", "Other", "Ac…
## $ Target <int> 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, …
Dari pengecekan dengan fungsi Summary dan Glimpse dilakukan langkah berikut:
Tidak menggunakan kolom ID
Mengubah kolom Income_type, Education_type, Family_status, Housing_type, Occupation_type menjadi angka
Membulatkan umur dan tahun kerja ke atas
Mengubah kesemua jenis kolom kecuali Account_length, Total_income, Age, Years_employed menjadi kategorikal
dataset_clean <- dataset %>%
#Langkah 1
select(-ID) %>%
#Langkah 2 dan 3
mutate(across(c(Income_type, Education_type, Family_status, Housing_type, Occupation_type), ~dense_rank(.)),
Age = round(Age),
Years_employed = round(Years_employed)) %>%
#Langkah 4
mutate_at(vars(Gender, Own_car, Own_property, Work_phone, Phone, Email, Unemployed, Num_children, Num_family, Income_type, Education_type, Family_status, Housing_type, Occupation_type, Target),as.factor)
dataset_cleanMelakukan pemeriksaan distribusi data
Library scorecard menyediakan suatu fungsi describe() dimana menyediakan statistik deskriptif untuk analisis data eksploratif. Periksa proporsi kelas Target
describe(dataset_clean)Tujuannya untuk:
Jika distribusi kelas target tidak seimbang, di mana satu kelas memiliki frekuensi yang jauh lebih tinggi atau lebih rendah dibandingkan kelas lainnya, maka model dapat menjadi bias.
Model yang dilatih pada dataset tidak seimbang dapat memiliki kecenderungan untuk memprediksi dengan benar kelas mayoritas dan mengabaikan kelas minoritas.
❓ Mari kita cek data application yang kita miliki. Berapa banyak applicant dengan status Yes dan No?
prop.table(table(dataset_clean$Target))##
## 0 1
## 0.8678546 0.1321454
Data tidak seimbang 86:13 dimana yang diharapkan setidaknya berada di perbandingan 60:40 sehingga harus diseimbangkan dengan menggunakan metode SMOTE.
Dikutip dari https://rpubs.com/VicNP/UBL-SmoteClassif, berikut penjelasan penggunaan fungsi SMOTE:
#Gunaka library(UBL)
dataset_smote <- SmoteClassif(form = Target ~ .,
dat = dataset_clean,
C.perc = "balance",
dist = "HVDM")Kita periksa kembali balance datanya
prop.table(table(dataset_smote$Target))##
## 0 1
## 0.5000515 0.4999485
Data sudah menjadi balance
Cross Validation adalah metode yang digunakan untuk mengetahui seberapa baik performa model kita memprediksi terhadap data baru.
Lalu, bagaimana cara mengetahui apakah model yang dibuat telah baik dalam memprediksi data baru? Di sinilah dilakukan Train-test splitting. Data dibagi menjadi 2 kelompok, yaitu data train dan test.
train: Data yang model gunakan untuk training.test/validation: Data untuk evaluasi model (Untuk melihat seberapa baik model memprediksi terhadap data yang tidak digunakan untuk training)Fungsi initial_split() dari paket rsample memiliki beberapa parameter:
data = data frame awalprop = proporsi dari data yang akan digunakan sebagai data trainSelanjutnya, fungsi training() and testing() dilakukan untuk mengekstrak data train dan test dari hasil split.
#kembalikan kolom Target dari Faktor ke Numerical
#Factor levels in R are stored as integers starting from 1.
#So, if your factor levels are "0" and "1", the underlying integer codes for these levels would be 1 and 2, respectively.
#This is why applying as.numeric() directly to a factor results in 1 and 2 instead of 0 and 1.
#To convert the factor to numeric values correctly, we should first convert the factor to a character and then to numeric.
dataset_smote2 <- dataset_smote %>%
mutate(Target = as.numeric(as.character(Target)))
RNGkind(sample.kind= "Rounding")
set.seed(123) # mengunci kerandoman data
# membuat binary split data menjadi set data training dan testing dengan proporsi 80:20
splitter <- initial_split(data = dataset_smote2,
prop = 0.8) # data train
# splitting
train <- training(splitter)
test <- testing(splitter)Wajib! Mengecek proporsi kelas target yang ada pada data TRAIN. Karena harapannya model belajar sama (adil) untuk tipe kelas target. Sehingga tidak ada kelas target yang lebih dominan menghindari adanya missclassification
prop.table(table(train$Target))##
## 0 1
## 0.5008371 0.4991629
Initial Characteristic Analysis merupakan langkah awal dalam mengidentifikasi dan menganalisis karakteristik atau variabel yang potensial untuk dimasukkan ke dalam model application scoring. Tujuan utama dari langkah ini adalah untuk membuat kategorisasi variabel dan memahami hubungan antara variabel-variabel yang tersedia dengan perilaku pemberian kredit yang akan diprediksi oleh skor kredit.
Tahapan ini sering disebut sebagai tahapan EDA pada pembuatan scorecard.
Pembentukan WOE bertujuan melakukan binning / kategorisasi seluruh variabel prediktor yang ada pada data, kemudian menghitung kekuatan masing-masing hasil kategori dalam memisahkan kelas positif dan kelas negatif.
Hal ini penting karena:
📐 Formula WOE:
\[ log(\frac{Distr_{Good}}{Distr_{Bad}}) \]
Keterangan:
🛑 Important Points:
Nilai WoE negatif menunjukkan bahwa banyak sebaran kelas negatif pada kelompok tersebut. Begitupula sebaliknya.
📌 Cara membuat binning dan menghitung WOE:
Gunakan fungsi woebin(), dengan parameter:
dt : data frame trainy : nama variabel y pada datapositive: kelas positive (applicant Good)# your code here
binning <- woebin(dt = train,
y = 'Target',
positive = 1) #Yes = 1, No = 0## ℹ Creating woe binning ...
## ✔ Binning on 7765 rows and 19 columns in 00:00:03
binning## $Gender
## variable bin count count_distr neg pos posprob woe bin_iv
## 1: Gender 0 5007 0.6448165 2539 2468 0.4929099 -0.02501384 0.0004034270
## 2: Gender 1 2758 0.3551835 1350 1408 0.5105149 0.04541403 0.0007324445
## total_iv breaks is_special_values
## 1: 0.001135871 0 FALSE
## 2: 0.001135871 1 FALSE
##
## $Own_car
## variable bin count count_distr neg pos posprob woe bin_iv
## 1: Own_car 0 4961 0.6388925 2449 2512 0.5063495 0.02874783 0.0005279812
## 2: Own_car 1 2804 0.3611075 1440 1364 0.4864479 -0.05087319 0.0009343345
## total_iv breaks is_special_values
## 1: 0.001462316 0 FALSE
## 2: 0.001462316 1 FALSE
##
## $Own_property
## variable bin count count_distr neg pos posprob woe
## 1: Own_property 0 2658 0.3423052 1257 1401 0.5270880 0.11180670
## 2: Own_property 1 5107 0.6576948 2632 2475 0.4846289 -0.05815526
## bin_iv total_iv breaks is_special_values
## 1: 0.004275015 0.006498627 0 FALSE
## 2: 0.002223611 0.006498627 1 FALSE
##
## $Work_phone
## variable bin count count_distr neg pos posprob woe
## 1: Work_phone 0 6096 0.7850612 3048 3048 0.5000000 0.003348361
## 2: Work_phone 1 1669 0.2149388 841 828 0.4961055 -0.012230144
## bin_iv total_iv breaks is_special_values
## 1: 8.801747e-06 4.09508e-05 0 FALSE
## 2: 3.214905e-05 4.09508e-05 1 FALSE
##
## $Phone
## variable bin count count_distr neg pos posprob woe bin_iv
## 1: Phone 0 5564 0.7165486 2758 2806 0.5043134 0.02060256 0.0003041447
## 2: Phone 1 2201 0.2834514 1131 1070 0.4861427 -0.05209519 0.0007690537
## total_iv breaks is_special_values
## 1: 0.001073198 0 FALSE
## 2: 0.001073198 1 FALSE
##
## $Email
## variable bin count count_distr neg pos posprob woe bin_iv
## 1: Email 0 7073 0.91088216 3551 3522 0.4979500 -0.004851883 2.144273e-05
## 2: Email 1 692 0.08911784 338 354 0.5115607 0.049599379 2.192028e-04
## total_iv breaks is_special_values
## 1: 0.0002406455 0 FALSE
## 2: 0.0002406455 1 FALSE
##
## $Unemployed
## variable bin count count_distr neg pos posprob woe
## 1: Unemployed 0 6483 0.8349002 3192 3291 0.5076354 0.03389215
## 2: Unemployed 1 1282 0.1650998 697 585 0.4563183 -0.17182520
## bin_iv total_iv breaks is_special_values
## 1: 0.0009589668 0.005820702 0 FALSE
## 2: 0.0048617354 0.005820702 1 FALSE
##
## $Num_children
## variable bin count count_distr neg pos posprob
## 1: Num_children 0 5356 0.6897618 2740 2616 0.4884242
## 2: Num_children 1 1543 0.1987122 742 801 0.5191186
## 3: Num_children 2%,%3%,%4%,%5%,%7%,%14 866 0.1115261 407 459 0.5300231
## woe bin_iv total_iv breaks is_special_values
## 1: -0.04296313 0.001272941 0.004241053 0 FALSE
## 2: 0.07986007 0.001266724 0.004241053 1 FALSE
## 3: 0.12358539 0.001701388 0.004241053 2%,%3%,%4%,%5%,%7%,%14 FALSE
##
## $Num_family
## variable bin count count_distr neg pos posprob
## 1: Num_family 1 1521 0.1958789 764 757 0.4976989
## 2: Num_family 2 4088 0.5264649 2091 1997 0.4885029
## 3: Num_family 3 1334 0.1717965 652 682 0.5112444
## 4: Num_family 4%,%5%,%6%,%7%,%9%,%15 822 0.1058596 382 440 0.5352798
## woe bin_iv total_iv breaks
## 1: -0.005856175 6.717573e-06 0.003578358 1
## 2: -0.042648005 9.573826e-04 0.003578358 2
## 3: 0.048333457 4.012759e-04 0.003578358 3
## 4: 0.144702479 2.212982e-03 0.003578358 4%,%5%,%6%,%7%,%9%,%15
## is_special_values
## 1: FALSE
## 2: FALSE
## 3: FALSE
## 4: FALSE
##
## $Account_length
## variable bin count count_distr neg pos posprob woe
## 1: Account_length [-Inf,5) 403 0.05189955 323 80 0.1985112 -1.392277327
## 2: Account_length [5,9) 545 0.07018674 319 226 0.4146789 -0.341307742
## 3: Account_length [9,38) 4265 0.54925950 2127 2138 0.5012896 0.008506638
## 4: Account_length [38, Inf) 2552 0.32865422 1120 1432 0.5611285 0.249091744
## bin_iv total_iv breaks is_special_values
## 1: 8.689890e-02 0.1153253 5 FALSE
## 2: 8.095374e-03 0.1153253 9 FALSE
## 3: 3.974604e-05 0.1153253 38 FALSE
## 4: 2.029133e-02 0.1153253 Inf FALSE
##
## $Total_income
## variable bin count count_distr neg pos posprob woe
## 1: Total_income [-Inf,100000) 1193 0.1536381 653 540 0.4526404 -0.1866596
## 2: Total_income [100000,130000) 1157 0.1490019 541 616 0.5324114 0.1331760
## 3: Total_income [130000,140000) 905 0.1165486 480 425 0.4696133 -0.1183486
## 4: Total_income [140000,180000) 1193 0.1536381 508 685 0.5741827 0.3022858
## 5: Total_income [180000,210000) 1129 0.1453960 643 486 0.4304694 -0.2765877
## 6: Total_income [210000,270000) 1059 0.1363812 461 598 0.5646837 0.2635411
## 7: Total_income [270000, Inf) 1129 0.1453960 603 526 0.4658990 -0.1332676
## bin_iv total_iv breaks is_special_values
## 1: 0.005336711 0.04659064 100000 FALSE
## 2: 0.002639072 0.04659064 130000 FALSE
## 3: 0.001630361 0.04659064 140000 FALSE
## 4: 0.013936506 0.04659064 180000 FALSE
## 5: 0.011049994 0.04659064 210000 FALSE
## 6: 0.009419826 0.04659064 270000 FALSE
## 7: 0.002578169 0.04659064 Inf FALSE
##
## $Age
## variable bin count count_distr neg pos posprob woe
## 1: Age [-Inf,35) 2212 0.28486800 958 1254 0.5669078 0.27259430
## 2: Age [35,37) 416 0.05357373 241 175 0.4206731 -0.31666260
## 3: Age [37,51) 2776 0.35750161 1411 1365 0.4917147 -0.02979588
## 4: Age [51,54) 574 0.07392144 260 314 0.5470383 0.19205972
## 5: Age [54, Inf) 1787 0.23013522 1019 768 0.4297706 -0.27943894
## bin_iv total_iv breaks is_special_values
## 1: 0.0210425337 0.04725517 35 FALSE
## 2: 0.0053262710 0.04725517 37 FALSE
## 3: 0.0003173566 0.04725517 51 FALSE
## 4: 0.0027188202 0.04725517 54 FALSE
## 5: 0.0178501878 0.04725517 Inf FALSE
##
## $Years_employed
## variable bin count count_distr neg pos posprob woe
## 1: Years_employed [-Inf,0.5) 1481 0.19072762 810 671 0.4530722 -0.18491675
## 2: Years_employed [0.5,1.5) 773 0.09954926 394 379 0.4902975 -0.03546634
## 3: Years_employed [1.5,6.5) 3069 0.39523503 1387 1682 0.5480613 0.19618878
## 4: Years_employed [6.5,10.5) 1231 0.15853187 634 597 0.4849716 -0.05678348
## 5: Years_employed [10.5, Inf) 1211 0.15595621 664 547 0.4516928 -0.19048499
## bin_iv total_iv breaks is_special_values
## 1: 0.0065022551 0.0279458 0.5 FALSE
## 2: 0.0001252023 0.0279458 1.5 FALSE
## 3: 0.0151664866 0.0279458 6.5 FALSE
## 4: 0.0005110028 0.0279458 10.5 FALSE
## 5: 0.0056408524 0.0279458 Inf FALSE
##
## $Income_type
## variable bin count count_distr neg pos posprob woe
## 1: Income_type 1 1873 0.24121056 915 958 0.5114789 0.04927207
## 2: Income_type 2 1333 0.17166774 697 636 0.4771193 -0.08823849
## 3: Income_type 3 549 0.07070187 297 252 0.4590164 -0.16095469
## 4: Income_type 4%,%5 4010 0.51641983 1980 2030 0.5062344 0.02828731
## bin_iv total_iv breaks is_special_values
## 1: 0.0005855016 0.004161796 1 FALSE
## 2: 0.0013356451 0.004161796 2 FALSE
## 3: 0.0018274420 0.004161796 3 FALSE
## 4: 0.0004132069 0.004161796 4%,%5 FALSE
##
## $Education_type
## variable bin count count_distr neg pos posprob woe
## 1: Education_type 1%,%2%,%3 2360 0.3039279 1136 1224 0.5186441 0.07795922
## 2: Education_type 4%,%5 5405 0.6960721 2753 2652 0.4906568 -0.03402879
## bin_iv total_iv breaks is_special_values
## 1: 0.0018463499 0.002652272 1%,%2%,%3 FALSE
## 2: 0.0008059221 0.002652272 4%,%5 FALSE
##
## $Family_status
## variable bin count count_distr neg pos posprob woe
## 1: Family_status 1 718 0.09246619 336 382 0.5320334 0.13165781
## 2: Family_status 2 5135 0.66130071 2642 2493 0.4854917 -0.05470104
## 3: Family_status 3 427 0.05499034 221 206 0.4824356 -0.06693817
## 4: Family_status 4%,%5 1485 0.19124276 690 795 0.5353535 0.14499888
## bin_iv total_iv breaks is_special_values
## 1: 0.0016006535 0.00783938 1 FALSE
## 2: 0.0019781627 0.00783938 2 FALSE
## 3: 0.0002462905 0.00783938 3 FALSE
## 4: 0.0040142732 0.00783938 4%,%5 FALSE
##
## $Housing_type
## variable bin count count_distr neg pos posprob woe
## 1: Housing_type 1%,%2 6912 0.89014810 3501 3411 0.4934896 -0.02269478
## 2: Housing_type 3%,%4%,%5 458 0.05898261 198 260 0.5676856 0.27576296
## 3: Housing_type 6 395 0.05086929 190 205 0.5189873 0.07933427
## bin_iv total_iv breaks is_special_values
## 1: 0.0004584450 0.005236624 1%,%2 FALSE
## 2: 0.0044581584 0.005236624 3%,%4%,%5 FALSE
## 3: 0.0003200209 0.005236624 6 FALSE
##
## $Occupation_type
## variable bin count count_distr neg
## 1: Occupation_type 1%,%2%,%3%,%4%,%5%,%6%,%7%,%8%,%9 3444 0.4435287 1685
## 2: Occupation_type 10%,%11%,%12 931 0.1198970 443
## 3: Occupation_type 13%,%14%,%15%,%16%,%17%,%18%,%19 3390 0.4365744 1761
## pos posprob woe bin_iv total_iv
## 1: 1759 0.5107433 0.04632826 0.0009518158 0.00457833
## 2: 488 0.5241676 0.10009400 0.0012003234 0.00457833
## 3: 1629 0.4805310 -0.07456714 0.0024261907 0.00457833
## breaks is_special_values
## 1: 1%,%2%,%3%,%4%,%5%,%6%,%7%,%8%,%9 FALSE
## 2: 10%,%11%,%12 FALSE
## 3: 13%,%14%,%15%,%16%,%17%,%18%,%19 FALSE
Output hasil woebin:
variable : nama variabelbin : hasil binning kategoricount : jumlah data pada masing-masing bincount_distr : distribusi masing-masing bin/total dataneg : banyaknya kelas negatif pada bin (not_default)pos : banyaknya kelas postif pada binposprob : pos/count masing-masing binwoe : nilai woe untuk bin tersebut.🛑 Note:
chimerge -> metode binning menggunakan analisis chi-squaredfreq -> akan menghasilkan proporsi nilai yang cenderung sama antara binningnya (hanya untuk var numerik)width -> akan menghasilkan binning yang secara rentang akan mirip antara satu dengan yang lain (hanya untuk var numerik)Mari kita pahami menggunakan variable Age!
# your code here
binning$Age💡 Insight:
Setelah kita melakukan binning pada data dalam bentuk WOE value, values di data train maupun test perlu dikonversi ke nilai WOE sesuai kategori/bins yang sudah dihitung.
Kita bisa gunakan fungsi woebin_ply() dari library scorecard, dengan parameter:
dt : dataframe yang akan ditransformasi -> data trainbins : informasi binning yang dihasilkan dari woebin# data train
train_woe <- woebin_ply(dt = train,
bins = binning)## ℹ Converting into woe values ...
## ✔ Woe transformating on 7765 rows and 18 columns in 00:00:11
train_woe# data test
test_woe <- woebin_ply(dt = test,
bins = binning)## ℹ Converting into woe values ...
## ✔ Woe transformating on 1942 rows and 18 columns in 00:00:11
Information Value digunakan untuk melihat feature importance pada data. Nilai IV yang tinggi mengindikasikan kekuatan suatu feature/variabel dalam memprediksi target.
📐 Formula IV:
\[ \sum_{i=1}^n (Distr_{Good_i} - Distr_{Bad_i}) \times ln(\frac{Distr_{Good_i}}{Distr_{Bad_i}}) \]
📌 Cara mengeluarkan nilai information value (iv) pada data:
Gunakan fungsi iv(), dengan parameter:
dt : data frame train hasil woey : nama variabel y pada datapositive: kelas positive (applicant good)#untuk mengubah tampilan exponential notation ke tampilan angka normal (0 koma sekian)
options("scipen"=100, "digits"=4)
#penggunaan fungsi iv()
iv(dt = train_woe,
y ='Target',
positive = 1)Menurut (Siddiqi, Naeem), skor IV dapat dikategorikan menjadi nilai berikut:
❓ Nilai IV dapat digunakan sebagai feature elimination kecuali:
Account_length_woe, Total_income_woe, Age_woe, Years_employed_woe dan target; variable selebihnya dapat dihilangkan.
# hasil data setelah feature elimination
train_woe_final <- train_woe %>%
select(c(Target, Account_length_woe, Age_woe, Total_income_woe, Years_employed_woe))
test_woe_final <- test_woe %>%
select(c(Target, Account_length_woe, Age_woe, Total_income_woe, Years_employed_woe))Setelah WOE binning berhasil dihasilkan dan di-apply untuk data train dan test, terkadang visualisasi dibutuhkan dalam perspektif bisnis karena lebih mudah untuk dipresentasikan.
Plot trend bertujuan untuk mengidentifikasi dan memahami pola atau trend dalam data hasil WOE/binning.
📌 Di R, untuk mengecek logical trend kita dapat gunakan fugsi woebin_plot(), dengan parameter:
bins = data frame hasil woebin# logical trend plot
plot <- woebin_plot(bins = binning)
plot## $Gender
##
## $Own_car
##
## $Own_property
##
## $Work_phone
##
## $Phone
##
## $Email
##
## $Unemployed
##
## $Num_children
##
## $Num_family
##
## $Account_length
##
## $Total_income
##
## $Age
##
## $Years_employed
##
## $Income_type
##
## $Education_type
##
## $Family_status
##
## $Housing_type
##
## $Occupation_type
💡 Insight:
Age menandakan range umur -Inf~34, memiliki positive probability yang tertinggi sebesar 55.8%. artinya pada range umur tersebut, potensi pemberian kartu kredit pada applicant dapat dilakukan lebih tinggi jika dibandingkan range umur yang lain.Logistic regression merupakan salah satu metode klasifikasi yang konsepnya hampir mirip dengan regresi linear. Hanya saja, dalam binary logistic regression tidak menghitung secara spesifik nilai prediksi target variabel, namun menghitung kemungkinan pada masing-masing kelas target.
📌 Cara membuat model Logistic Regression:
glm(target ~ prediktor, data, family = "binomial")
terdapat 3 paramater yang kita gunakan yaitu:
formula : tempat mendefinisikan target dan predictor (y~x)data : data yang digunakan untuk membuat modelfamily : gunakan “binomial” bila ingin menggunakan logistic regression pada pemodelan initrain_woe_finalmodel <- glm(formula = Target ~ .,
data = train_woe_final,
family = "binomial")
summary(model) ##
## Call:
## glm(formula = Target ~ ., family = "binomial", data = train_woe_final)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.00387 0.02334 -0.17 0.87
## Account_length_woe 1.05851 0.07657 13.82 < 0.0000000000000002 ***
## Age_woe 0.92954 0.11475 8.10 0.00000000000000055 ***
## Total_income_woe 0.94077 0.10806 8.71 < 0.0000000000000002 ***
## Years_employed_woe 0.59486 0.14884 4.00 0.00006426160363769 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 10765 on 7764 degrees of freedom
## Residual deviance: 10347 on 7760 degrees of freedom
## AIC: 10357
##
## Number of Fisher Scoring iterations: 4
💡 Interpretasi model:
Signifikansi variabel : Account_length_woe, Age_woe, Total_income_woe dan Years_employed_woe
Model dapat dibuat dengan hanya memasukan/ menggunakan variable yang signifikan, hanya saja perlu dilakukan pertimbangan secara bisnis apakah variable lain tersebut dapat kita buang secara cuma2.
Deviance null -> error model ketika model tanpa prediktor apapun
residual deviance -> error model ketika prediktor sama dengan prediktor model
Multicollinearity: antar prediktor tidak saling berkorelasi terlalu kuat (lebih dari +- 0.9)
y ~ x1, x2 , x3 -> kuat x1 ~ x2 -> tidak kuat x2 ~ x3 ->tidak kuat
vif() dari library(car)vif(model)## Account_length_woe Age_woe Total_income_woe Years_employed_woe
## 1.008 1.143 1.003 1.142
💡 Insight: tidak ada multikolinearitas pada data
Setelah model didapatkan, prediksi dapat dilakukan terhadap data test yang sudah ditransformasi ke dalam WOE. Prediksi ini dilakukan dengan tujuan 2 hal:
Pada tahapan ini dapat menggunakan fungsi predict.
📌 Syntax: predict(model, newdata, type = "response")
Keterangan:
object : model logistic regressionnewdata : data untuk diprediksi bisa data test ataupun data barutype = "response" untuk menghasilkan prediksi berupa peluang, “link” = prediksi log of odds❓ Prediksikan data test hasil transformasi WOE. Simpan pada kolom baru bernama pred_risk.
# Melakukan prediksi pada data test
test_woe_final$pred_risk <- predict(object = model,
newdata = test_woe_final,
type = "response")
test_woe_finalperf_eva() dari library scorecard menghitung metrik untuk evaluasi model klasifikasi binomial.
Untuk melakukan model evaluation, kita dapat menggunakan fungsi perf_eva() dengan parameter:
pred = list dari vector prediksilabel = list dari vector label actual -> wajib numerikconfusion_matrix = TRUE -> membuat tabel confusion matrixthreshold = 0.5list_pred <- list(test = test_woe_final$pred_risk)list_label <- list(test = test_woe_final$Target)perf_eva untuk melakukan evaluasiperf_eva(pred = list_pred,
label = list_label,
confusion_matrix = TRUE,
threshold = 0.5,
show_plot = c("ks", "roc"))## ℹ The threshold of confusion matrix is 0.5000.
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## ℹ The deprecated feature was likely used in the scorecard package.
## Please report the issue at <https://github.com/ShichenXie/scorecard/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## $binomial_metric
## $binomial_metric$test
## MSE RMSE LogLoss R2 KS AUC Gini
## 1: 0.2402 0.4901 0.6725 0.03899 0.1539 0.6047 0.2094
##
##
## $confusion_matrix
## $confusion_matrix$test
## label pred_0 pred_1 error
## 1: 0 504 461 0.4777
## 2: 1 388 589 0.3971
## 3: total 892 1050 0.4372
##
##
## $pic
## TableGrob (1 x 2) "arrange": 2 grobs
## z cells name grob
## 1 1 (1-1,1-1) arrange gtable[layout]
## 2 2 (1-1,2-2) arrange gtable[layout]
KS (Kolmogorov-Smirnov) Statistics adalah metode statistik yang digunakan untuk mengukur perbedaan antara dua distribusi kumulatif empiris, sering digunakan untuk membandingkan distribusi skor antara dua kelompok, misalnya dalam analisis kinerja credit model (membedakan antara good dan bad customers).
- Satu kurva untuk distribusi kumulatif dari satu kelompok (misalnya, good customers). - Kurva lainnya untuk distribusi kumulatif dari kelompok kedua (misalnya, bad customers). - Garis vertikal pada titik di mana perbedaan antara kedua kurva adalah yang terbesar. Ini adalah titik di mana KS Statistics diukur.
Nilai KS yang tinggi menunjukkan model yang baik dalam membedakan antara kedua kelompok (misalnya, good vs bad customers).
Biasanya, nilai KS > 0.4 dianggap baik dalam kredit scoring.
💡 Interpretasi:
AUC adalah Area under curve atau luas dibawah kurva ROC. Jika nilai AUC semakin mendekati nilai 1, model semakin baik dalam memisahkan kelas positif dan negatif.
💡 Interpretasi:
Pada model logistic regression, output yang dihasilkan berupa prediksi apakah default atau tidak default dalam bentuk probabilitas.
Untuk mempermudah pengambilan keputusan apakah seorang applicant akan default dan tidak default maka hasil binning dapat dibuat menjadi penilaian dalam bentuk score point untuk setiap bin yang diakumulasikan menjadi scorecard.
Manfaat pembentukan scorecard antara lain:
Rumus umum pembentukan score dalam setiap binning (Siddiqi, Naeem)
\[ Points_{ij} = (\frac{pdo}{ln(2)}) \times -Coef_i \times WOE_{ij} \] Keterangan:
Coef : Hasil nilai coefficient dari logistic regressionWOE : Nilai WOE dari setiap binning untuk setiap variabelnya📌 Untuk membuat scorecard dapat menggunakan fungsi scorecard() dengan parameter:
bins: object binning hasil woebin()model: object model hasil glm()odds0: Tingkat keketatan / target odds, rasio kemungkinan default terhadap kemungkinan tidak default. Contoh: 1/19, artinya 1 yg akan default dibanding 19 yang tidak default. Semakin kecil, semakin ketat (ditentukan oleh user)points0: Target points ketika odds0 tercapai. Contoh: points0 = 600 dan odds0 = 1/19, maka pada poin 600 berarti terdapat 1 applicant default terhadap 19 applicant lain yang tidak default (ditentukan oleh user)pdo: points to double the odds, ketika skor kredit suatu individu naik sebesar PDO, itu mengindikasikan bahwa peluang (odds) untuk individu itu berhasil bayar mengalami perubahan sebanyak dua kali lipat. Sebaliknya, jika skor kredit turun sebesar PDO, peluangnya mengalami penurunan setengahnya (ditentukan oleh user).❓ Contoh kasus:
Ingin dihasilkan sebuah scorecard sesuai dengan kebutuhan user dengan odds 19:1 pada poin 600 dan ingin peluangnya berlipat ganda setiap kenaikan 20 poin, maka bagaimana pembentukan scorecardnya?
# membentuk scorecard
score_card <- scorecard(bins = binning,
model = model,
odds0 = 1/19,
points0 = 600,
pdo = 20)
score_card## $basepoints
## variable bin woe points
## 1: basepoints NA NA 515
##
## $Account_length
## variable bin count count_distr neg pos posprob woe
## 1: Account_length [-Inf,5) 403 0.05190 323 80 0.1985 -1.392277
## 2: Account_length [5,9) 545 0.07019 319 226 0.4147 -0.341308
## 3: Account_length [9,38) 4265 0.54926 2127 2138 0.5013 0.008507
## 4: Account_length [38, Inf) 2552 0.32865 1120 1432 0.5611 0.249092
## bin_iv total_iv breaks is_special_values points
## 1: 0.08689890 0.1153 5 FALSE 43
## 2: 0.00809537 0.1153 9 FALSE 10
## 3: 0.00003975 0.1153 38 FALSE 0
## 4: 0.02029133 0.1153 Inf FALSE -8
##
## $Age
## variable bin count count_distr neg pos posprob woe bin_iv
## 1: Age [-Inf,35) 2212 0.28487 958 1254 0.5669 0.2726 0.0210425
## 2: Age [35,37) 416 0.05357 241 175 0.4207 -0.3167 0.0053263
## 3: Age [37,51) 2776 0.35750 1411 1365 0.4917 -0.0298 0.0003174
## 4: Age [51,54) 574 0.07392 260 314 0.5470 0.1921 0.0027188
## 5: Age [54, Inf) 1787 0.23014 1019 768 0.4298 -0.2794 0.0178502
## total_iv breaks is_special_values points
## 1: 0.04726 35 FALSE -7
## 2: 0.04726 37 FALSE 8
## 3: 0.04726 51 FALSE 1
## 4: 0.04726 54 FALSE -5
## 5: 0.04726 Inf FALSE 7
##
## $Total_income
## variable bin count count_distr neg pos posprob woe
## 1: Total_income [-Inf,100000) 1193 0.1536 653 540 0.4526 -0.1867
## 2: Total_income [100000,130000) 1157 0.1490 541 616 0.5324 0.1332
## 3: Total_income [130000,140000) 905 0.1165 480 425 0.4696 -0.1183
## 4: Total_income [140000,180000) 1193 0.1536 508 685 0.5742 0.3023
## 5: Total_income [180000,210000) 1129 0.1454 643 486 0.4305 -0.2766
## 6: Total_income [210000,270000) 1059 0.1364 461 598 0.5647 0.2635
## 7: Total_income [270000, Inf) 1129 0.1454 603 526 0.4659 -0.1333
## bin_iv total_iv breaks is_special_values points
## 1: 0.005337 0.04659 100000 FALSE 5
## 2: 0.002639 0.04659 130000 FALSE -4
## 3: 0.001630 0.04659 140000 FALSE 3
## 4: 0.013937 0.04659 180000 FALSE -8
## 5: 0.011050 0.04659 210000 FALSE 8
## 6: 0.009420 0.04659 270000 FALSE -7
## 7: 0.002578 0.04659 Inf FALSE 4
##
## $Years_employed
## variable bin count count_distr neg pos posprob woe
## 1: Years_employed [-Inf,0.5) 1481 0.19073 810 671 0.4531 -0.18492
## 2: Years_employed [0.5,1.5) 773 0.09955 394 379 0.4903 -0.03547
## 3: Years_employed [1.5,6.5) 3069 0.39524 1387 1682 0.5481 0.19619
## 4: Years_employed [6.5,10.5) 1231 0.15853 634 597 0.4850 -0.05678
## 5: Years_employed [10.5, Inf) 1211 0.15596 664 547 0.4517 -0.19048
## bin_iv total_iv breaks is_special_values points
## 1: 0.0065023 0.02795 0.5 FALSE 3
## 2: 0.0001252 0.02795 1.5 FALSE 1
## 3: 0.0151665 0.02795 6.5 FALSE -3
## 4: 0.0005110 0.02795 10.5 FALSE 1
## 5: 0.0056409 0.02795 Inf FALSE 3
Semisal 2 data pertama pada data train:
📌 Untuk mengubah nilai karakteristik applicant menjadi points dan total points (score) secara otomatis, dapat menggunakan fungsi scorecard_ply() dengan parameter:
dt: dataframe yang berisi karakteristik asli applicant.card: Objek hasil fungsi scorecard().only_total_score: TRUE/FALSE, apakah hanya menampilkan total score atau tidak.Mari kita terapkan scorecard_ply() pada dataframe train dan test.
train %>% head()score_train <- scorecard_ply(dt = train,
card = score_card,
only_total_score = F)
score_train %>% head()Mari kita terapkan scorecard_ply() pada dataframe test.
score_test <- scorecard_ply(dt = test,
card = score_card,
only_total_score = F)
score_test %>% head()Dapat dilihat dari setiap karakteristik asli applicant diubah menjadi bentuk points dan setiap points tersebut dijumlahkan ke dalam kolom score yang menyatakan total points dari applicant tersebut.
perf_psi()Population Stability Index (PSI) adalah suatu metrik yang digunakan dalam analisis kredit dan risiko kredit untuk mengevaluasi stabilitas atau perubahan dalam distribusi poin atau skor kredit dari suatu populasi dari waktu ke waktu.
Langkah-langkah:
Membuat list dengan function list()
score_list <- list(train = score_train$score,
test = score_test$score)label_list <- list(train = train_woe_final$Target,
test = test_woe_final$Target)perf_psi()Parameter:
score : list berisikan score antara data train dan testlabel : list berisikan label antara data train dan test (tidak wajib)positive : kelas positivepsi <- perf_psi(score = score_list,
label = label_list,
positive = 1)
psi$psi # psi data frame📌 Menurut Siddqi Naeem, index PSI memiliki rentang:
PSI < 0.10: Biasanya dianggap sebagai tanda bahwa tidak ada perubahan yang signifikan dalam distribusi skor kredit, dan populasi skor cenderung stabil.
PSI 0.10 s.d 0.25: Menunjukkan perubahan yang relatif kecil yang mungkin memerlukan penyelidikan lebih lanjut. Meskipun tidak menciptakan alarm besar, tetapi tetap penting untuk memahami faktor-faktor apa yang mungkin menyebabkan perubahan tersebut.
PSI > 0.25: Menandakan pergeseran yang signifikan dalam distribusi scorecard dan dapat dianggap sebagai sinyal bahwa ada perubahan yang patut diperhatikan dalam profil risiko kredit. Ini mungkin memerlukan analisis mendalam dan tindakan lebih lanjut.
Penentuan seorang applicant termasuk dalam “GOOD” atau “BAD” applicant, harus ditetapkan nilai cutoff (batas) dari total score applicant. Untuk menentukan nilai cutoff dibutuhkan informasi approval rate dan juga bad rate sehingga dapat menentukan persentase applicant yang dianggap GOOD dan juga tingkat risiko dari applicant yang dianggap GOOD.
Untuk mendapatkan nilai approval rate dan bad rate kita membutuhkan function approval_rate().
approval_rate() akan menampilkan tabel berupa pilihan nilai cutoff, approval rate, negative rate (bad rate) beserta detail lainnya. Adapun parameter approval_rate() antara lain:
score: Kolom score total dari data applicantlabel: Kolom label yang menyatakan apakah applicant default/not default.positive: Kelas positif dari kolom label.#Fungsi Approval_rate
approval_rate <- function(score, label, positive = 0){
# membuat list
score_list <- list(data = score)
label_list <- list(data = label)
# membuat gains_table
g <- gains_table(score = score_list, label = label_list, positive = positive)
final_df <- g %>%
mutate(
count_approved = max(cum_count) - cum_count,
neg_approved = max(cum_neg) - cum_neg,
neg_rate = round((neg_approved / count_approved), 4)
) %>%
replace(is.na(.), 0) %>%
select(bin, approval_rate, neg_rate,
count_approved, neg_approved,
count, neg, pos)
final_df
}# using score test
approval_rate(score = score_test$score,
label = test_woe_final$Target,
positive = 0)Keterangan:
bin : hasil binning dari scoreapproval_rate : tingkat approve apabila kita menggunakan cutoff di titik 501.Rumus = count_approve/total applicant
5576/nrow(test)## [1] 2.871
neg_rate : proporsi applicant yang diapprove tetapi menghasilkan flag negatif (default)Rumus = neg_approved/count_approved
852/1763## [1] 0.4833
count_approve : Banyaknya applicant yang diapprove# banyaknya data train - banyaknya applicant pada binning tersebut
nrow(test) - 179## [1] 1763
neg_approved : Banyaknya applicant yang diapprove tetapi flag negatif (default)neg : Banyaknya applicant default pada bin tertentupos : Banyaknya applicant not default pada bin tertentuInterpretasi
📝 Notes
💡 Kasus:
Semisal risiko yang dapat ditanggung oleh institusi hanyalah di bawah 44%, maka:
Penentuan nilai cutoff dapat digunakan sebagai acuan apakah seorang applicant dianggap “GOOD” ketika total points scorecard di atas nilai cutoff, begitupun akan mendapatkan “BAD” behaviour jika total points di bawah nilai cutoff.
❓ Kasus: semisal kita mempunyai debitur dengan karakteristik nilai asli sebagai berikut. Bagaimana keputusan scorenya?
new_data <- data.frame(list(
Gender = 0,
Own_car = 1,
Own_property = 1,
Work_phone = 1,
Phone = 1,
Email = 1,
Unemployed = 0,
Num_children = 0,
Num_family = 0,
Account_length = 100,
Total_income = 300000,
Age = 40,
Years_employed = 15,
Income_type = 1,
Education_type = 1,
Family_status = 4,
Housing_type = 2,
Occupation_type = 11
))
new_data#Use to check dense_rank of several columns
# unique(dataset)
# unique(dataset_clean)
# unique(dataset$Housing_type)
#
# dataset %>%
# mutate(rank = dense_rank(Occupation_type))Untuk mengubah karakteristik nilai asli hingga menjadi total points dan penentuan behaviour, maka perlu dilakukan tahapan sebagai berikut:
scorecard_ply()Beberapa tahapan ini akan sering digunakan, maka dari itu sebaiknya dibuatkan sebuah fungsi sehingga dapat digunakan berulang kali dengan mudah.
📌 Fungsi yang dibuat bernama predict_behaviour() dengan parameter berikut:
data: Data karakteristik nilai asli debitur yang akan diprediksi skor dan behaviour.score_card: Objek pembentukan score_card hasil dari fungsi scorecard()cutoff: Nilai cutoff ditentukan userSelanjutnya tinggal memanggil fungsi predict_behaviour() dengan memasukkan data debitur beserta objek score_card.
# DO NOT CHANGE
predict_behaviour <- function(data, score_card, cutoff = 529){
new_score <- scorecard_ply(data, score_card)
new_score <- new_score %>%
mutate(
recommendation = case_when(
score > cutoff ~ "GOOD",
TRUE ~ "BAD"
)
)
new_score
}# predict behaviour
result <- predict_behaviour(data = new_data,
score_card = score_card,
cutoff = 512)
resultDengan menggunakan library ScoreCard, pengguna dapat dimudahkan untuk menentukan batasan penerimaan/ penolakan berdasarkan karakteristik data.Beberapa fungsi dapat disesuaikan berdasarkan kebutuhan pengguna dengan pertimbangan bisnis masing-masing.