Project ini adalah salah satu project yang terdapat di DQLab dan merupakan bagian dari proses pembelajaran saya di platform DQLab. DQLab adalah salah satu platform kursus data science di Indonesia. Mentor dalam project ini adalah Mr. Said Al Afghani, seorang Assistant Manager II di PT. Pegadaian (Persero).
Website DQLab: https://academy.dqlab.id/
Perusahaan Alembert merupakan perusahaan yang bergerak di bidang layanan pinjaman usaha bagi sektor UMKM. Karena adanya pandemik ini, perusahaan berusaha memberikan pelayanan berupa keringanan pinjaman bagi pelanggan yang disebut sebagai rekomendasi tindak lanjut. Pemberian rekomendasi tindak lanjut pada pelanggan ini didasari pada kriteria tertentu, dan perlu ditentukan faktor-faktor apa saja yang berpengaruh sehingga pelanggan mendapatkan treatment tertentu yang masuk dalam rekomendasi tindak lanjut program dari perusahaan.
Tujuan Project: Klasifikasi nasabah yang akan dimasukkan pada rekomendasi tindak lanjut. Pada kelas target rekomendasi tindak lanjut ini sendiri terdiri dari beberapa kelas seperti restrukturisasi dan angsuran biasa.
Model: Regresi multinomial.
Referensi model (Ref): Kelas pada rekomendasi tindak lanjut yang memiliki banyak pelanggan.
Data: Data yang digunakan terdiri dari 1000 baris.
Tujuan Pembelajaran dari Project ini:
Memahami dasar-dasar sintak R untuk keperluan statistika dasar dan dasar-dasar machine learning.
Memberikan gambaran secara umum pemodelan dengan menggunakan R.
Catatan : Apabila ingin melakukan eksplorasi pada R yang terpasang pada komputer, dapat ditambahkan perintah setwd(“path file tempat kamu bekerja”) pada tiap baris pertama editor di R-Studio kamu.
Hal yang pertama dilakukan adalah membaca dataset yang telah dipersiapkan. Dengan menggunakan fungsi bawaan R bacalah dataset yang berformat csv tersebut yang bernama “https://storage.googleapis.com/dqlab-dataset/project.csv”.
data = read.csv("https://storage.googleapis.com/dqlab-dataset/project.csv")
Setelah data berhasil di import, cobalah kamu untuk menginspeksi dataset dengan jalan
Melihat 6 baris pertama data tersebut, apa saja yang ditunjukkannya dan
Tampilkan tipe data dari setiap kolom.
# Enam baris teratas data
head(data)
## X NAMA_NASABAH NOMOR_KONTRAK DOMISILI KARAKTER
## 1 0 YOLI SEPINA NAINGGOLAN 0 MASIH TETAP KOOPERATIF
## 2 1 ERWIN NASUTION 1 MASIH TETAP TIDAK KOOPERATIF
## 3 2 HUSIN 2 MASIH TETAP TIDAK KOOPERATIF
## 4 3 HARITSYAH 3 PINDAH PERMANEN KOOPERATIF
## 5 4 HARIRI PANGGABEAN 4 MASIH TETAP TIDAK KOOPERATIF
## 6 5 JHON PREDDY HUTABARAT 5 MASIH TETAP KOOPERATIF
## PROFESI KONDISI_USAHA KONDISI_JAMINAN STATUS PRODUK PYD
## 1 IBU RUMAH TANGGA 2 Baik 2 3 30000000
## 2 NELAYAN 3 Rusak 8 3 10000000
## 3 LAINNYA 3 Baik 8 3 60000000
## 4 PNS 1 Rusak 7 3 90000000
## 5 WIRAUSAHA / PEDAGANG 1 Baik 8 3 150000000
## 6 WIRAUSAHA / PEDAGANG 1 Baik 7 3 40000000
## TENOR OSL KEWAJIBAN KOLEKTIBILITAS COUNT_SURVEY
## 1 24 28750000 4896841 DALAM PENGAWASAN KHUSUS 1
## 2 12 2040693 0 MACET 1
## 3 24 0 0 MACET 1
## 4 18 0 0 MACET 1
## 5 18 19844807 0 MACET 1
## 6 36 27298726 2208516 DALAM PENGAWASAN KHUSUS 1
## REKOMENDASI_TINDAK_LANJUT
## 1 Angsuran Biasa
## 2 Penarikan
## 3 Penarikan
## 4 Angsuran Biasa
## 5 Penarikan
## 6 Restrukturisasi
# Tampilkan tipe data setiap kolomnya
str(data)
## 'data.frame': 1000 obs. of 17 variables:
## $ X : int 0 1 2 3 4 5 6 7 8 9 ...
## $ NAMA_NASABAH : chr "YOLI SEPINA NAINGGOLAN" "ERWIN NASUTION" "HUSIN" "HARITSYAH" ...
## $ NOMOR_KONTRAK : int 0 1 2 3 4 5 6 7 8 9 ...
## $ DOMISILI : chr "MASIH TETAP" "MASIH TETAP" "MASIH TETAP" "PINDAH PERMANEN" ...
## $ KARAKTER : chr "KOOPERATIF" "TIDAK KOOPERATIF" "TIDAK KOOPERATIF" "KOOPERATIF" ...
## $ PROFESI : chr "IBU RUMAH TANGGA" "NELAYAN" "LAINNYA" "PNS" ...
## $ KONDISI_USAHA : int 2 3 3 1 1 1 3 2 2 3 ...
## $ KONDISI_JAMINAN : chr "Baik" "Rusak" "Baik" "Rusak" ...
## $ STATUS : int 2 8 8 7 8 7 7 7 7 3 ...
## $ PRODUK : int 3 3 3 3 3 3 3 3 3 3 ...
## $ PYD : int 30000000 10000000 60000000 90000000 150000000 40000000 60000000 7500000 45000000 50000000 ...
## $ TENOR : int 24 12 24 18 18 36 36 4 24 36 ...
## $ OSL : int 28750000 2040693 0 0 19844807 27298726 19999200 7500000 45000000 6944100 ...
## $ KEWAJIBAN : int 4896841 0 0 0 0 2208516 6946592 0 0 7730984 ...
## $ KOLEKTIBILITAS : chr "DALAM PENGAWASAN KHUSUS" "MACET" "MACET" "MACET" ...
## $ COUNT_SURVEY : int 1 1 1 1 1 1 2 2 1 1 ...
## $ REKOMENDASI_TINDAK_LANJUT: chr "Angsuran Biasa" "Penarikan" "Penarikan" "Angsuran Biasa" ...
Melalui R kita dapat menampilkan statistik deskriptif pada data yang dimiliki. Jika diinginkan lebih spesifik maka dapat dilakukan pada kolom tertentu pada tabel data yang kita punya. Tentunya kita dapat menggunakan accessor $ untuk memilih kolom yang diinginkan dari data.
summary(data)
## X NAMA_NASABAH NOMOR_KONTRAK DOMISILI
## Min. : 0.0 Length:1000 Min. : 0.0 Length:1000
## 1st Qu.:249.8 Class :character 1st Qu.:249.8 Class :character
## Median :499.5 Mode :character Median :499.5 Mode :character
## Mean :499.5 Mean :499.5
## 3rd Qu.:749.2 3rd Qu.:749.2
## Max. :999.0 Max. :999.0
## KARAKTER PROFESI KONDISI_USAHA KONDISI_JAMINAN
## Length:1000 Length:1000 Min. :1.000 Length:1000
## Class :character Class :character 1st Qu.:2.000 Class :character
## Mode :character Mode :character Median :2.000 Mode :character
## Mean :2.273
## 3rd Qu.:3.000
## Max. :3.000
## STATUS PRODUK PYD TENOR
## Min. :2.000 Min. : 3.00 Min. : 500000 Min. : 3.00
## 1st Qu.:3.000 1st Qu.: 3.00 1st Qu.: 8000000 1st Qu.:12.00
## Median :7.000 Median : 3.00 Median : 15000000 Median :18.00
## Mean :5.379 Mean :12.45 Mean : 38537508 Mean :20.75
## 3rd Qu.:7.000 3rd Qu.: 7.00 3rd Qu.: 50000000 3rd Qu.:24.00
## Max. :8.000 Max. :77.00 Max. :500000000 Max. :48.00
## OSL KEWAJIBAN KOLEKTIBILITAS COUNT_SURVEY
## Min. : 0 Min. : 0 Length:1000 Min. :1.000
## 1st Qu.: 3999950 1st Qu.: 687487 Class :character 1st Qu.:1.000
## Median : 8687350 Median : 2008974 Mode :character Median :1.000
## Mean : 26562373 Mean : 5663981 Mean :1.036
## 3rd Qu.: 32082900 3rd Qu.: 4823198 3rd Qu.:1.000
## Max. :440932336 Max. :400900000 Max. :2.000
## REKOMENDASI_TINDAK_LANJUT
## Length:1000
## Class :character
## Mode :character
##
##
##
Pada data yang kamu miliki, sebenarnya kamu tidak memerlukan nama pelanggan untuk diberikan rekomendasi. Atau dengan kata lain penanda pelanggan untuk diberikan rekomendasi cukup dengan melihat no_kontrak pelanggan itu saja.
Tugas: Hapuslah kolom “X” dan nama nasabah pada data yang kamu miliki dan cetak kembali nama kolom yang tersedia pada data.
data_reduce = data[-c(1,2)]
colnames(data_reduce)
## [1] "NOMOR_KONTRAK" "DOMISILI"
## [3] "KARAKTER" "PROFESI"
## [5] "KONDISI_USAHA" "KONDISI_JAMINAN"
## [7] "STATUS" "PRODUK"
## [9] "PYD" "TENOR"
## [11] "OSL" "KEWAJIBAN"
## [13] "KOLEKTIBILITAS" "COUNT_SURVEY"
## [15] "REKOMENDASI_TINDAK_LANJUT"
Seperti yang diketahui ketika data ditarik dari suatu sumber terkadang ada kondisi tipe data tidak dengan tepat direpresentasikan. Misalkan semua record/baris pada suatu kolom berisi seharusnya data numerik akan tetapi disajikan didalam suatu karakter angka.
R sendiri memiliki fungsi sapply yang dapat digunakan untuk mengkoversi tipe data. Dalam hal ini fungsi sapply menerima input/argumen fungsi berupa list, vector, atau data frame dan mengembalikan/menghasilkan output berupa vector atau matrix.
Cobalah untuk meninjau kembali kolom “PRODUK”, “PYD”, “TENOR”, dan “OSL” apakah perlu dikonversikan menjadi bertipe numerik atau tidak.
Jika tidak, kamu dapat menjawab dengan mengetikkan FALSE di code editor.
Tetapi, jika perlu dirubah maka ketikkanlah perintah berikut:
data_reduce[, 8:11] = sappy(data_reduce[, 8:11], as.numeric)
FALSE
## [1] FALSE
data_kategorik = data_reduce[, c("KONDISI_USAHA","KONDISI_JAMINAN","REKOMENDASI_TINDAK_LANJUT")]
data_reduce$REKOMENDASI_TINDAK_LANJUT = as.factor(data_reduce$REKOMENDASI_TINDAK_LANJUT)
chisq.test(data_kategorik$KONDISI_USAHA, data_kategorik$REKOMENDASI_TINDAK_LANJUT)
## Warning in chisq.test(data_kategorik$KONDISI_USAHA,
## data_kategorik$REKOMENDASI_TINDAK_LANJUT): Chi-squared approximation may be
## incorrect
##
## Pearson's Chi-squared test
##
## data: data_kategorik$KONDISI_USAHA and data_kategorik$REKOMENDASI_TINDAK_LANJUT
## X-squared = 129.82, df = 6, p-value < 2.2e-16
chisq.test(data_kategorik$KONDISI_JAMINAN, data_kategorik$REKOMENDASI_TINDAK_LANJUT)
## Warning in chisq.test(data_kategorik$KONDISI_JAMINAN,
## data_kategorik$REKOMENDASI_TINDAK_LANJUT): Chi-squared approximation may be
## incorrect
##
## Pearson's Chi-squared test
##
## data: data_kategorik$KONDISI_JAMINAN and data_kategorik$REKOMENDASI_TINDAK_LANJUT
## X-squared = 162.87, df = 9, p-value < 2.2e-16
Selain melihat hubungan pada data yang bersifat kategorikal, kita juga bisa melihat hubungan antar variabel numerikal. Ya. Kita akan menggunakan korelasi.
library(corrplot)
## corrplot 0.92 loaded
library(ggcorrplot)
## Loading required package: ggplot2
M = data_reduce[, 8:11]
# Library corrplot
# -- Pearson correlation
par(mfrow=c(2,2))
corrplot(cor(M), type="upper",order="hclust")
corrplot(cor(M), method="square",type="upper")
corrplot(cor(M), method="number",type="lower")
corrplot(cor(M), method="ellipse")
# -- Kendall correlation
par(mfrow=c(2,2))
corrplot(cor(M, method="kendall"), type="upper",order="hclust")
corrplot(cor(M, method="kendall"), method="square",type="upper")
corrplot(cor(M, method="kendall"), method="number",type="lower")
corrplot(cor(M, method="kendall"), method="ellipse")
# Library ggcorrplot
corr = round(cor(M), 1) # Pearson correlation
ggcorrplot(round(cor(M), 1),
hc.order = TRUE,
type = "lower",
lab = TRUE,
lab_size = 3,
method = "circle",
colors = c("tomato2","white","springgreen3"),
title = "Correlogram of Data Nasabah",
ggtheme = theme_bw)
## Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> =
## "none")` instead.
Pada masing-masing sintak di atas tervisualisasikan beberapa variabel dalam kaitan hubungan antar satu variabel dengan variabel lainnya.
Dalam melakukan pemodelan tentu kita perlu meninjau variabel-variabel apa saja yang berpengaruh pada model kita, khususnya pada klasifikasi. Pada kesempatan ini kita menggunakan model Regresi Multinomial.
colnames(data_reduce)
## [1] "NOMOR_KONTRAK" "DOMISILI"
## [3] "KARAKTER" "PROFESI"
## [5] "KONDISI_USAHA" "KONDISI_JAMINAN"
## [7] "STATUS" "PRODUK"
## [9] "PYD" "TENOR"
## [11] "OSL" "KEWAJIBAN"
## [13] "KOLEKTIBILITAS" "COUNT_SURVEY"
## [15] "REKOMENDASI_TINDAK_LANJUT"
data_select =
data_reduce[,c("KARAKTER","KONDISI_USAHA","KONDISI_JAMINAN","STATUS","KEWAJIBAN","OSL","KOLEKTIBILITAS","REKOMENDASI_TINDAK_LANJUT")]
data_non_na = na.omit(data_select)
Jika pada data terdapat NA value, nilai tersebut dapat pula untuk dipangkas. Hapuslah nilai NA tersebut.
Untuk memberikan performa model yang baik, maka pada data kita perlu dilakukan treatment tertentu, misalnya dilakukan scalling atau dilakukan pengelompokan data atau disebut juga bucketing.
data_select_new = data_select
data_select_new$KEWAJIBAN = scale(data_select_new$KEWAJIBAN)[, 1]
data_select_new$OSL = scale(data_select_new$OSL)[, 1]
data_select_new$KEWAJIBAN = cut(data_select_new$KEWAJIBAN, breaks = c(-0.354107,5,15,30))
data_select_new$KEWAJIBAN = as.factor(data_select_new$KEWAJIBAN)
data_select_new$OSL = cut(data_select_new$OSL, breaks= c(-0.60383,3,10,15))
data_select_new$OSL = as.factor(data_select_new$OSL)
data_select_new = na.omit(data_select_new)
Sebelum masuk pada pemodelan, kita perlu memisahkan data kita menjadi training dan testing (ada pula yang membaginya menjadi training, testing, dan validasi).
Tujuan dari pemisahan data ini ialah untuk melihat kemampuan model kita untuk melakukan prediksi sebagaimana tujuan dari pemodelan kita.
library(caret)
## Loading required package: lattice
index = createDataPartition(data_select_new$REKOMENDASI_TINDAK_LANJUT, p= .95, list = FALSE)
train = data_select_new[index,]
test = data_select_new[-index,]
Sekarang kita siap untuk masuk pada pemodelan.
Ingat bahwa kita menggunakan Model Regresi Multinomial, dimana kita perlu menentukan referensi dari kelas target.
Referensi kelas target ini ialah kelas yang memiliki jumlah anggota terbanyak.
train2 = train
# Setting the reference
train2$REKOMENDASI_TINDAK_LANJUT = relevel(train2$REKOMENDASI_TINDAK_LANJUT, ref = "Angsuran Biasa")
#training the model
require(nnet)
## Loading required package: nnet
# Training the multinomial model
multinom_model = multinom(REKOMENDASI_TINDAK_LANJUT ~ ., data = train2)
## # weights: 64 (45 variable)
## initial value 1319.752232
## iter 10 value 747.201800
## iter 20 value 620.100522
## iter 30 value 615.850387
## iter 40 value 615.569348
## iter 50 value 615.557160
## iter 60 value 615.556756
## final value 615.556740
## converged
# Checking the model
summary(multinom_model)
## Warning in sqrt(diag(vc)): NaNs produced
## Call:
## multinom(formula = REKOMENDASI_TINDAK_LANJUT ~ ., data = train2)
##
## Coefficients:
## (Intercept) KARAKTERTIDAK KOOPERATIF KONDISI_USAHA
## Diskon Pelunasan -3.262955 1.776002 -0.7395132
## Penarikan -7.478478 3.637925 0.7217574
## Restrukturisasi -4.127991 -2.260366 0.9795331
## KONDISI_JAMINANHilang KONDISI_JAMINANPindah Tangan
## Diskon Pelunasan -24.6997691 -27.1747309
## Penarikan 0.8730593 0.5546689
## Restrukturisasi 0.5009700 -13.6878369
## KONDISI_JAMINANRusak STATUS KEWAJIBAN(5,15]
## Diskon Pelunasan -25.1217347 0.0969241 0
## Penarikan -1.0061029 0.1151513 0
## Restrukturisasi 0.1020155 0.3245591 0
## KEWAJIBAN(15,30] OSL(3,10] OSL(10,15]
## Diskon Pelunasan -3.929780 2.9912517 0
## Penarikan 1.166857 -25.9027242 0
## Restrukturisasi 27.321491 0.3635798 0
## KOLEKTIBILITASDIRAGUKAN KOLEKTIBILITASKURANG LANCAR
## Diskon Pelunasan 2.8501679 0.2787231
## Penarikan 4.4870441 1.1655693
## Restrukturisasi -0.1123873 -0.1840878
## KOLEKTIBILITASLANCAR KOLEKTIBILITASMACET
## Diskon Pelunasan 0.08547222 0.5976027
## Penarikan -30.57565318 1.8176430
## Restrukturisasi 0.83530149 -3.2573230
##
## Std. Errors:
## (Intercept) KARAKTERTIDAK KOOPERATIF KONDISI_USAHA
## Diskon Pelunasan 1.1067392 0.9037187 0.3823120
## Penarikan 1.2598373 0.6255479 0.3784048
## Restrukturisasi 0.3550675 0.7803456 0.1032816
## KONDISI_JAMINANHilang KONDISI_JAMINANPindah Tangan
## Diskon Pelunasan 2.421793e-12 1.739812e-13
## Penarikan 1.128468e+00 6.684965e-01
## Restrukturisasi 1.178410e+00 7.159447e-07
## KONDISI_JAMINANRusak STATUS KEWAJIBAN(5,15]
## Diskon Pelunasan 4.845066e-12 0.14132584 NaN
## Penarikan 1.279423e+00 0.10445796 NaN
## Restrukturisasi 1.192534e+00 0.03728698 0
## KEWAJIBAN(15,30] OSL(3,10] OSL(10,15]
## Diskon Pelunasan 3.889289e-15 1.045538e+00 NaN
## Penarikan NaN 9.841226e-14 NaN
## Restrukturisasi 3.962966e-13 6.311337e-01 0
## KOLEKTIBILITASDIRAGUKAN KOLEKTIBILITASKURANG LANCAR
## Diskon Pelunasan 0.9289846 0.7417426
## Penarikan 0.8955148 0.6969970
## Restrukturisasi 0.6002134 0.1934950
## KOLEKTIBILITASLANCAR KOLEKTIBILITASMACET
## Diskon Pelunasan 9.512842e-01 1.2231805
## Penarikan 2.098666e-14 0.7346257
## Restrukturisasi 2.142116e-01 1.0812796
##
## Residual Deviance: 1231.113
## AIC: 1309.113
#converting the coefficients to odds by taking the exponential of the coefficients.
exp(coef(multinom_model))
## (Intercept) KARAKTERTIDAK KOOPERATIF KONDISI_USAHA
## Diskon Pelunasan 0.0382751405 5.9061988 0.4773462
## Penarikan 0.0005651168 38.0128741 2.0580469
## Restrukturisasi 0.0161152157 0.1043123 2.6632124
## KONDISI_JAMINANHilang KONDISI_JAMINANPindah Tangan
## Diskon Pelunasan 1.875109e-11 1.578208e-12
## Penarikan 2.394224e+00 1.741364e+00
## Restrukturisasi 1.650321e+00 1.136182e-06
## KONDISI_JAMINANRusak STATUS KEWAJIBAN(5,15] KEWAJIBAN(15,30]
## Diskon Pelunasan 1.229615e-11 1.101777 1 1.964800e-02
## Penarikan 3.656411e-01 1.122043 1 3.211883e+00
## Restrukturisasi 1.107401e+00 1.383420 1 7.337917e+11
## OSL(3,10] OSL(10,15] KOLEKTIBILITASDIRAGUKAN
## Diskon Pelunasan 1.991059e+01 1 17.290685
## Penarikan 5.631056e-12 1 88.858401
## Restrukturisasi 1.438470e+00 1 0.893698
## KOLEKTIBILITASKURANG LANCAR KOLEKTIBILITASLANCAR
## Diskon Pelunasan 1.3214414 1.089231e+00
## Penarikan 3.2077485 5.262142e-14
## Restrukturisasi 0.8318628 2.305509e+00
## KOLEKTIBILITASMACET
## Diskon Pelunasan 1.8177558
## Penarikan 6.1573286
## Restrukturisasi 0.0384913
head(round(fitted(multinom_model), 2))
## Angsuran Biasa Diskon Pelunasan Penarikan Restrukturisasi
## 1 0.81 0.01 0.00 0.18
## 2 0.48 0.00 0.51 0.01
## 3 0.25 0.02 0.72 0.00
## 4 0.98 0.00 0.01 0.02
## 5 0.47 0.20 0.32 0.00
## 6 0.69 0.02 0.00 0.29
# Predicting the values for train dataset
train2$ClassPredicted = predict(multinom_model, newdata = train2, "class")
train_prob = predict(multinom_model, newdata = train2, "probs")
df = train_prob
df$max=apply(df,1, max)
## Warning in df$max = apply(df, 1, max): Coercing LHS to a list
train2$score = df$max
test_prob = predict(multinom_model, newdata = test, "probs")
df2 = test_prob
df2$max=apply(df2,1, max)
## Warning in df2$max = apply(df2, 1, max): Coercing LHS to a list
tab_train = table(train2$REKOMENDASI_TINDAK_LANJUT, train2$ClassPredicted)
round((sum(diag(tab_train))/sum(tab_train))*100,4)
## [1] 68.2773
test$ClassPredicted = predict(multinom_model, newdata = test, "class")
test$score = df2$max
tab_test = table(test$REKOMENDASI_TINDAK_LANJUT, test$ClassPredicted)
round((sum(diag(tab_test))/sum(tab_test))*100,4)
## [1] 75
Untuk keperluan tertentu, kita perlu mengetahui peluang dari tiap baris data (perwakilan dari pelanggan) untuk masuk pada kelas target tertentu.
Tujuannya ialah untuk melihat seberapa pengaruh model untuk melakukan klasifikasi. Selain itu bisa juga dari sudut pandang bisnis, dalam kasus real penentuan threshold pada nilai peluang juga dikaitkan dengan beberapa faktor, misalnya revenue pelanggan.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tentang saya, silakan kunjungi: