Pengantar

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.

Membaca data eksternal

data = read.csv("https://storage.googleapis.com/dqlab-dataset/project.csv")

Inspeksi data

Setelah data berhasil di import, cobalah kamu untuk menginspeksi dataset dengan jalan

  1. Melihat 6 baris pertama data tersebut, apa saja yang ditunjukkannya dan
  2. 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" ...

Statistik deskriptif 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         
##                           
##                           
## 

Menghapus kolom

Pada data, sebenarnya tidak memerlukan nama pelanggan untuk diberikan rekomendasi. Atau dengan kata lain penanda pelanggan untuk diberikan rekomendasi cukup dengan melihat no_kontrak pelanggan itu saja.

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"

Konversi data

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.

Jika tidak perlu di konversi, tidak perlu diubah

Tetapi, jika perlu dirubah kolom “PRODUK”, “PYD”, “TENOR”, dan “OSL” maka perintahnya berikut:

data_reduce[, 8:11] = sapply(data_reduce[, 8:11], as.numeric)

Pemilihan data kategori

Data kategori dapat dipilih melalui kolom-kolom “KONDISI_USAHA”, “KONDISI_JAMINAN”, “REKOMENDASI_TINDAK_LANJUT”.

Ubah kolom “REKOMENDASI_TINDAK_LANJUT” sebagai faktor (gunakan as.factor).

Gunakan uji chi-square dapat digunakan untuk melihat hubungan antar variabel kategorik berikut:

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

Berdasarkan uji chi-square diatas dapat disimpulkan bahwa variabel kondisi usaha memiliki hubungan dengan variabel rekomendasi tindak lanjut karena p-value < 0,05(5%). Kondisi jaminan juga memiliki hubungan dengan variabel rekomendasi tindak lanjut karena p-value < 0,05(5%).

Korelasi antar variabel data

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
## Warning in register(): Can't find generic `scale_type` in package ggplot2 to
## register S3 method.
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.

Metode yang digunakan untuk melihat korelasi adalah dengan metode korelasi pearson dan korelasi kendall. Jika nilai korelasinya bernilai positif maka korelasi antar variabel tersebut berkorelasi kuat.

Pemilihan fitur/independent variabel/input

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.

Lalu bagaimana menentukan variabel apa saja yang berpengaruh tersebut?

Ada banyak alternatif, salah satunya ialah Information Gain. Melalui information gain diambil nilai importance variabel yang lebih dari 0.02 (kamu dapat eksplorasi apa yang terjadi apabila kita mengambil nilai yang kurang dari 0.02).

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)

Transformasi data

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)

Training data

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,]

Pemodelan/Modelling data

Sekarang kita siap untuk masuk pada pemodelan.

