Data Career Day (DCD) 16.0
Introduksi atau Latar Belakang
LendingClub adalah perusahaan pinjaman peer-to-peer AS, yang berkantor pusat di San Francisco, California. Itu adalah pemberi pinjaman peer-to-peer pertama yang mendaftarkan penawarannya sebagai sekuritas dengan Securities and Exchange Commission (SEC), dan menawarkan perdagangan pinjaman di pasar sekunder. LendingClub adalah platform pinjaman peer-to-peer terbesar di dunia.
Pengertian Bisnis
Kita bekerja untuk perusahaan LendingClub yang mengkhususkan diri dalam meminjamkan berbagai jenis pinjaman kepada pelanggan perkotaan. Ketika perusahaan menerima aplikasi pinjaman, perusahaan harus membuat keputusan untuk persetujuan pinjaman berdasarkan profil pemohon. Dua jenis risiko yang terkait dengan keputusan bank:
Jika pemohon kemungkinan akan membayar kembali pinjaman, dan kita tidak menyetujui pinjaman mengakibatkan loss (kehilangan keuntungan) bagi perusahaan.
Jika pemohon tidak mungkin untuk membayar kembali pinjaman, yaitu dia cenderung gagal bayar, dan kita menyetujui pinjaman dapat menyebabkan loss (kerugian finansial) bagi perusahaan.
Data yang diberikan berisi informasi tentang pemohon pinjaman masa lalu dan apakah mereka ‘gagal bayar’ atau tidak. Tujuannya adalah untuk mengidentifikasi pola-pola yang menunjukkan jika seseorang cenderung gagal, yang dapat digunakan untuk mengambil tindakan seperti menolak pinjaman, mengurangi jumlah pinjaman, atau tetap meminjamkan (kepada pemohon berisiko) pada tingkat bunga yang lebih tinggi, dll.
Ketika seseorang mengajukan pinjaman, ada dua jenis keputusan yang dapat diambil oleh perusahaan:
1. Pinjaman Disetujui: Jika perusahaan menyetujui pinjaman, ada 3 kemungkinan skenario yang dijelaskan di bawah ini:
Fully Paid: Pemohon telah melunasi pinjaman (pokok dan tingkat bunga)/ dapat dikatakan bahwa pemohon tidak ada pinjaman yang lain.Current: Pemohon sedang dalam proses pembayaran cicilan, yaitu masa pinjaman belum selesai. Kandidat ini tidak diberi label sebagai ‘defauled / gagal bayar’.Charged-off: Pemohon tidak membayar angsuran pada waktunya untuk jangka waktu yang lama, yaitu dia telah gagal membayar pinjaman.
2. Pinjaman Ditolak: Perusahaan telah menolak pinjaman (karena kandidat tidak memenuhi persyaratan mereka dll). Sejak pinjaman ditolak, tidak ada riwayat transaksi pemohon dengan perusahaan dan data ini tidak tersedia dengan perusahaan (dan dengan demikian dalam kumpulan data ini)
Tujuan Bisnis
Tujuan dari Bisnis ini adalah:
- LendingClub adalah pasar pinjaman online terbesar, memfasilitasi pinjaman pribadi, pinjaman bisnis, dan pembiayaan prosedur medis. Peminjam dapat dengan mudah mengakses pinjaman dengan suku bunga rendah melalui antarmuka online yang cepat.
- Seperti kebanyakan perusahaan pemberi pinjaman lainnya, meminjamkan pinjaman kepada pelamar yang ‘berisiko’ adalah sumber kerugian finansial terbesar (disebut kerugian kredit). Kerugian kredit adalah jumlah uang yang hilang oleh pemberi pinjaman ketika peminjam menolak untuk membayar atau melarikan diri dengan uang yang terutang. Dengan kata lain, peminjam yang gagal bayar menyebabkan kerugian terbesar bagi pemberi pinjaman. Dalam hal ini, pelanggan yang diberi label ‘Charged-off’ adalah ‘defaulters’.
- Jika seseorang dapat mengidentifikasi pemohon pinjaman berisiko ini, maka pinjaman tersebut dapat dikurangi sehingga mengurangi jumlah kerugian kredit. Identifikasi pelamar tersebut menggunakan EDA dan pembelajaran mesin adalah tujuan dari studi kasus ini.
- Dengan kata lain, perusahaan ingin memahami faktor pendorong (atau variabel pendorong) di balik default pinjaman, yaitu variabel yang merupakan indikator kuat default. Perusahaan dapat memanfaatkan pengetahuan ini untuk portofolio dan penilaian risiko.
- Untuk mengembangkan pemahaman Kita tentang domain, Kita mencoba untuk meneliti sedikit tentang analisis risiko (memahami jenis variabel dan signifikansinya sudah cukup).
Penyataan Masalah
Memecahkan studi kasus ini akan memberi kita gambaran tentang bagaimana masalah bisnis nyata diselesaikan menggunakan EDA dan Machine Learning. Dalam studi kasus ini, kita juga akan mengembangkan pemahaman dasar tentang analisis risiko di perbankan dan layanan keuangan dan memahami bagaimana data digunakan untuk meminimalkan risiko kehilangan uang saat meminjamkan kepada pelanggan.
Batasan Masalah
Data pinjaman telah diperoleh dari situs resmi LendingClub dan kode negara bagian AS dan nama mereka diperoleh dari Wikipedia. Data training terdiri dari data pinjaman dari tahun 2007 sampai 2015 dan data test berisi data pinjaman dari tahun 2016 sampai dengan 2017.
Ide Projek
Ide dari permasalahan yang ada adalah mengembangkan sebuah model machine learning yang dapat melakukan klasifikasi apakah peminjam / nasabah yang sedang mengajukan akan berhasil / gagal bayar berdasarkan hasil dari beberapa teknikal analisis, hasil klasifikasi dari model yang dibuat dapat dimanfaatkan oleh para investor untuk mengambil keputusan apakah akan memberikan pinjaman dengan resiko-resikonya.
Bisnis Serupa
Di Indonesia sudah ada aplikasi serupa seperti KoinWorks dan ModalWho.
Dampak Bisnis
Projek ini dapat dikembangkan untuk memberikan manfaat kepada 2 pihak, yaitu nasabah, dan investor.
- Nasabah dapat memanfaatkan projek ini untuk mendapatkan dana / modal dari investor, namun harus melalui proses seleksi terlebih dahulu.
- Investor dapat memanfaatkan projek ini untuk mendapatkan penghasilan tambahan dari bunga peminjaman dengan mengetahui resiko nya.
Output
Output yang akan dihasilkan berupa dashboard yang akan dibuat dengan R Shinny. Dashboard tersebut akan berisikan informasi dan simulasi prediksi. Berikut contoh dari dashboard yang akan dibuat:
knitr::include_graphics("dashboard.png")Input data berisi data-data yang digunakan sebagai prediktor. Hal ini perlu karena berpengaruh kepada target.
Proses Modeling, merupakan penggunaan beberapa jenis model machine learning dalam melakukan prediksi target.
Output, merupakan hasil prediksi. Berisikan hasil, probability, dan resiko nya.
Data Preparation
Import Library
library(lattice)
library(data.table)
library(ggplot2) #for beautiful plots
library(dplyr) #for manipulations
library(caret) #for partitiong data set
library(randomForest) #for Random Forest
library(tidyr)
library(googleVis) #to create Interactive Maps
library(stringr)
library(tm) #for text analytics
library(SnowballC) #for text analytics - Stemming
library(Matrix)
library(h2o) #to use H2O to build models on large data sets
library(knitr)
library(kableExtra)
library(htmltools)Fungsi Outlier
num_format <- function(l) {
# turn in to accounting format
l <- format(l, scientific = F,big.mark = ",")
# return formatted number
l
}
outlier_treatment <- function(x) {
x[x>quantile(x,.95,na.rm = T)]<-quantile(x,.95,na.rm = T)
x[x<quantile(x,.05,na.rm = T)]<-quantile(x,.05,na.rm = T)
x
}Read Data
Membaca datadari dataset yang sudah ada:
lending <- fread("data input/Lending Club/lc_loan.csv", sep = "," , header = T, stringsAsFactors = F, data.table = T)
head(lending)#> id member_id loan_amnt funded_amnt funded_amnt_inv term int_rate
#> 1: 1077501 1296599 5000 5000 4975 36 months 10.65
#> 2: 1077430 1314167 2500 2500 2500 60 months 15.27
#> 3: 1077175 1313524 2400 2400 2400 36 months 15.96
#> 4: 1076863 1277178 10000 10000 10000 36 months 13.49
#> 5: 1075358 1311748 3000 3000 3000 60 months 12.69
#> 6: 1075269 1311441 5000 5000 5000 36 months 7.90
#> installment grade sub_grade emp_title emp_length
#> 1: 162.87 B B2 10+ years
#> 2: 59.83 C C4 Ryder < 1 year
#> 3: 84.33 C C5 10+ years
#> 4: 339.31 C C1 AIR RESOURCES BOARD 10+ years
#> 5: 67.79 B B5 University Medical Group 1 year
#> 6: 156.46 A A4 Veolia Transportaton 3 years
#> home_ownership annual_inc verification_status issue_d loan_status
#> 1: RENT 24000 Verified Dec-2011 Fully Paid
#> 2: RENT 30000 Source Verified Dec-2011 Charged Off
#> 3: RENT 12252 Not Verified Dec-2011 Fully Paid
#> 4: RENT 49200 Source Verified Dec-2011 Fully Paid
#> 5: RENT 80000 Source Verified Dec-2011 Current
#> 6: RENT 36000 Source Verified Dec-2011 Fully Paid
#> pymnt_plan
#> 1: n
#> 2: n
#> 3: n
#> 4: n
#> 5: n
#> 6: n
#> url
#> 1: https://www.lendingclub.com/browse/loanDetail.action?loan_id=1077501
#> 2: https://www.lendingclub.com/browse/loanDetail.action?loan_id=1077430
#> 3: https://www.lendingclub.com/browse/loanDetail.action?loan_id=1077175
#> 4: https://www.lendingclub.com/browse/loanDetail.action?loan_id=1076863
#> 5: https://www.lendingclub.com/browse/loanDetail.action?loan_id=1075358
#> 6: https://www.lendingclub.com/browse/loanDetail.action?loan_id=1075269
#> desc
#> 1: Borrower added on 12/22/11 > I need to upgrade my business technologies.<br>
#> 2: Borrower added on 12/22/11 > I plan to use this money to finance the motorcycle i am looking at. I plan to have it paid off as soon as possible/when i sell my old bike. I only need this money because the deal im looking at is to good to pass up.<br><br> Borrower added on 12/22/11 > I plan to use this money to finance the motorcycle i am looking at. I plan to have it paid off as soon as possible/when i sell my old bike.I only need this money because the deal im looking at is to good to pass up. I have finished college with an associates degree in business and its takingmeplaces<br>
#> 3:
#> 4: Borrower added on 12/21/11 > to pay for property tax (borrow from friend, need to pay back) & central A/C need to be replace. I'm very sorry to let my loan expired last time.<br>
#> 5: Borrower added on 12/21/11 > I plan on combining three large interest bills together and freeing up some extra each month to pay toward other bills. I've always been a good payor but have found myself needing to make adjustments to my budget due to a medical scare. My job is very stable, I love it.<br>
#> 6:
#> purpose title zip_code addr_state
#> 1: credit_card Computer 860xx AZ
#> 2: car bike 309xx GA
#> 3: small_business real estate business 606xx IL
#> 4: other personel 917xx CA
#> 5: other Personal 972xx OR
#> 6: wedding My wedding loan I promise to pay back 852xx AZ
#> dti delinq_2yrs earliest_cr_line inq_last_6mths mths_since_last_delinq
#> 1: 27.65 0 Jan-1985 1 NA
#> 2: 1.00 0 Apr-1999 5 NA
#> 3: 8.72 0 Nov-2001 2 NA
#> 4: 20.00 0 Feb-1996 1 35
#> 5: 17.94 0 Jan-1996 0 38
#> 6: 11.20 0 Nov-2004 3 NA
#> mths_since_last_record open_acc pub_rec revol_bal revol_util total_acc
#> 1: NA 3 0 13648 83.7 9
#> 2: NA 3 0 1687 9.4 4
#> 3: NA 2 0 2956 98.5 10
#> 4: NA 10 0 5598 21.0 37
#> 5: NA 15 0 27783 53.9 38
#> 6: NA 9 0 7963 28.3 12
#> initial_list_status out_prncp out_prncp_inv total_pymnt total_pymnt_inv
#> 1: f 0.0 0.0 5861.071 5831.78
#> 2: f 0.0 0.0 1008.710 1008.71
#> 3: f 0.0 0.0 3003.654 3003.65
#> 4: f 0.0 0.0 12226.302 12226.30
#> 5: f 766.9 766.9 3242.170 3242.17
#> 6: f 0.0 0.0 5631.378 5631.38
#> total_rec_prncp total_rec_int total_rec_late_fee recoveries
#> 1: 5000.00 861.07 0.00 0.00
#> 2: 456.46 435.17 0.00 117.08
#> 3: 2400.00 603.65 0.00 0.00
#> 4: 10000.00 2209.33 16.97 0.00
#> 5: 2233.10 1009.07 0.00 0.00
#> 6: 5000.00 631.38 0.00 0.00
#> collection_recovery_fee last_pymnt_d last_pymnt_amnt next_pymnt_d
#> 1: 0.00 Jan-2015 171.62
#> 2: 1.11 Apr-2013 119.66
#> 3: 0.00 Jun-2014 649.91
#> 4: 0.00 Jan-2015 357.48
#> 5: 0.00 Jan-2016 67.79 Feb-2016
#> 6: 0.00 Jan-2015 161.03
#> last_credit_pull_d collections_12_mths_ex_med mths_since_last_major_derog
#> 1: Jan-2016 0 NA
#> 2: Sep-2013 0 NA
#> 3: Jan-2016 0 NA
#> 4: Jan-2015 0 NA
#> 5: Jan-2016 0 NA
#> 6: Sep-2015 0 NA
#> policy_code application_type annual_inc_joint dti_joint
#> 1: 1 INDIVIDUAL NA NA
#> 2: 1 INDIVIDUAL NA NA
#> 3: 1 INDIVIDUAL NA NA
#> 4: 1 INDIVIDUAL NA NA
#> 5: 1 INDIVIDUAL NA NA
#> 6: 1 INDIVIDUAL NA NA
#> verification_status_joint acc_now_delinq tot_coll_amt tot_cur_bal
#> 1: 0 NA NA
#> 2: 0 NA NA
#> 3: 0 NA NA
#> 4: 0 NA NA
#> 5: 0 NA NA
#> 6: 0 NA NA
#> open_acc_6m open_il_6m open_il_12m open_il_24m mths_since_rcnt_il
#> 1: NA NA NA NA NA
#> 2: NA NA NA NA NA
#> 3: NA NA NA NA NA
#> 4: NA NA NA NA NA
#> 5: NA NA NA NA NA
#> 6: NA NA NA NA NA
#> total_bal_il il_util open_rv_12m open_rv_24m max_bal_bc all_util
#> 1: NA NA NA NA NA NA
#> 2: NA NA NA NA NA NA
#> 3: NA NA NA NA NA NA
#> 4: NA NA NA NA NA NA
#> 5: NA NA NA NA NA NA
#> 6: NA NA NA NA NA NA
#> total_rev_hi_lim inq_fi total_cu_tl inq_last_12m
#> 1: NA NA NA NA
#> 2: NA NA NA NA
#> 3: NA NA NA NA
#> 4: NA NA NA NA
#> 5: NA NA NA NA
#> 6: NA NA NA NA
Data Wrangling
Cek Dimensi Dataset
dim(lending)#> [1] 887379 74
Dataset terdiri dari 887.379 observasi dan 74 variabel.
Cek NA Dataset
colSums(is.na(lending))#> id member_id
#> 0 0
#> loan_amnt funded_amnt
#> 0 0
#> funded_amnt_inv term
#> 0 0
#> int_rate installment
#> 0 0
#> grade sub_grade
#> 0 0
#> emp_title emp_length
#> 0 0
#> home_ownership annual_inc
#> 0 4
#> verification_status issue_d
#> 0 0
#> loan_status pymnt_plan
#> 0 0
#> url desc
#> 0 0
#> purpose title
#> 0 0
#> zip_code addr_state
#> 0 0
#> dti delinq_2yrs
#> 0 29
#> earliest_cr_line inq_last_6mths
#> 0 29
#> mths_since_last_delinq mths_since_last_record
#> 454312 750326
#> open_acc pub_rec
#> 29 29
#> revol_bal revol_util
#> 0 502
#> total_acc initial_list_status
#> 29 0
#> out_prncp out_prncp_inv
#> 0 0
#> total_pymnt total_pymnt_inv
#> 0 0
#> total_rec_prncp total_rec_int
#> 0 0
#> total_rec_late_fee recoveries
#> 0 0
#> collection_recovery_fee last_pymnt_d
#> 0 0
#> last_pymnt_amnt next_pymnt_d
#> 0 0
#> last_credit_pull_d collections_12_mths_ex_med
#> 0 145
#> mths_since_last_major_derog policy_code
#> 665676 0
#> application_type annual_inc_joint
#> 0 886868
#> dti_joint verification_status_joint
#> 886870 0
#> acc_now_delinq tot_coll_amt
#> 29 70276
#> tot_cur_bal open_acc_6m
#> 70276 866007
#> open_il_6m open_il_12m
#> 866007 866007
#> open_il_24m mths_since_rcnt_il
#> 866007 866569
#> total_bal_il il_util
#> 866007 868762
#> open_rv_12m open_rv_24m
#> 866007 866007
#> max_bal_bc all_util
#> 866007 866007
#> total_rev_hi_lim inq_fi
#> 70276 866007
#> total_cu_tl inq_last_12m
#> 866007 866007
Dilihat dari jumlah NA yang banyak, maka beberapa variable bisa dihilangkan. Karena kemungkinan variabel tersebut tidak memiliki dampak. Variabel yang dapat dihilangkan seperti mths_since_last_delinq, mths_since_last_record, mths_since_last_major_derog, annual_inc_joint, dti_joint, tot_coll_amt, tot_cur_bal, open_acc_6m, open_il_6m, open_il_12m, open_il_24m, mths_since_rcnt_il, total_bal_il, il_util, open_rv_12m, open_rv_24m, max_bal_bc, all_util, total_rev_hi_lim, inq_fi, total_cu_tl, inq_last_12m.
Data Cleansing
lending <- lending %>%
select(-c(mths_since_last_delinq, mths_since_last_record, mths_since_last_major_derog, annual_inc_joint, dti_joint, tot_coll_amt, tot_cur_bal, open_acc_6m, open_il_6m, open_il_12m, open_il_24m, mths_since_rcnt_il, total_bal_il, il_util, open_rv_12m, open_rv_24m, max_bal_bc, all_util, total_rev_hi_lim, inq_fi, total_cu_tl, inq_last_12m))colSums(is.na(lending))#> id member_id
#> 0 0
#> loan_amnt funded_amnt
#> 0 0
#> funded_amnt_inv term
#> 0 0
#> int_rate installment
#> 0 0
#> grade sub_grade
#> 0 0
#> emp_title emp_length
#> 0 0
#> home_ownership annual_inc
#> 0 4
#> verification_status issue_d
#> 0 0
#> loan_status pymnt_plan
#> 0 0
#> url desc
#> 0 0
#> purpose title
#> 0 0
#> zip_code addr_state
#> 0 0
#> dti delinq_2yrs
#> 0 29
#> earliest_cr_line inq_last_6mths
#> 0 29
#> open_acc pub_rec
#> 29 29
#> revol_bal revol_util
#> 0 502
#> total_acc initial_list_status
#> 29 0
#> out_prncp out_prncp_inv
#> 0 0
#> total_pymnt total_pymnt_inv
#> 0 0
#> total_rec_prncp total_rec_int
#> 0 0
#> total_rec_late_fee recoveries
#> 0 0
#> collection_recovery_fee last_pymnt_d
#> 0 0
#> last_pymnt_amnt next_pymnt_d
#> 0 0
#> last_credit_pull_d collections_12_mths_ex_med
#> 0 145
#> policy_code application_type
#> 0 0
#> verification_status_joint acc_now_delinq
#> 0 29
dim(lending)#> [1] 887379 52
Setelah dilakukan Data Cleansing awal, dimensi variabel dari 74 berubah menjadi 52.
Deskripsi Data:
id: Nomor ID peminjam.member_id: Nomor Member ID pemimjam.loan_amnt: Jumlah pinjaman yang terdaftar yang diajukan oleh peminjam. Jika pada suatu saat, departemen kredit mengurangi jumlah pinjaman, maka itu akan tercermin dalam nilai ini.funded_amnt: Jumlah total yang diberikan untuk pinjaman itu pada saat itu.funded_amnt_inv: Jumlah total yang dilakukan oleh investor untuk pinjaman tersebut pada saat itu.term: Jumlah pembayaran pinjaman. Nilai dalam bulan dan dapat berupa 36 atau 60.int_rate: Suku bunga peminjamaninstallment: Pembayaran bulanan yang harus dibayar oleh peminjam jika pinjaman berasal.grade: LendingClub memberikan peringkat pinjaman.sub_grade: LendingClub memberikan sub-peringkat pinjaman.emp_title: Jabatan yang diberikan oleh Peminjam saat mengajukan pinjaman.emp_length: Lama kerja dalam tahun. Nilai yang mungkin antara 0 dan 10 di mana 0 berarti kurang dari satu tahun dan 10 berarti sepuluh tahun atau lebih.home_ownership: Status kepemilikan rumah yang diberikan oleh peminjam pada saat pendaftaran atau diperoleh dari laporan kredit. Nilai-nilai kami adalah: RENT, OWN, MORTGAGE, OTHER.annual_inc: Pendapatan tahunan yang dilaporkan sendiri yang diberikan oleh peminjam selama pendaftaran.verification_status: Menunjukkan jika pendapatan diverifikasi oleh LendingClub, tidak diverifikasi, atau jika sumber pendapatan diverifikasi.issue_d: Bulan di mana pinjaman didanai.loan_status: Status pinjaman saat ini.pymnt_plan: Rencana pembayaran dapat merujuk pada pelunasan hutang yang belum dibayar, atau terkadang lebih dari satu hutang melalui konsolidasi ke dalam jadwal pembayaran yang terorganisir.url: URL untuk halaman LendingClub dengan data daftar.desc: Deskripsi pinjaman yang diberikan oleh peminjam.purpose: Kategori yang disediakan oleh peminjam untuk permintaan pinjaman.title: Judul pinjaman yang diberikan oleh peminjam.zip_code: Kode Pos peminjam.addr_state: Alamat Kode Regional di US.dti: Rasio yang dihitung dengan menggunakan total pembayaran utang bulanan peminjam terhadap total kewajiban utang, (tidak termasuk hipotek dan pinjaman LendingClub yang diminta), dibagi dengan pendapatan bulanan yang dilaporkan sendiri oleh peminjam.delinq-2yrs: Berapa kali peminjam telah melewati batas waktu 30+ hari untuk pembayaran dalam 2 tahun terakhir.earliest_cr_line: Bulan dimana batas kredit paling awal yang dilaporkan peminjam dibuka.inq_last_6mths: Jumlah pertanyaan oleh kreditur selama 6 bulan terakhir.open_acc: Jumlah jalur kredit terbuka dalam file kredit peminjam.pub_rec: Jumlah catatan publik yang derogatory/menghina.revol_bal: Total saldo kredit bergulir.revol_util: Tingkat pemanfaatan jalur revolving, atau jumlah kredit yang digunakan peminjam relatif terhadap semua kredit revolving yang tersedia.total_acc: Jumlah total jalur kredit saat ini dalam file kredit peminjam.initial_list_status: Status pencatatan awal pinjaman. Nilai yang mungkin adalah – W, Fout_prncp: Sisa pokok pinjaman untuk jumlah total yang didanai.out_prncp_inv: Sisa pokok pinjaman untuk sebagian dari jumlah total yang didanai oleh investor.total_pymnt: Pembayaran diterima hingga saat ini untuk jumlah total yang didanai.total_pymnt_inv: Pembayaran yang diterima hingga saat ini untuk sebagian dari jumlah total yang didanai oleh investor.total_rec_prncp: Pokok diterima hingga saat ini.total_rec_int: Bunga yang diterima hingga saat ini.total_rec_late_fee: Biaya keterlambatan diterima hingga saat ini.recoveries: pasca charge off pemulihan kotor.collection_recovery_fee: post charge off biaya pengumpulan.last_pymnt_d: Pembayaran bulan lalu telah diterima.last_pymnt_amnt: Jumlah total pembayaran terakhir yang diterima.next_pymnt_d: Tanggal pembayaran terjadwal berikutnya.last_credit_pull_d: LendingClub bulan terakhir menarik kredit untuk pinjaman ini.collections_12_mths_ex_med: Jumlah koleksi dalam 12 bulan tidak termasuk koleksi medis.policy_code: tersedia untuk umum policy_code=1 produk baru tidak tersedia untuk publik policy_code=2.application_type: Menunjukkan apakah pinjaman tersebut merupakan aplikasi individu atau aplikasi bersama dengan dua peminjam bersama.verification_status_joint: Menunjukkan jika pendapatan bersama peminjam telah diverifikasi oleh LendingClub, tidak diverifikasi, atau jika sumber pendapatan diverifikasi.acc_now_delinq: Jumlah rekening di mana peminjam sekarang menunggak.
Exploratory Data Analysis
Berguna untuk mendapatkan pemahaman tentang variabel mana yang penting, lihat statistik ringkasan, dan visualisasikan datanya.
Melihat Ringkasan Dataset
summary(lending)#> id member_id loan_amnt funded_amnt
#> Min. : 54734 Min. : 70473 Min. : 500 Min. : 500
#> 1st Qu.: 9206643 1st Qu.:10877134 1st Qu.: 8000 1st Qu.: 8000
#> Median :34433267 Median :37095283 Median :13000 Median :13000
#> Mean :32465133 Mean :35001825 Mean :14755 Mean :14742
#> 3rd Qu.:54908135 3rd Qu.:58471347 3rd Qu.:20000 3rd Qu.:20000
#> Max. :68617057 Max. :73544841 Max. :35000 Max. :35000
#>
#> funded_amnt_inv term int_rate installment
#> Min. : 0 Length:887379 Min. : 5.32 Min. : 15.67
#> 1st Qu.: 8000 Class :character 1st Qu.: 9.99 1st Qu.: 260.70
#> Median :13000 Mode :character Median :12.99 Median : 382.55
#> Mean :14702 Mean :13.25 Mean : 436.72
#> 3rd Qu.:20000 3rd Qu.:16.20 3rd Qu.: 572.60
#> Max. :35000 Max. :28.99 Max. :1445.46
#>
#> grade sub_grade emp_title emp_length
#> Length:887379 Length:887379 Length:887379 Length:887379
#> Class :character Class :character Class :character Class :character
#> Mode :character Mode :character Mode :character Mode :character
#>
#>
#>
#>
#> home_ownership annual_inc verification_status issue_d
#> Length:887379 Min. : 0 Length:887379 Length:887379
#> Class :character 1st Qu.: 45000 Class :character Class :character
#> Mode :character Median : 65000 Mode :character Mode :character
#> Mean : 75028
#> 3rd Qu.: 90000
#> Max. :9500000
#> NA's :4
#> loan_status pymnt_plan url desc
#> Length:887379 Length:887379 Length:887379 Length:887379
#> Class :character Class :character Class :character Class :character
#> Mode :character Mode :character Mode :character Mode :character
#>
#>
#>
#>
#> purpose title zip_code addr_state
#> Length:887379 Length:887379 Length:887379 Length:887379
#> Class :character Class :character Class :character Class :character
#> Mode :character Mode :character Mode :character Mode :character
#>
#>
#>
#>
#> dti delinq_2yrs earliest_cr_line inq_last_6mths
#> Min. : 0.00 Min. : 0.0000 Length:887379 Min. : 0.0000
#> 1st Qu.: 11.91 1st Qu.: 0.0000 Class :character 1st Qu.: 0.0000
#> Median : 17.65 Median : 0.0000 Mode :character Median : 0.0000
#> Mean : 18.16 Mean : 0.3144 Mean : 0.6946
#> 3rd Qu.: 23.95 3rd Qu.: 0.0000 3rd Qu.: 1.0000
#> Max. :9999.00 Max. :39.0000 Max. :33.0000
#> NA's :29 NA's :29
#> open_acc pub_rec revol_bal revol_util
#> Min. : 0.00 Min. : 0.0000 Min. : 0 Min. : 0.00
#> 1st Qu.: 8.00 1st Qu.: 0.0000 1st Qu.: 6443 1st Qu.: 37.70
#> Median :11.00 Median : 0.0000 Median : 11875 Median : 56.00
#> Mean :11.55 Mean : 0.1953 Mean : 16921 Mean : 55.07
#> 3rd Qu.:14.00 3rd Qu.: 0.0000 3rd Qu.: 20829 3rd Qu.: 73.60
#> Max. :90.00 Max. :86.0000 Max. :2904836 Max. :892.30
#> NA's :29 NA's :29 NA's :502
#> total_acc initial_list_status out_prncp out_prncp_inv
#> Min. : 1.00 Length:887379 Min. : 0 Min. : 0
#> 1st Qu.: 17.00 Class :character 1st Qu.: 0 1st Qu.: 0
#> Median : 24.00 Mode :character Median : 6458 Median : 6456
#> Mean : 25.27 Mean : 8403 Mean : 8400
#> 3rd Qu.: 32.00 3rd Qu.:13659 3rd Qu.:13654
#> Max. :169.00 Max. :49373 Max. :49373
#> NA's :29
#> total_pymnt total_pymnt_inv total_rec_prncp total_rec_int
#> Min. : 0 Min. : 0 Min. : 0 Min. : 0.0
#> 1st Qu.: 1915 1st Qu.: 1900 1st Qu.: 1201 1st Qu.: 441.5
#> Median : 4895 Median : 4862 Median : 3215 Median : 1073.3
#> Mean : 7559 Mean : 7521 Mean : 5758 Mean : 1754.8
#> 3rd Qu.:10617 3rd Qu.:10566 3rd Qu.: 8000 3rd Qu.: 2238.3
#> Max. :57778 Max. :57778 Max. :35000 Max. :24205.6
#>
#> total_rec_late_fee recoveries collection_recovery_fee
#> Min. : 0.0000 Min. : 0.00 Min. : 0.000
#> 1st Qu.: 0.0000 1st Qu.: 0.00 1st Qu.: 0.000
#> Median : 0.0000 Median : 0.00 Median : 0.000
#> Mean : 0.3967 Mean : 45.92 Mean : 4.881
#> 3rd Qu.: 0.0000 3rd Qu.: 0.00 3rd Qu.: 0.000
#> Max. :358.6800 Max. :33520.27 Max. :7002.190
#>
#> last_pymnt_d last_pymnt_amnt next_pymnt_d last_credit_pull_d
#> Length:887379 Min. : 0.0 Length:887379 Length:887379
#> Class :character 1st Qu.: 280.2 Class :character Class :character
#> Mode :character Median : 462.8 Mode :character Mode :character
#> Mean : 2164.2
#> 3rd Qu.: 831.2
#> Max. :36475.6
#>
#> collections_12_mths_ex_med policy_code application_type
#> Min. : 0.00000 Min. :1 Length:887379
#> 1st Qu.: 0.00000 1st Qu.:1 Class :character
#> Median : 0.00000 Median :1 Mode :character
#> Mean : 0.01438 Mean :1
#> 3rd Qu.: 0.00000 3rd Qu.:1
#> Max. :20.00000 Max. :1
#> NA's :145
#> verification_status_joint acc_now_delinq
#> Length:887379 Min. : 0.000000
#> Class :character 1st Qu.: 0.000000
#> Mode :character Median : 0.000000
#> Mean : 0.004991
#> 3rd Qu.: 0.000000
#> Max. :14.000000
#> NA's :29
Analysis 1 Variable
Melihat Proporsional Target Dataset
unique(lending$loan_status)#> [1] "Fully Paid"
#> [2] "Charged Off"
#> [3] "Current"
#> [4] "Default"
#> [5] "Late (31-120 days)"
#> [6] "In Grace Period"
#> [7] "Late (16-30 days)"
#> [8] "Does not meet the credit policy. Status:Fully Paid"
#> [9] "Does not meet the credit policy. Status:Charged Off"
#> [10] "Issued"
Terdapat 10 unik yang terdapat pada variabel loan_status.
dist_status <- lending %>%
select(loan_status) %>%
count(loan_status) %>%
mutate(pct = n / sum(n),
pctlabel = paste0(round(pct*100), "%"))
ggplot(dist_status,
aes(x = reorder(loan_status, -pct),
y = pct)) +
geom_bar(stat = "identity",
fill = rainbow(10),
color = "azure4") +
geom_text(aes(label = pctlabel),
vjust = -0.15) +
theme_minimal() +
labs(x = "Loan Status",
y = "Frequency",
title = "Loan Status Count") +
theme(axis.text.x = element_text(angle = 10,
hjust = 1))Dapat dilihat bahwa sekitar 10 jenis status pinjaman ada dalam kumpulan data ini. Kita hanya tertarik pada 2 status yaitu Defaulted dan Not Defaulted. Oleh karena itu, kita perlu menambahkan variabel baru yang akan bertipe binomial (0 dan 1).
- 0 berarti Non-default / tidak melanggar / mampu bayar.
- 1 berarti Defaulted / melanggar / gagal bayar.
Semua pinjaman yang berstatus “Fully Paid”, “Current”, “Issued” akan dikategorikan “Tidak Melanggar” dan sisanya akan dikategorikan “Gagal Bayar”. Untuk mencapai ini kita akan memperkenalkan variabel baru default.
lending[loan_status %like% "(.*)?Fully Paid",loan_status:="Fully Paid"]
lending[loan_status %like% "(.*)?Charged Off",loan_status:="Charged Off"]
lending[!(loan_status %in% c("Fully Paid","Current","Issued")),loan_status:="Default"]
lending <- lending %>%
mutate(defaulted=ifelse(loan_status=="Default",1,0))
lending <- data.table(lending)
lending$defaulted <- as.factor(lending$defaulted)dist_status1 <- lending %>%
select(defaulted) %>%
count(defaulted) %>%
mutate(pct1 = n / sum(n),
pctlabel1 = paste0(round(pct1*100), "%"))
ggplot(dist_status1,
aes(x = reorder(defaulted, -pct1),
y = pct1)) +
geom_bar(stat = "identity",
fill = rainbow(2),
color = "azure4") +
geom_text(aes(label = pctlabel1),
vjust = -0.25) +
theme_minimal() +
labs(x = "Non-Default VS Default",
y = "Frequency",
title = "Distribution Non-Default VS Default Count") +
theme(axis.text.x = element_text(angle = 0,
hjust = 1))Dapat dilihat dari tabel di atas bahwa hanya 8% dari pinjaman yang gagal bayar. Oleh karena itu, ini adalah kumpulan data yang sangat tidak seimbang, yang akan memerlukan beberapa penyesuaian parameter selama pemodelan prediksi. Namun jika kita melihat dari sisi bisnis, hal tersebut dapat menjadi tolak ukur dari kinerja perusahaan tersebut. Semakin sedikit nilai yang gagal bayar, berarti perusahaan tersebut profit.
Melihat Jenis Jumlah Pinjaman
Kita memiliki 3 bidang berbeda yang menunjukkan jumlah pinjaman yang diajukan / didanai.
loan_amnt: Jumlah pinjaman yang diajukan oleh peminjam.funded_amnt: Jumlah total yang didanai.funded_amnt_inv: Jumlah total yang didanai oleh investor individu.
Mari kita analisis untuk melihat apakah ada perbedaan yang signifikan antara ketiganya.
loan_amount_vars <- c("loan_amnt", "funded_amnt", "funded_amnt_inv")
lending %>%
select(.dots = loan_amount_vars) %>%
gather(key="vars",value="amounts") %>%
ggplot(aes(x=amounts)) +
geom_histogram() +
facet_grid(.~vars)Histogram dari 3 bidang hampir identik sama. Artinya jumlah pinjaman yang diajukan oleh peminjam, kurang lebih diberikan sama oleh LendingClub.
Returns on Investment (ROI)
Mari kita cari tahu Pengembalian Investasi (ROI) LendingClub. Kita akan mengabaikan pinjaman yang berstatus ‘Current / Lancar’ dan hanya akan mempertimbangkan pinjaman ‘Default / Gagal Bayar’ dan ‘Fully Paid / Dibayar Penuh’.
#Defaulted Loans
(sum(lending[defaulted==1,total_pymnt]) - sum(lending[defaulted==1,funded_amnt])) * 100 / sum(lending[defaulted==1,funded_amnt])#> [1] -56.88283
#Fully Paid loans
(sum(lending[loan_status=='Fully Paid',total_pymnt]) - sum(lending[loan_status=='Fully Paid',funded_amnt])) *100 / sum(lending[loan_status=='Fully Paid',funded_amnt])#> [1] 14.1718
Untuk pinjaman Gagal Bayar, LendingClub mengalami kerugian sebesar kurang lebih 57%. Sedangkan untuk pinjaman yang Dibayar Penuh, ada kenaikan pendapatan sebesar 14% yang dihasilkan dari bunga, biaya, biaya, denda, dll.
Analysis Multi-Variables
Sekarang, mari kita pertimbangkan beberapa variabel sekaligus untuk menemukan hubungan di antara mereka dan mendapatkan wawasan lainnya.
Grade VS Interest Rate
ggplot(lending,
aes(grade,int_rate,fill = grade)) +
geom_boxplot(show.legend = F) +
facet_grid(.~defaulted) +
stat_summary(geom = "text",fun.data=function(x) {return(c(y=median(x)*1.1,label=length(x)))})Ketika kualitas pinjaman meningkat, suku bunga menurun dan tidak banyak. Kredit yang diberikan tergolong kredit dengan kualitas baik hingga sedang. ‘A’ menjadi pinjaman dengan kualitas tertinggi dan ‘G’ menjadi yang terendah. Banyak outlier yang ada untuk variabel int_rate, oleh karena itu perlu dilakukan treatment outlier yang sesuai.
Grade VS Loan Amount
ggplot(lending,
aes(grade,loan_amnt,fill=grade)) +
geom_boxplot(show.legend = F) +
facet_grid(.~defaulted) +
stat_summary(geom = "text",fun.data=function(x) {return(c(y=median(x)*1.1,label=length(x)))})Ketika kualitas pinjaman menurun, orang cenderung membeli jumlah pinjaman yang lebih besar.
Home Ownership VS Loan Amount
ggplot(lending,
aes(home_ownership,loan_amnt,fill=home_ownership)) +
geom_boxplot(show.legend = F) +
facet_grid(.~defaulted) +
stat_summary(geom = "text",fun.data=function(x) {return(c(y=quantile(x,.75)[[1]],label=length(x)))},aes(vjust="bottom"))1.) Peminjam yang berada di Mortgaged / di Rented, mengambil sebagian besar pinjaman. 2.) Kebanyakan Default / 1 / gagal bayar berada di Rented.
Verification Status VS Defaulted
ggplot(lending,
aes(x=verification_status)) +
geom_bar() +
facet_grid(.~defaulted) +
stat_count(geom = "text",aes(label=..count..,vjust="bottom"))Pendapatan peminjam Default dan Non-Default dari pinjaman, 40% ‘tidak diverifikasi’. Oleh karena itu, tidak banyak signifikansi untuk memprediksi peminjam default / gagal bayar / 1.
Purpose VS Defaulted
ggplot(lending,
aes(x=purpose)) +
geom_bar() +
facet_grid(.~defaulted) +
stat_count(geom = "text",aes(label=..count..,vjust="bottom")) +
theme(axis.text.x=element_text( angle=30, vjust=.8, hjust=0.8)) +
scale_y_continuous(labels = num_format)Sebagian besar pinjaman diambil untuk tujuan Kartu Kredit dan Konsolidasi Hutang dan sebagian besar telah gagal.
Application type VS Funded Amount
ggplot(lending,
aes(x=application_type,y=funded_amnt)) +
geom_boxplot() +
facet_grid(.~defaulted) +
stat_summary(geom = "text",fun.data=function(x) {return(c(y=quantile(x,.75)[[1]],label=length(x)))},aes(vjust="bottom"))Rasio pelamar Gabungan dengan Perorangan sangat rendah. Oleh karena itu kita akan mengabaikan variabel application_type.
Grade VS Interest Rate VS Tenure
ggplot(lending,
aes(grade,int_rate,fill=grade)) +
geom_boxplot(show.legend = F) +
facet_grid(.~term) +
stat_summary(geom = "text",fun.data=function(x) {return(c(y=median(x)*1.1,label=length(x)))})1.) Pinjaman besar diambil di jangka waktu 36 bulan. 2.) Pinjaman berkualitas baik di jangka waktu 36 bulan. 3.) Pinjaman berkualitas menengah hingga rendah diambil di jangka waktu 60 bulan.
Mari kita hitung berapa banyak kerugian yang terjadi pada pinjaman Default oleh LendingClub untuk setiap tenor.
temp_vars<-c('total_pymnt','funded_amnt','term')
knitr::kable(as.data.table(lending[defaulted==1] %>%
select(total_pymnt,funded_amnt,term) %>%
group_by(term) %>%
summarise(total_pay=sum(total_pymnt),funded=sum(funded_amnt))%>%
mutate(loss.perc =100*(total_pay-funded)/funded)))| term | total_pay | funded | loss.perc |
|---|---|---|---|
| 36 months | 243770134 | 514638825 | -52.63277 |
| 60 months | 187227612 | 484957700 | -61.39300 |
1.) Sekitar 61% kerugian terjadi dalam kasus pinjaman dengan durasi 60 bulan. 2.) Sekitar 52% kerugian terjadi dalam kasus pinjaman dengan durasi 36 bulan.
Employment Period VS Defaulted
ggplot(lending,
aes(emp_length)) +
geom_bar(position="dodge") +
facet_grid(.~defaulted) +
theme(axis.text.x=element_text( angle=30, vjust=.8, hjust=0.8)) +
scale_y_continuous(labels = num_format)Peminjam dengan masa kerja > 10 tahun telah mengambil sebagian besar pinjaman dan juga paling sering gagal.
Annual Income VS Funded Amount
ggplot(lending,
aes(annual_inc,funded_amnt)) +
geom_point()Individu berpenghasilan sangat tinggi (pendapatan> 6 juta) telah mengambil pinjaman hanya 10ribu.
HNI Borrowers
knitr::kable(lending[annual_inc>=7500000],caption="HNI Borrower Details")| id | member_id | loan_amnt | funded_amnt | funded_amnt_inv | term | int_rate | installment | grade | sub_grade | emp_title | emp_length | home_ownership | annual_inc | verification_status | issue_d | loan_status | pymnt_plan | url | desc | purpose | title | zip_code | addr_state | dti | delinq_2yrs | earliest_cr_line | inq_last_6mths | open_acc | pub_rec | revol_bal | revol_util | total_acc | initial_list_status | out_prncp | out_prncp_inv | total_pymnt | total_pymnt_inv | total_rec_prncp | total_rec_int | total_rec_late_fee | recoveries | collection_recovery_fee | last_pymnt_d | last_pymnt_amnt | next_pymnt_d | last_credit_pull_d | collections_12_mths_ex_med | policy_code | application_type | verification_status_joint | acc_now_delinq | defaulted |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 24304613 | 26707548 | 15000 | 15000 | 15000 | 36 months | 19.52 | 553.80 | E | E2 | Sales & service rep | 10+ years | MORTGAGE | 7500000 | Verified | Aug-2014 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=24304613 | medical | Medical expenses | 894xx | NV | 0.20 | 2 | Jan-1988 | 5 | 29 | 1 | 9872 | 27.3 | 42 | f | 9393.62 | 9393.62 | 8860.80 | 8860.80 | 5606.38 | 3254.42 | 0 | 0 | 0 | Jan-2016 | 553.80 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 66605376 | 71331231 | 14000 | 14000 | 14000 | 60 months | 10.64 | 301.89 | B | B4 | Customer Representative | 10+ years | MORTGAGE | 8700000 | Source Verified | Dec-2015 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=66605376 | debt_consolidation | Debt consolidation | 292xx | SC | 0.18 | 0 | Jun-1993 | 0 | 20 | 0 | 12664 | 44.9 | 32 | w | 13822.24 | 13822.24 | 285.34 | 285.34 | 177.76 | 107.58 | 0 | 0 | 0 | Jan-2016 | 301.89 | Jan-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 65945334 | 70640084 | 11000 | 11000 | 11000 | 36 months | 6.89 | 339.10 | A | A3 | registered nurse | 10+ years | MORTGAGE | 9000000 | Source Verified | Dec-2015 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=65945334 | debt_consolidation | Debt consolidation | 330xx | FL | 0.08 | 0 | Apr-2004 | 1 | 15 | 0 | 14165 | 33.8 | 29 | w | 10724.06 | 10724.06 | 334.89 | 334.89 | 275.94 | 58.95 | 0 | 0 | 0 | Jan-2016 | 339.10 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 64097639 | 68528362 | 12000 | 12000 | 12000 | 36 months | 9.17 | 382.55 | B | B2 | Senior Field Operator | 10+ years | MORTGAGE | 8500021 | Source Verified | Nov-2015 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=64097639 | credit_card | Credit card refinancing | 115xx | NY | 0.22 | 0 | Sep-2001 | 0 | 9 | 0 | 18409 | 88.9 | 21 | f | 11709.15 | 11709.15 | 373.38 | 373.38 | 290.85 | 82.53 | 0 | 0 | 0 | Dec-2015 | 382.55 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 63527107 | 67869887 | 30000 | 30000 | 30000 | 36 months | 12.69 | 1006.35 | C | C2 | Sr Mgr | 10+ years | OWN | 8253000 | Source Verified | Nov-2015 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=63527107 | debt_consolidation | Debt consolidation | 752xx | TX | 0.14 | 0 | Aug-2002 | 2 | 18 | 0 | 26402 | 61.5 | 26 | f | 28614.51 | 28614.51 | 1864.65 | 1864.65 | 1385.49 | 479.16 | 0 | 0 | 0 | Dec-2015 | 1006.35 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 60753579 | 64795396 | 5000 | 5000 | 5000 | 36 months | 8.18 | 157.10 | B | B1 | Facilities Operations Manager | 10+ years | MORTGAGE | 8121180 | Source Verified | Oct-2015 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=60753579 | debt_consolidation | Debt consolidation | 820xx | WY | 0.48 | 0 | Dec-1980 | 0 | 19 | 0 | 66893 | 88.0 | 36 | w | 4628.43 | 4628.43 | 466.76 | 466.76 | 371.57 | 95.19 | 0 | 0 | 0 | Jan-2016 | 157.10 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 60565847 | 64586591 | 10000 | 10000 | 9900 | 36 months | 6.89 | 308.27 | A | A3 | Interim Director of Case Management | 3 years | MORTGAGE | 7600000 | Source Verified | Sep-2015 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=60565847 | home_improvement | Home improvement | 295xx | SC | 0.09 | 10 | Feb-1989 | 1 | 18 | 0 | 2494 | 15.7 | 27 | f | 0.00 | 0.00 | 10160.26 | 10058.66 | 10000.00 | 160.26 | 0 | 0 | 0 | Dec-2015 | 9551.38 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 55140826 | 58711625 | 10550 | 10550 | 10550 | 36 months | 15.61 | 368.88 | D | D1 | commercial driver | 10+ years | RENT | 8900060 | Source Verified | Jul-2015 | Default | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=55140826 | debt_consolidation | Debt consolidation | 338xx | FL | 0.09 | 0 | Nov-2006 | 1 | 9 | 0 | 5311 | 102.1 | 11 | w | 9361.26 | 9361.26 | 1826.10 | 1826.10 | 1188.74 | 637.36 | 0 | 0 | 0 | Jan-2016 | 368.88 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 1 | ||
| 54067210 | 57607924 | 24000 | 24000 | 24000 | 60 months | 7.89 | 485.38 | A | A5 | reg nurse | 10+ years | MORTGAGE | 9500000 | Source Verified | Jul-2015 | Current | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=54067210 | credit_card | Credit card refinancing | 906xx | CA | 0.12 | 0 | Jul-1982 | 0 | 12 | 0 | 16854 | 22.0 | 31 | f | 22001.93 | 22001.93 | 2901.76 | 2901.76 | 1998.07 | 903.69 | 0 | 0 | 0 | Jan-2016 | 485.38 | Feb-2016 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 0 | ||
| 39429853 | 42233601 | 8000 | 8000 | 8000 | 36 months | 13.66 | 272.11 | C | C3 | Correctional Sgt. | 10+ years | MORTGAGE | 8706582 | Source Verified | Jan-2015 | Default | n | https://www.lendingclub.com/browse/loanDetail.action?loan_id=39429853 | credit_card | Credit card refinancing | 629xx | IL | 0.11 | 0 | Jul-2000 | 1 | 11 | 0 | 16449 | 54.1 | 18 | w | 0.00 | 0.00 | 1345.37 | 1345.37 | 926.06 | 419.31 | 0 | 0 | 0 | Jun-2015 | 272.11 | Jan-2016 | 0 | 1 | INDIVIDUAL | 0 | 1 |
Dengan melihat data HNI, employment title mereka tidak dapat membenarkan pendapatan tahunan mereka. Misalnya, peminjam seperti perawat & pengemudi memiliki pendapatan tahunan lebih dari 7 juta. Oleh karena itu, kita tahu bahwa pendapatan tahunan tampaknya tidak diberikan dengan benar oleh peminjam pada saat mengajukan pinjaman. Jadi kita akan mengabaikan variabel ini untuk membangun model prediktif. Mari kita mulai membuat beberapa variabel/fitur baru yang dapat memberi tahu kita lebih banyak cerita dari kumpulan data ini. Kemudian kita akan melakukan beberapa analisis pada fitur baru ini.
Feature Engineering
Di bagian ini, kita akan membuat variabel baru alias fitur yang akan membantu kita mendapatkan lebih banyak wawasan dari data. Fitur-fitur ini mungkin berguna sebagai prediktor baru untuk model.
Variabel Date
Tanggal penerbitan pinjaman dilambangkan dengan variabel issue_d dan tanggal angsuran pembayaran terakhir dilambangkan dengan variabel last_pymnt_d. Jadi, kita harus mengubahnya menjadi variabel tanggal. Karena hanya bulan dan tahun yang diberikan, kita akan menganggapnya sebagai hari pertama setiap bulan untuk analisis kita. Jadi mari kita buat variabel baru issue_dt & last_pymnt_dt sebagai tipe data tanggal.
lending <- lending %>%
mutate(issue_dt= as.Date(paste('01',issue_d,sep = "-"),'%d-%b-%Y'))
lending <- lending %>%
mutate(last_pymnt_dt= as.Date(paste('01',last_pymnt_d,sep = "-"),'%d-%b-%Y'))
lending <- as.data.table(lending)Karena tanggal pembayaran terakhir tidak akan terlalu penting untuk analisis/ pemodelan kita, kita tidak akan menggunakan variabel ini lebih lanjut. Kita akan lebih fokus pada variabel issue_dt.
Time-series analysis Menggunakan Issue Date
range(lending$issue_dt)#> [1] "2007-06-01" "2015-12-01"
Dataset yang digunakan dari tanggal Juni 2007 hingga Desember 2015, kurang lebih 8 tahun.
lending %>%
select(grade,issue_dt,int_rate) %>%
group_by(grade,issue_dt) %>%
summarise(int_rate_mean=mean(int_rate,na.rm = T)) %>%
ggplot(aes(issue_dt)) +
geom_line(aes(y=int_rate_mean),color="purple",size=1) +
ylab("Average Interest rate")+ xlab("Issue date") +
facet_wrap(~grade)Dapat diamati dari plot di atas bahwa tingkat bunga rata-rata untuk pinjaman berkualitas baik hampir stabil selama 8 tahun terakhir. Namun, untuk pinjaman berkualitas rendah, tingkat bunga rata-rata meningkat 2x. Oleh karena itu, stabilitas suku bunga tampaknya menjadi titik kuat untuk pinjaman berkualitas baik.
lending %>%
filter(defaulted==1) %>%
select(grade,issue_dt,defaulted) %>%
group_by(grade,issue_dt) %>%
summarise(defaulters=sum(as.numeric(as.character(defaulted)))) %>%
ggplot(aes(issue_dt)) +
geom_line(aes(y=log(defaulters,base=10)),color="orange",size=1) +
ylab("No. of Defaulters log-transformed")+ xlab("Issue date") +
facet_wrap(~grade)Di sini kita mengamati no. of defaulters untuk pinjaman berkualitas baik & menengah telah meningkat tajam dalam 8 tahun terakhir dibandingkan dengan pinjaman berkualitas rendah. Di sini saya telah menggunakan transformasi log pada no. of defaulters (sumbu y) untuk menghadirkan visualisasi yang tepat.
lending %>%
filter(defaulted==1) %>%
select(grade,issue_dt,defaulted) %>%
group_by(grade,issue_dt) %>%
summarise(defaulters=sum(as.numeric(as.character(defaulted)))) %>%
ggplot(aes(issue_dt)) +
geom_line(aes(y=defaulters),color="darkblue",size=1) +
ylab("No. of Defaulters")+ xlab("Issue date") +
facet_wrap(~grade)Di sini kita mengamati bahwa no. of defaulters meningkat tajam pada tahun 2014-2015.
lending %>%
select(grade,defaulted,issue_dt,funded_amnt) %>%
group_by(grade,defaulted,issue_dt) %>%
summarise(funded_amount=mean(funded_amnt,na.rm=T)) %>%
ggplot(aes(issue_dt)) +
geom_line(aes(y=funded_amount,colour=defaulted),size=1) +
ylab("Funded Amount")+ xlab("Issue date") +
facet_wrap(~grade)1.) Di sini kita melihat bahwa jumlah yang didanai telah meningkat dalam 10 tahun terakhir. Untuk kualitas baik variasi jumlahnya lebih sempit, tetapi untuk kualitas rendah variasi pinjaman sangat tinggi. 2.) Juga, untuk pinjaman berkualitas rendah, jumlah dana rata-rata telah meningkat 3x lipat dalam 10 tahun terakhir. 3.) Peminjam yang gagal bayar dan tidak gagal bayar menunjukkan perilaku yang sama.
Debt to Income Ratio (DTI)
Berikut ini merupakan satu variabel menarik dti yang dimana dapat didefinisikan sebagai ‘Rasio yang dihitung dengan menggunakan total pembayaran utang bulanan peminjam atas total kewajiban utang, tidak termasuk mortgage dan pinjaman LendingClub yang diminta, dibagi dengan pendapatan bulanan yang dilaporkan sendiri oleh peminjam.’
Kita asumsikan ini menunjukkan utang dibagi pendapatan. Kemudian
nilai yang lebih besar dari 1, akan menunjukkan pembayaran utang lebih
dari pendapatan bulanan.
Karena DTI adalah variabel kontinu, mari kita kategorikan ke dalam
kategori kecil untuk melihat pengaruhnya pada no. of defaulters.
lending <- as.data.table(lending %>%
mutate(dti_range_100 = as.factor(case_when(dti>=0 & dti<=10 ~ "dti_0-10",
dti>10 & dti<=20 ~ "dti_10-20",
dti>20 & dti<=30 ~ "dti_20-30",
dti>30 & dti<=40 ~ "dti_30-40",
dti>40 & dti<=50 ~ "dti_40-50",
dti>50 & dti<=60 ~ "dti_50-60",
dti>60 & dti<=70 ~ "dti_60-70",
dti>70 & dti<=80 ~ "dti_70-80",
dti>80 & dti<=90 ~ "dti_80-90",
dti>90 & dti<=100 ~ "dti_90-100",
dti>100 ~ "dti_100"))))
knitr::kable(lending %>%
group_by(dti_range_100) %>%
summarise(n()))| dti_range_100 | n() |
|---|---|
| dti_0-10 | 158103 |
| dti_10-20 | 375601 |
| dti_100 | 11 |
| dti_20-30 | 272685 |
| dti_30-40 | 80900 |
| dti_40-50 | 46 |
| dti_50-60 | 15 |
| dti_60-70 | 9 |
| dti_70-80 | 5 |
| dti_80-90 | 4 |
Sekarang mari kita periksa hubungan DTI dengan no. of defaulters.
ggplot(lending,
aes(dti_range_100)) +
geom_bar(aes(y=log(..count..))) +
facet_grid(.~defaulted) +
theme(axis.text.x=element_text( angle=30, vjust=.8, hjust=0.8)) +
ylab("No. of Defaulters log-transformed") +
xlab("DTI") +
scale_y_continuous(labels = num_format)Individu dengan DTI tinggi cenderung lebih sedikit gagal bayar daripada individu dengan DTI lebih rendah.
Insiden delinquency
Di sini kita memiliki satu lagi variabel menarik yang dapat membantu untuk memprediksi apakah suatu pinjaman akan gagal bayar atau tidak. Variabel delinq_2yrs menurut kamus data adalah ‘jumlah 30+ hari insiden tunggakan dalam file kredit peminjam selama 2 tahun terakhir’.
Pertama periksa apakah ada NA dalam data untuk variabel ini.
lending[is.na(delinq_2yrs),] %>%
summarise(n())#> n()
#> 1 29
Terdapat 29 data yang NA, kita akan mengganti NA ini dengan 0, karena itu berarti tidak ada insiden kenakalan yang ada dalam catatan peminjam.
lending[is.na(delinq_2yrs),delinq_2yrs:=0]Sekarang mari kita periksa hubungan incidences of delinquency dengan no. of defaulters.
ggplot(lending,
aes(delinq_2yrs)) +
geom_bar(aes(y=log(..count..))) +
facet_grid(.~defaulted) +
theme(axis.text.x=element_text( angle=30, vjust=.8, hjust=0.8)) +
scale_y_continuous(labels = num_format) Hanya non-defaulters yang memiliki lebih dari 15 insiden delinquency dalam catatan mereka. Hal ini cukup mencengangkan karena mereka yang melakukan insiden delinquency tertinggi adalah non-defaulters.
Variable Numeric
Ada banyak variabel numerik dalam kumpulan data. Tidak semua berguna untuk memprediksi apakah pinjaman akan gagal bayar. Oleh karena itu kita hanya akan mempertimbangkan variabel-variabel yang menunjukkan pola yang berbeda dalam hal defaulters dan non-defaulters.
Sebelum ini kita akan melakukan outlier treatment untuk variabel ini karena outlier memiliki dampak cascading dalam algoritma Machine Learning. Kita akan melakukan treatment menggunakan fungi awal yang sudah dibuat.
numeric_vars <- lending %>%
sapply(is.numeric) %>%
which() %>%
names()
#Hapus variabel yang tidak boleh diperlakukan seperti variabel jenis faktor
numeric_vars <- setdiff(numeric_vars,c("id","member_id","policy_code","dti","delinq_2yrs"))
#Outlier treatment untuk variabel numerik
loan_num_vars <- as.data.table(lending %>%
select(numeric_vars) %>%
mutate_all(.funs = outlier_treatment) %>%
gather(measure,values))
head(loan_num_vars)#> measure values
#> 1: loan_amnt 5000
#> 2: loan_amnt 3600
#> 3: loan_amnt 3600
#> 4: loan_amnt 10000
#> 5: loan_amnt 3600
#> 6: loan_amnt 5000
Kita telah memplot kepadatan untuk masing-masing variabel numerik untuk yang defaulters dan yang non-defaulters (tidak ditampilkan di sini). Semua plot serupa kecuali untuk variabel int_rate (suku bunga). Jumlah defaulters meningkat seiring dengan kenaikan suku bunga.
loan_num_vars[measure==numeric_vars[4]] %>%
mutate(defaulted=lending$defaulted) %>%
ggplot(aes(x=values,fill=defaulted,color=defaulted)) +
geom_density(alpha=0.3) +
xlab("Interest Rate")Prediction Modeling
Di Bagian ini kita akan menggunakan beberapa variabel lama dan baru sebagai prediktor untuk memprediksi target/variabel dependen default.
Karena kumpulan data ini sangat besar dan saya memiliki sumber daya perangkat keras yang terbatas, oleh karena itu saya akan menggunakan H2O.
H2O adalah platform ML sumber terbuka untuk analisis data besar. Ini diproduksi oleh perusahaan H2O.ai. Ini menggunakan pemrosesan dalam memori yang sangat skalabel untuk data besar tanpa menurunkan akurasi komputasi. Ini tersedia sebagai paket dalam R dan menyediakan UI web ‘H2O Flow’ untuk membangun model.
Pemilihan Prediktor
Kita kemudian akan mengubah variabel karakter yang sesuai menjadi faktor/variabel kategori.
model.vars <- c("int_rate","grade","emp_length","home_ownership","defaulted",
"purpose","dti_range_100","delinq_2yrs")
loan_final <- lending[,..model.vars]
loan_final <- loan_final %>%
mutate_if(is.character,as.factor) #convert char to factor type
sapply(loan_final, class)#> int_rate grade emp_length home_ownership defaulted
#> "numeric" "factor" "factor" "factor" "factor"
#> purpose dti_range_100 delinq_2yrs
#> "factor" "factor" "numeric"
Jadi dataset loan_final sudah siap, di mana kita dapat membangun/melatih/memvalidasi model klasifikasi.
Alasan menggunakan variable grade dipilih karena memiliki hubungan sebagai resiko yang akan terjadi pada nasabah.
Alasan menggunakan variable int_rate karena memiliki hubungan terbalik dengan grade dari nasabahnya.
Alasan menggunakan variable emp_length karena memiliki hubungan dengan target dari proses EDA yang dilakukan.
Alasan menggunakan variable home_ownership karena setelah proses EDA dapat dikatakan jenis kepemilikan dapat mempengaruhi target.
Alasan menggunakan variable purpose karena dari proses EDA dapat diketahui jenis mana saja yang mempengaruhi target.
Alasan menggunakan variable dti_range_100 karena Kita asumsikan ini menunjukkan utang dibagi pendapatan. Sehingga kita akan lihat pengaruh dari ratio tersebut.
Alasan menggunakan variable delinq_2yrs karena kita dapat melihat insiden delinquency atas peminjaman tersebut.
Untuk variable lain yang belum digunakan, karena belum ada hubungan signifikan terhadap targetnya.
Spliting / Partition Dataset
Kita akan terlebih dahulu mempartisi dataset ke dalam data train dan validation. Training set akan digunakan untuk membangun model klasifikasi dan Validation set akan digunakan untuk memvalidasi akurasi model.
Data train akan berisi 70% dari dataset dan sisanya untuk data Validasi.
train.ind <- createDataPartition(loan_final$defaulted,p = .7,list = F)
loan_train <- as.data.table(loan_final[train.ind,])
loan_validate <- as.data.table(loan_final[-train.ind,])
dim(loan_train); dim(loan_validate)#> [1] 621166 8
#> [1] 266213 8
Initialize H2O
Pertama-tama kita akan menginisialisasi H2O pada mesin kita. Karena laptop saya memiliki RAM 8GB, saya akan menggunakan pengaturan max_mem_size = “8g” saat inisialisasi. Karena Kaggle menyediakan RAM 17GB, saya akan menggunakan pengaturan max_mem_size = “15g” di sini.
Kita juga akan mengonversi set train dan validation ke tipe H2O yang setara. Setelah itu dapat digunakan dengan H2O untuk membangun dan memvalidasi model.
h2o.init(nthreads = -1,max_mem_size = "15g")#> Connection successful!
#>
#> R is connected to the H2O cluster:
#> H2O cluster uptime: 41 minutes 47 seconds
#> H2O cluster timezone: Asia/Jakarta
#> H2O data parsing timezone: UTC
#> H2O cluster version: 3.36.1.2
#> H2O cluster version age: 3 months
#> H2O cluster name: H2O_started_from_R_sarnimargaretha_gbf819
#> H2O cluster total nodes: 1
#> H2O cluster total memory: 12.78 GB
#> H2O cluster total cores: 8
#> H2O cluster allowed cores: 8
#> H2O cluster healthy: TRUE
#> H2O Connection ip: localhost
#> H2O Connection port: 54321
#> H2O Connection proxy: NA
#> H2O Internal Security: FALSE
#> R Version: R version 4.2.0 (2022-04-22)
train <- as.h2o(loan_train)#>
|
| | 0%
|
|======================================================================| 100%
validation <- as.h2o(loan_validate)#>
|
| | 0%
|
|======================================================================| 100%
colnames(train)#> [1] "int_rate" "grade" "emp_length" "home_ownership"
#> [5] "defaulted" "purpose" "dti_range_100" "delinq_2yrs"
Kolom 5 merupakan variable target, sisanya adalah variable prediktor.
Model yang akan digunakan Logistic Regression, Random Forest, Gradient Boosting Machine.
Logistic Regression menggunakan H2O
Kita akan menggunakan model Logistic Regression untuk memprediksi variabel target kita default karena ini adalah model klasifikasi yang paling umum digunakan.
model.glm <- h2o.glm(x=c(1:4,6:8), #prediktor
y=5, #target
training_frame = train,
validation_frame = validation,
nfolds = 5,
family = "binomial",
seed = 786,
link = "logit",
compute_p_values = T,
lambda = 0,
standardize = F,
remove_collinear_columns = T)#>
|
| | 0%
|
|== | 2%
|
|===================================== | 52%
|
|============================================================= | 87%
|
|======================================================================| 100%
Interpretation of Coefficients
knitr::kable(as.data.frame(model.glm@model$coefficients_table)) %>%
kable_styling() %>%
scroll_box(width = "500px", height = "200px")| names | coefficients | std_error | z_value | p_value | standardized_coefficients |
|---|---|---|---|---|---|
| Intercept | -11.0733948 | 31.9692762 | -0.3463762 | 0.7290600 | -6.9546628 |
| purpose.credit_card | -0.1476167 | 0.0529047 | -2.7902406 | 0.0052669 | -0.1476167 |
| purpose.debt_consolidation | -0.0480969 | 0.0520351 | -0.9243158 | 0.3553219 | -0.0480969 |
| purpose.educational | 1.5989269 | 0.1531402 | 10.4409355 | 0.0000000 | 1.5989269 |
| purpose.home_improvement | -0.0400466 | 0.0559281 | -0.7160375 | 0.4739682 | -0.0400466 |
| purpose.house | 0.0134896 | 0.0814904 | 0.1655359 | 0.8685222 | 0.0134896 |
| purpose.major_purchase | -0.0217833 | 0.0628265 | -0.3467209 | 0.7288010 | -0.0217833 |
| purpose.medical | 0.0410382 | 0.0681517 | 0.6021589 | 0.5470684 | 0.0410382 |
| purpose.moving | 0.0084481 | 0.0732676 | 0.1153041 | 0.9082041 | 0.0084481 |
| purpose.other | -0.0634026 | 0.0554743 | -1.1429177 | 0.2530728 | -0.0634026 |
| purpose.renewable_energy | 0.2474005 | 0.1658776 | 1.4914642 | 0.1358397 | 0.2474005 |
| purpose.small_business | 0.5066528 | 0.0610419 | 8.3000880 | 0.0000000 | 0.5066528 |
| purpose.vacation | -0.0486457 | 0.0808852 | -0.6014168 | 0.5475624 | -0.0486457 |
| purpose.wedding | 0.2294769 | 0.0930575 | 2.4659698 | 0.0136643 | 0.2294769 |
| emp_length.10+ years | -0.1266961 | 0.0211312 | -5.9956968 | 0.0000000 | -0.1266961 |
| emp_length.2 years | -0.0211312 | 0.0250166 | -0.8446878 | 0.3982852 | -0.0211312 |
| emp_length.3 years | -0.0002146 | 0.0255938 | -0.0083852 | 0.9933097 | -0.0002146 |
| emp_length.4 years | -0.0065933 | 0.0274622 | -0.2400862 | 0.8102634 | -0.0065933 |
| emp_length.5 years | 0.0377589 | 0.0267387 | 1.4121435 | 0.1579077 | 0.0377589 |
| emp_length.6 years | 0.1190330 | 0.0280532 | 4.2431217 | 0.0000220 | 0.1190330 |
| emp_length.7 years | 0.0223691 | 0.0283077 | 0.7902137 | 0.4294030 | 0.0223691 |
| emp_length.8 years | -0.0438579 | 0.0291810 | -1.5029576 | 0.1328500 | -0.0438579 |
| emp_length.9 years | -0.0131913 | 0.0311232 | -0.4238395 | 0.6716829 | -0.0131913 |
| emp_length.< 1 year | 0.0640121 | 0.0253027 | 2.5298507 | 0.0114111 | 0.0640121 |
| emp_length.n/a | 0.0906936 | 0.0283723 | 3.1965505 | 0.0013908 | 0.0906936 |
| dti_range_100.dti_10-20 | 0.0704302 | 0.0146964 | 4.7923423 | 0.0000016 | 0.0704302 |
| dti_range_100.dti_100 | -5.3587289 | 15.5685953 | -0.3442012 | 0.7306950 | -5.3587289 |
| dti_range_100.dti_20-30 | 0.1597213 | 0.0152110 | 10.5003495 | 0.0000000 | 0.1597213 |
| dti_range_100.dti_30-40 | -0.0729385 | 0.0206914 | -3.5250663 | 0.0004234 | -0.0729385 |
| dti_range_100.dti_40-50 | -5.2655100 | 6.4052430 | -0.8220625 | 0.4110413 | -5.2655100 |
| dti_range_100.dti_50-60 | 0.6427573 | 0.7824410 | 0.8214771 | 0.4113746 | 0.6427573 |
| dti_range_100.dti_60-70 | -5.4537898 | 21.2432554 | -0.2567304 | 0.7973869 | -5.4537898 |
| dti_range_100.dti_70-80 | -5.6138254 | 25.8638311 | -0.2170531 | 0.8281669 | -5.6138254 |
| dti_range_100.dti_80-90 | -5.1614686 | 45.2445428 | -0.1140794 | 0.9091749 | -5.1614686 |
| grade.B | -0.4001013 | 0.0269895 | -14.8243238 | 0.0000000 | -0.4001013 |
| grade.C | -0.9519330 | 0.0339946 | -28.0024602 | 0.0000000 | -0.9519330 |
| grade.D | -1.5284185 | 0.0439847 | -34.7488809 | 0.0000000 | -1.5284185 |
| grade.E | -2.1850208 | 0.0540953 | -40.3920573 | 0.0000000 | -2.1850208 |
| grade.F | -2.9379355 | 0.0681445 | -43.1133084 | 0.0000000 | -2.9379355 |
| grade.G | -3.3859130 | 0.0827535 | -40.9156352 | 0.0000000 | -3.3859130 |
| home_ownership.MORTGAGE | 5.0445337 | 31.9692117 | 0.1577935 | 0.8746195 | 5.0445337 |
| home_ownership.NONE | 5.9240108 | 31.9725533 | 0.1852843 | 0.8530061 | 5.9240108 |
| home_ownership.OTHER | 6.3774586 | 31.9700329 | 0.1994824 | 0.8418854 | 6.3774586 |
| home_ownership.OWN | 5.0925444 | 31.9692148 | 0.1592953 | 0.8734363 | 5.0925444 |
| home_ownership.RENT | 5.2624189 | 31.9692116 | 0.1646090 | 0.8692518 | 5.2624189 |
| int_rate | 0.3109918 | 0.0037587 | 82.7385795 | 0.0000000 | 1.3626280 |
| delinq_2yrs | -0.0035468 | 0.0055863 | -0.6349207 | 0.5254802 | -0.0030669 |
- Prediktor yang memiliki p-values lebih kecil dari 0,05, berpengaruh signifikan terhadap variabel target yaitu memiliki efek terhadap pinjaman yang gagal bayar.
- Contoh prediktor tersebut dengan efeknya adalah grade (-), sedangkan interest rate/ suku bunga (+), purpose like credit card and debt consolidation (-), employment length of 10+ years (-), DTI between 20-30 (+), dll.
- Ada banyak variabel yang secara statistik tidak berpengaruh signifikan terhadap pinjaman yang dicairkan yang memiliki p-value > 0,05. Variabel tersebut adalah home ownership, delinquency in past 2 years, dll.
- Beberapa hasil di atas akan mengejutkan kita, seperti dalam analisis kita mungkin telah mengamati efek positif dari variabel tersebut pada variabel target tetapi pada tabel koefisien di atas kita mungkin mendapatkan yang sebaliknya. Hal ini disebabkan fakta bahwa precitor signifikan lainnya akan memiliki efek yang jauh lebih besar pada variabel target, dan menggabungkan precitor kuat ini dengan variabel kita yang bersangkutan akan mengurangi/mengubah efek keseluruhan variabel kita pada variabel target.
Performance
Mari hitung metrik performace dari model.glm kita pada dataset training dan validation.
model.glm@model$validation_metrics#> H2OBinomialMetrics: glm
#> ** Reported on validation data. **
#>
#> MSE: 0.06759641
#> RMSE: 0.2599931
#> LogLoss: 0.2508285
#> Mean Per-Class Error: 0.3781707
#> AUC: 0.7016084
#> AUCPR: 0.1539418
#> Gini: 0.4032169
#> R^2: 0.03723434
#> Residual Deviance: 133547.6
#> AIC: 133641.6
#>
#> Confusion Matrix (vertical: actual; across: predicted) for F1-optimal threshold:
#> 0 1 Error Rate
#> 0 202398 43587 0.177194 =43587/245985
#> 1 11715 8513 0.579148 =11715/20228
#> Totals 214113 52100 0.207736 =55302/266213
#>
#> Maximum Metrics: Maximum metrics at their respective thresholds
#> metric threshold value idx
#> 1 max f1 0.110386 0.235400 206
#> 2 max f2 0.076080 0.363444 267
#> 3 max f0point5 0.163658 0.203473 142
#> 4 max accuracy 0.626424 0.924016 0
#> 5 max precision 0.626424 0.500000 0
#> 6 max recall 0.001488 1.000000 399
#> 7 max specificity 0.626424 0.999996 0
#> 8 max absolute_mcc 0.096967 0.166167 228
#> 9 max min_per_class_accuracy 0.078261 0.644997 263
#> 10 max mean_per_class_accuracy 0.077120 0.648224 265
#> 11 max tns 0.626424 245984.000000 0
#> 12 max fns 0.626424 20227.000000 0
#> 13 max fps 0.001488 245985.000000 399
#> 14 max tps 0.001488 20228.000000 399
#> 15 max tnr 0.626424 0.999996 0
#> 16 max fnr 0.626424 0.999951 0
#> 17 max fpr 0.001488 1.000000 399
#> 18 max tpr 0.001488 1.000000 399
#>
#> Gains/Lift Table: Extract with `h2o.gainsLift(<model>, <data>)` or `h2o.gainsLift(<model>, valid=<T/F>, xval=<T/F>)`
plot(h2o.performance(model.glm, validation),
type='roc')h2o.confusionMatrix(model.glm,
thresholds=.1,
newdata=validation)#> Confusion Matrix (vertical: actual; across: predicted) @ threshold = 0.100123355919231:
#> 0 1 Error Rate
#> 0 192011 53974 0.219420 =53974/245985
#> 1 10423 9805 0.515276 =10423/20228
#> Totals 202434 63779 0.241900 =64397/266213
Observasi:
- Area Di Bawah Kurva (AUC): 0,70
- Kurva ROC diplot untuk setiap threshold. Kurva jauh di atas diagonal yang berarti model kami lebih baik dalam prediksi daripada peluang acak (>50%).
- Karena dataset kita tidak seimbang yaitu no. of defaulters (1) sangat kurang dibandingkan dengan yang non-defaulters (0), kita akan memilih ambang yang lebih kecil, sehingga lebih banyak tidak pengamatan untuk diklasifikasikan sebagai default.
- Akurasi bukanlah ukuran yang benar untuk memeriksa kinerja model, kita akan lebih fokus pada Precision and Sensitivity (Recall) karena kita ingin memeriksa berapa banyak defaulted loans (1) yang diprediksi dengan benar.
- Dengan memilih threshold 0.1, kita mendapatkan Precision (TP/TP+FP) = (9784/63630) atau 15.4% dan Sensitivity (TP/TP+FN) = (9784/20228) atau 48.4%. Metrik ini bersama dengan AUC akan digunakan untuk membandingkan model kita yang berbeda.
Random Forest
Model klasifikasi hebat lainnya yang memberikan prediksi lebih baik dan tidak melebih-lebihkan data.
model.rf <- h2o.randomForest(x=c(1:4,6:8),
y=5,
training_frame = train,
validation_frame = validation,
ntrees = 300,
nbins_cats = 50,
seed = 786,
categorical_encoding = "Enum")#>
|
| | 0%
|
|= | 1%
|
|= | 2%
|
|== | 2%
|
|== | 3%
|
|=== | 4%
|
|=== | 5%
|
|==== | 5%
|
|==== | 6%
|
|===== | 7%
|
|===== | 8%
|
|====== | 8%
|
|====== | 9%
|
|======= | 9%
|
|======= | 10%
|
|======= | 11%
|
|======== | 11%
|
|======== | 12%
|
|========= | 13%
|
|=========== | 15%
|
|============ | 17%
|
|============ | 18%
|
|============= | 18%
|
|============= | 19%
|
|============== | 20%
|
|=============== | 21%
|
|================ | 22%
|
|================ | 23%
|
|================= | 24%
|
|================= | 25%
|
|================== | 25%
|
|================== | 26%
|
|=================== | 27%
|
|==================== | 28%
|
|==================== | 29%
|
|===================== | 29%
|
|===================== | 30%
|
|===================== | 31%
|
|====================== | 31%
|
|====================== | 32%
|
|======================= | 33%
|
|======================== | 34%
|
|======================== | 35%
|
|========================= | 35%
|
|========================= | 36%
|
|========================== | 37%
|
|=========================== | 39%
|
|============================ | 41%
|
|============================= | 41%
|
|============================= | 42%
|
|============================== | 42%
|
|============================== | 43%
|
|=============================== | 44%
|
|=============================== | 45%
|
|================================ | 45%
|
|================================ | 46%
|
|================================= | 47%
|
|================================== | 48%
|
|================================== | 49%
|
|=================================== | 49%
|
|=================================== | 50%
|
|=================================== | 51%
|
|==================================== | 51%
|
|==================================== | 52%
|
|===================================== | 52%
|
|===================================== | 53%
|
|====================================== | 54%
|
|====================================== | 55%
|
|======================================= | 55%
|
|======================================= | 56%
|
|======================================== | 57%
|
|======================================== | 58%
|
|========================================= | 58%
|
|========================================= | 59%
|
|========================================== | 59%
|
|========================================== | 60%
|
|=========================================== | 61%
|
|=========================================== | 62%
|
|============================================ | 62%
|
|============================================ | 63%
|
|============================================= | 64%
|
|============================================== | 65%
|
|============================================== | 66%
|
|=============================================== | 67%
|
|=============================================== | 68%
|
|================================================ | 68%
|
|================================================ | 69%
|
|================================================= | 69%
|
|================================================= | 70%
|
|================================================= | 71%
|
|================================================== | 71%
|
|================================================== | 72%
|
|=================================================== | 72%
|
|=================================================== | 73%
|
|==================================================== | 74%
|
|==================================================== | 75%
|
|===================================================== | 75%
|
|===================================================== | 76%
|
|====================================================== | 77%
|
|====================================================== | 78%
|
|======================================================= | 78%
|
|======================================================= | 79%
|
|======================================================== | 79%
|
|======================================================== | 80%
|
|========================================================= | 81%
|
|========================================================= | 82%
|
|========================================================== | 82%
|
|========================================================== | 83%
|
|=========================================================== | 84%
|
|============================================================ | 85%
|
|============================================================ | 86%
|
|============================================================= | 87%
|
|============================================================= | 88%
|
|============================================================== | 88%
|
|============================================================== | 89%
|
|=============================================================== | 89%
|
|=============================================================== | 90%
|
|=============================================================== | 91%
|
|================================================================ | 91%
|
|================================================================ | 92%
|
|================================================================= | 92%
|
|================================================================= | 93%
|
|================================================================== | 94%
|
|================================================================== | 95%
|
|=================================================================== | 95%
|
|=================================================================== | 96%
|
|===================================================================== | 98%
|
|===================================================================== | 99%
|
|======================================================================| 100%
Variable Importance
Mari kita periksa variabel/prediktor mana yang paling penting dalam model RF ini.
h2o.varimp_plot(model.rf)Kita dapat melihat bahwa Interest Rate memainkan peran paling penting dalam model RF dan paling tidak menjadi variabel home ownership.
Biasanya, RF lebih mementingkan variabel kontinu saat splitting tree.
Performance
model.rf@model$validation_metrics#> H2OBinomialMetrics: drf
#> ** Reported on validation data. **
#>
#> MSE: 0.06733002
#> RMSE: 0.2594803
#> LogLoss: 0.2475767
#> Mean Per-Class Error: 0.371018
#> AUC: 0.7209705
#> AUCPR: 0.163358
#> Gini: 0.4419411
#> R^2: 0.04102852
#>
#> Confusion Matrix (vertical: actual; across: predicted) for F1-optimal threshold:
#> 0 1 Error Rate
#> 0 203728 42257 0.171787 =42257/245985
#> 1 11535 8693 0.570249 =11535/20228
#> Totals 215263 50950 0.202064 =53792/266213
#>
#> Maximum Metrics: Maximum metrics at their respective thresholds
#> metric threshold value idx
#> 1 max f1 0.119072 0.244261 219
#> 2 max f2 0.068376 0.379394 291
#> 3 max f0point5 0.169602 0.207014 166
#> 4 max accuracy 0.684526 0.924019 1
#> 5 max precision 0.684526 0.600000 1
#> 6 max recall 0.004119 1.000000 399
#> 7 max specificity 0.710102 0.999996 0
#> 8 max absolute_mcc 0.087235 0.180234 263
#> 9 max min_per_class_accuracy 0.079578 0.660813 274
#> 10 max mean_per_class_accuracy 0.068376 0.663913 291
#> 11 max tns 0.710102 245984.000000 0
#> 12 max fns 0.710102 20228.000000 0
#> 13 max fps 0.004119 245985.000000 399
#> 14 max tps 0.004119 20228.000000 399
#> 15 max tnr 0.710102 0.999996 0
#> 16 max fnr 0.710102 1.000000 0
#> 17 max fpr 0.004119 1.000000 399
#> 18 max tpr 0.004119 1.000000 399
#>
#> Gains/Lift Table: Extract with `h2o.gainsLift(<model>, <data>)` or `h2o.gainsLift(<model>, valid=<T/F>, xval=<T/F>)`
plot(h2o.performance(model.rf,validation),
type='roc')h2o.confusionMatrix(model.rf,
thresholds=.1,
newdata=validation)#> Confusion Matrix (vertical: actual; across: predicted) @ threshold = 0.099937063886387:
#> 0 1 Error Rate
#> 0 187779 58206 0.236624 =58206/245985
#> 1 9519 10709 0.470585 =9519/20228
#> Totals 197298 68915 0.254402 =67725/266213
Observasi:
- Area Di Bawah Kurva (AUC): 0,72
- Kurva ROC diplot untuk setiap threshold. Kurva jauh di atas diagonal yang berarti model kita lebih baik dalam prediksi daripada peluang acak (>50%).
- Dengan memilih threshold 0.1, kita mendapatkan Precision (TP/TP+FP) = (10945/70233) atau 15.6% dan Sensitivity (TP/TP+FN) = (10945/20228) atau 54.1%.
Gradient Boosting Machine
Model hebat lainnya untuk mencapai akurasi yang lebih tinggi.
model.gbm <- h2o.gbm(x=c(1:4,6:8),
y=5,
training_frame = train,
validation_frame = validation,
ntrees = 300,
nbins_cats = 50,
seed = 786,
categorical_encoding = "Enum")#>
|
| | 0%
|
|= | 2%
|
|== | 3%
|
|=== | 4%
|
|==== | 5%
|
|===== | 8%
|
|======== | 11%
|
|=========== | 16%
|
|============= | 18%
|
|======================================================================| 100%
Variable Importance
Mari kita periksa variabel/prediktor mana yang paling penting dalam model GBM ini.
h2o.varimp_plot(model.gbm)Kita dapat melihat bahwa Suku bunga memainkan peran paling penting dalam model RF dan paling tidak menjadi variabel delinq_2tahun.
Performance
model.gbm@model$validation_metrics#> H2OBinomialMetrics: gbm
#> ** Reported on validation data. **
#>
#> MSE: 0.06654657
#> RMSE: 0.2579662
#> LogLoss: 0.244615
#> Mean Per-Class Error: 0.3560027
#> AUC: 0.7310225
#> AUCPR: 0.1772197
#> Gini: 0.4620451
#> R^2: 0.05218713
#>
#> Confusion Matrix (vertical: actual; across: predicted) for F1-optimal threshold:
#> 0 1 Error Rate
#> 0 202554 43431 0.176560 =43431/245985
#> 1 10831 9397 0.535446 =10831/20228
#> Totals 213385 52828 0.203829 =54262/266213
#>
#> Maximum Metrics: Maximum metrics at their respective thresholds
#> metric threshold value idx
#> 1 max f1 0.112770 0.257255 202
#> 2 max f2 0.082827 0.383966 253
#> 3 max f0point5 0.168762 0.225958 132
#> 4 max accuracy 0.635060 0.924019 0
#> 5 max precision 0.635060 1.000000 0
#> 6 max recall 0.008915 1.000000 398
#> 7 max specificity 0.635060 1.000000 0
#> 8 max absolute_mcc 0.110615 0.191819 206
#> 9 max min_per_class_accuracy 0.084853 0.665958 249
#> 10 max mean_per_class_accuracy 0.081389 0.668356 256
#> 11 max tns 0.635060 245985.000000 0
#> 12 max fns 0.635060 20227.000000 0
#> 13 max fps 0.008023 245985.000000 399
#> 14 max tps 0.008915 20228.000000 398
#> 15 max tnr 0.635060 1.000000 0
#> 16 max fnr 0.635060 0.999951 0
#> 17 max fpr 0.008023 1.000000 399
#> 18 max tpr 0.008915 1.000000 398
#>
#> Gains/Lift Table: Extract with `h2o.gainsLift(<model>, <data>)` or `h2o.gainsLift(<model>, valid=<T/F>, xval=<T/F>)`
plot(h2o.performance(model.gbm,validation),
type='roc')h2o.confusionMatrix(model.gbm,
thresholds=.1,
newdata=validation)#> Confusion Matrix (vertical: actual; across: predicted) @ threshold = 0.100259719565892:
#> 0 1 Error Rate
#> 0 188502 57483 0.233685 =57483/245985
#> 1 9144 11084 0.452047 =9144/20228
#> Totals 197646 68567 0.250277 =66627/266213
Observasi:
- Area Di Bawah Kurva (AUC): 0,732
- Kurva ROC diplot untuk setiap threshold. Kurva jauh di atas diagonal yang berarti model kami lebih baik dalam prediksi daripada peluang acak (>50%).
- Dengan memilih threshold 0.1, kita mendapatkan Precision (TP/TP+FP) = (10994/67580) atau 16.3% dan Sensitivity (TP/TP+FN) = (10994/20228) atau 54.4%.
Conclusion
Dari 3 model, GBM memiliki Precision and Sensitivity for Validation set terbaik. Oleh karena itu kita akan memilih model.gbm sebagai model akhir kita dan akan diterapkan pada kumpulan data uji untuk memeriksa seberapa bagusnya pada data yang tidak terlihat.
Prediction Test
test_orig <- fread("data input/Lending Club/lc_2016_2017.csv",sep=",",header = T,stringsAsFactors = F,data.table = T)knitr::kable(as.data.frame(colnames(test_orig))) %>%
kable_styling() %>%
scroll_box(width="200px",height = "200px")| colnames(test_orig) |
|---|
| id |
| member_id |
| loan_amnt |
| funded_amnt |
| funded_amnt_inv |
| term |
| int_rate |
| installment |
| grade |
| sub_grade |
| emp_title |
| emp_length |
| home_ownership |
| annual_inc |
| verification_status |
| issue_d |
| loan_status |
| pymnt_plan |
| desc |
| purpose |
| title |
| zip_code |
| addr_state |
| dti |
| delinq_2yrs |
| earliest_cr_line |
| inq_last_6mths |
| mths_since_last_delinq |
| mths_since_last_record |
| open_acc |
| pub_rec |
| revol_bal |
| revol_util |
| total_acc |
| initial_list_status |
| out_prncp |
| out_prncp_inv |
| total_pymnt |
| total_pymnt_inv |
| total_rec_prncp |
| total_rec_int |
| total_rec_late_fee |
| recoveries |
| collection_recovery_fee |
| last_pymnt_d |
| last_pymnt_amnt |
| next_pymnt_d |
| last_credit_pull_d |
| collections_12_mths_ex_med |
| mths_since_last_major_derog |
| policy_code |
| application_type |
| annual_inc_joint |
| dti_joint |
| verification_status_joint |
| acc_now_delinq |
| tot_coll_amt |
| tot_cur_bal |
| open_acc_6m |
| open_il_12m |
| open_il_24m |
| mths_since_rcnt_il |
| total_bal_il |
| il_util |
| open_rv_12m |
| open_rv_24m |
| max_bal_bc |
| all_util |
| total_rev_hi_lim |
| inq_fi |
| total_cu_tl |
| inq_last_12m |
Karena kita hanya tertarik pada variabel yang dapat digunakan dalam model kita, kita hanya akan mempertahankan variabel tersebut dalam kumpulan data test.
retain_vars <- c("int_rate","grade","emp_length","home_ownership",
"purpose","delinq_2yrs","loan_status","dti","issue_d")
test <- test_orig %>%
select(one_of(retain_vars))Feature Engineering
Pada bagian ini kita akan melakukan Feature Engineering untuk membuat fitur baru seperti yang telah kita buat di data train dan yang dapat digunakan untuk pemodelan. Kita juga akan melakukan transformasi seperti imputasi seperti yang telah kita lakukan sebelumnya di data train.
test <- test %>%
mutate(issue_dt= as.Date(paste('01',issue_d,sep = "-"),'%d-%b-%Y'))
test <- as.data.table(test)
max(test$issue_dt,na.rm = T); #> [1] "2017-09-01"
min(test$issue_dt,na.rm = T)#> [1] "2016-01-01"
distinct(test,loan_status)#> loan_status
#> 1: Current
#> 2: Fully Paid
#> 3: In Grace Period
#> 4: Late (31-120 days)
#> 5: Late (16-30 days)
#> 6: Charged Off
#> 7: Default
test[loan_status %like% "(.*)?Fully Paid",loan_status:="Fully Paid"]
test[loan_status %like% "(.*)?Charged Off",loan_status:="Charged Off"]
test[!(loan_status %in% c("Fully Paid","Current","Issued")),loan_status:="Default"]
test<-test %>% mutate(defaulted=ifelse(loan_status=="Default",1,0))
test<-data.table(test)
test$defaulted<- as.factor(test$defaulted)
sapply(lapply(test,is.na),sum)#> int_rate grade emp_length home_ownership purpose
#> 0 0 0 0 0
#> delinq_2yrs loan_status dti issue_d issue_dt
#> 0 0 355 0 0
#> defaulted
#> 0
#impute NA with 0
test[is.na(dti) | dti<0,dti:=0]
test<-as.data.table(test%>%mutate(dti_range_100=as.factor(
case_when(dti>=0 & dti<=10 ~ "dti_0-10",
dti>10 & dti<=20 ~ "dti_10-20",
dti>20 & dti<=30 ~ "dti_20-30",
dti>30 & dti<=40 ~ "dti_30-40",
dti>40 & dti<=50 ~ "dti_40-50",
dti>50 & dti<=60 ~ "dti_50-60",
dti>60 & dti<=70 ~ "dti_60-70",
dti>70 & dti<=80 ~ "dti_70-80",
dti>80 & dti<=90~"dti_80-90",
dti>90 & dti<=100 ~ "dti_90-100",
dti>100 ~ "dti_100",
is.na(dti) | dti<0 ~ "dti_0"))))
#remove redundant variables
test$issue_d<-NULL
test$dti<-NULL
test$loan_status<-NULL
#rearranging variables as training set as we have used column numbers
#for predictors and target variables while building models
test<-test[,..model.vars]
colnames(test)#> [1] "int_rate" "grade" "emp_length" "home_ownership"
#> [5] "defaulted" "purpose" "dti_range_100" "delinq_2yrs"
Sekarang mari kita lihat seperti apa kumpulan data akhir kita.
knitr::kable(head(test))| int_rate | grade | emp_length | home_ownership | defaulted | purpose | dti_range_100 | delinq_2yrs |
|---|---|---|---|---|---|---|---|
| 12.62 | C | OWN | 0 | credit_card | dti_20-30 | 0 | |
| 12.62 | C | 10+ years | MORTGAGE | 0 | debt_consolidation | dti_20-30 | 0 |
| 15.05 | C | 7 years | MORTGAGE | 0 | home_improvement | dti_0-10 | 0 |
| 9.44 | B | 10+ years | RENT | 0 | car | dti_20-30 | 0 |
| 11.99 | B | 10+ years | MORTGAGE | 0 | debt_consolidation | dti_0-10 | 1 |
| 9.44 | B | 10+ years | MORTGAGE | 0 | debt_consolidation | dti_10-20 | 0 |
Predicting Defaulted Loans
Seperti yang diamati sebelumnya, GBM memberikan hasil terbaik pada data validasi kita Oleh karena itu kita akan menerapkan GBM pada kumpulan data test untuk memprediksi pinjaman yang gagal bayar.
test.h2o<-as.h2o(test)#>
|
| | 0%
|
|======================================================================| 100%
pred.gbm<-h2o.predict(model.gbm,test.h2o)#>
|
| | 0%
|
|======================================================================| 100%
knitr::kable(head(pred.gbm))| predict | p0 | p1 |
|---|---|---|
| 0 | 0.9644712 | 0.0355288 |
| 0 | 0.9699410 | 0.0300590 |
| 0 | 0.9099274 | 0.0900726 |
| 0 | 0.9662202 | 0.0337798 |
| 0 | 0.9432951 | 0.0567049 |
| 0 | 0.9711942 | 0.0288058 |
pred2<-as.data.table(ifelse(pred.gbm$p1>.1,1,0))
table(test$defaulted,pred2$C1)#>
#> 0 1
#> 0 524727 171514
#> 1 35182 27915
Saat membandingkan nilai default aktual dengan nilai prediksi, kita mendapatkan Sensitivitas (TP/TP+FP) = (28630/203929) atau 14.0% dan Presisi (TP/TP+FN) = (28630/63097) atau 45.4%.
Final Conclusion
Kita cukup banyak membahas semua kemungkinan analisis yang bisa kita lakukan pada kumpulan data ini. Karena kumpulan data yang sangat besar ini membutuhkan sumber daya sistem yang lebih tinggi. Kita telah mengatasi tantangan ini melalui penggunaan H2O. Saya ingin menggunakan algoritma XGBoost ML, tetapi sayangnya itu tidak berfungsi di mesin Windows. Ini mungkin memberikan hasil yang lebih baik jika digunakan. Jadi ini adalah kesempatan bagi Anda semua untuk mencoba dan menemukan hasil.