train2 = train
# Setting the reference
train2$REKOMENDASI_TINDAK_LANJUT = relevel(train2$REKOMENDASI_TINDAK_LANJUT, ref = "Angsuran Biasa")
# training model
require(nnet)
## Loading required package: nnet
# training the multinomial mode
multinom_model = multinom(REKOMENDASI_TINDAK_LANJUT ~ ., data=train2)
## # weights:  64 (45 variable)
## initial  value 1319.752232 
## iter  10 value 740.291636
## iter  20 value 617.611445
## iter  30 value 612.855316
## iter  40 value 612.594366
## iter  50 value 612.580478
## iter  60 value 612.579999
## final  value 612.579988 
## converged
# checking 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.244546                 1.813299    -0.7478194
## Penarikan          -7.509439                 3.719067     0.7555596
## Restrukturisasi    -4.131078                -2.212290     0.9824744
##                  KONDISI_JAMINANHilang KONDISI_JAMINANPindah Tangan
## Diskon Pelunasan           -26.4258559                  -29.2016536
## Penarikan                    0.8105445                    0.5137542
## Restrukturisasi              0.5165099                  -13.9274117
##                  KONDISI_JAMINANRusak     STATUS KEWAJIBAN(5,15]
## Diskon Pelunasan          -26.9436152 0.09293497               0
## Penarikan                  -0.9777548 0.09720577               0
## Restrukturisasi             0.1654408 0.32285928               0
##                  KEWAJIBAN(15,30]   OSL(3,10] OSL(10,15]
## Diskon Pelunasan        -3.996223   2.9621134          0
## Penarikan                1.154449 -27.2107637          0
## Restrukturisasi         28.897700   0.3346525          0
##                  KOLEKTIBILITASDIRAGUKAN KOLEKTIBILITASKURANG LANCAR
## Diskon Pelunasan               2.7430892                   0.3192599
## Penarikan                      4.4002729                   1.2262682
## Restrukturisasi               -0.2622012                  -0.2150021
##                  KOLEKTIBILITASLANCAR KOLEKTIBILITASMACET
## Diskon Pelunasan            0.1967404           0.5590025
## Penarikan                 -32.9222221           1.7765398
## Restrukturisasi             0.9205171          -3.3061588
## 
## Std. Errors:
##                  (Intercept) KARAKTERTIDAK KOOPERATIF KONDISI_USAHA
## Diskon Pelunasan   1.0967879                0.9002311     0.3829643
## Penarikan          1.2687458                0.6261935     0.3821727
## Restrukturisasi    0.3569305                0.7833132     0.1041433
##                  KONDISI_JAMINANHilang KONDISI_JAMINANPindah Tangan
## Diskon Pelunasan          4.812955e-13                 4.648411e-14
## Penarikan                 1.140597e+00                 6.705835e-01
## Restrukturisasi           1.179181e+00                 5.370705e-07
##                  KONDISI_JAMINANRusak     STATUS KEWAJIBAN(5,15]
## Diskon Pelunasan         3.550206e-13 0.14047443    2.118292e-15
## Penarikan                1.286119e+00 0.10499286             NaN
## Restrukturisasi          1.193795e+00 0.03731573    0.000000e+00
##                  KEWAJIBAN(15,30]    OSL(3,10]   OSL(10,15]
## Diskon Pelunasan     9.725372e-16 1.054768e+00 3.486689e-16
## Penarikan            3.365132e-16 2.482327e-14 1.768231e-16
## Restrukturisasi      9.198348e-14 6.310624e-01 0.000000e+00
##                  KOLEKTIBILITASDIRAGUKAN KOLEKTIBILITASKURANG LANCAR
## Diskon Pelunasan               0.9190928                   0.7412557
## Penarikan                      0.8904435                   0.7010523
## Restrukturisasi                0.5843858                   0.1937207
##                  KOLEKTIBILITASLANCAR KOLEKTIBILITASMACET
## Diskon Pelunasan         9.598497e-01           1.2183108
## Penarikan                1.968480e-15           0.7345576
## Restrukturisasi          2.168910e-01           1.0783981
## 
## Residual Deviance: 1225.16 
## AIC: 1303.16
# converting the coefficients to odds by taking the exponential of the coefficients
exp(coef(multinom_model))
##                   (Intercept) KARAKTERTIDAK KOOPERATIF KONDISI_USAHA
## Diskon Pelunasan 0.0389862439                6.1306419     0.4733977
## Penarikan        0.0005478883               41.2259141     2.1288024
## Restrukturisasi  0.0160655478                0.1094497     2.6710572
##                  KONDISI_JAMINANHilang KONDISI_JAMINANPindah Tangan
## Diskon Pelunasan          3.337311e-12                 2.079136e-13
## Penarikan                 2.249132e+00                 1.671555e+00
## Restrukturisasi           1.676167e+00                 8.941326e-07
##                  KONDISI_JAMINANRusak   STATUS KEWAJIBAN(5,15] KEWAJIBAN(15,30]
## Diskon Pelunasan         1.988550e-12 1.097390               1     1.838494e-02
## Penarikan                3.761547e-01 1.102087               1     3.172275e+00
## Restrukturisasi          1.179913e+00 1.381071               1     3.549045e+12
##                     OSL(3,10] OSL(10,15] KOLEKTIBILITASDIRAGUKAN
## Diskon Pelunasan 1.933880e+01          1              15.5349009
## Penarikan        1.522353e-12          1              81.4731015
## Restrukturisasi  1.397455e+00          1               0.7693562
##                  KOLEKTIBILITASKURANG LANCAR KOLEKTIBILITASLANCAR
## Diskon Pelunasan                   1.3761090         1.217428e+00
## Penarikan                          3.4084859         5.035709e-15
## Restrukturisasi                    0.8065398         2.510588e+00
##                  KOLEKTIBILITASMACET
## Diskon Pelunasan          1.74892715
## Penarikan                 5.90937368
## Restrukturisasi           0.03665671
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.26             0.02      0.72            0.00
## 4           0.98             0.00      0.01            0.02
## 5           0.49             0.20      0.30            0.00
## 6           0.69             0.02      0.00            0.28
# 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
# Building classification table
tab_train = table(train2$REKOMENDASI_TINDAK_LANJUT, train2$ClassPredicted)
round((sum(diag(tab_train))/sum(tab_train))*100,4)
## [1] 67.1218
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] 68.75

Akurasi model untuk training dan testing sudah cukup baik untuk diaplikasikan.

Sekian dan terima kasih sudah melihat project ini. Jika terdapat kesalahan mohon koreksinya.