Training Objectives

Mempelajari dan mengembangkan algoritma klasifikasi dari awal, dan menyelidiki dasar matematika yang mendukung logistic regression dan algoritma nearest neighbors, dua algoritma paling serbaguna yang banyak digunakan saat ini.

  • Logistic Regression
    • Memahami Peluang (Odds & Probability)
    • Log Peluang (Log of Odds)
    • Fungsi glm
  • Prediksi Tetangga Terdekat
    • K-NN (K-Nearest Neighbors)

Classification 1

Dalam Machine Learning dan statistik, Classification / klasifikasi adalah bentuk pendekatan Supervised Learning untuk memprediksi label dari suatu data dengan tipe kategorikal.

Linear Regression vs Logistic Regression

Ide dari logistic regression mulanya berangkat dari model linear regression. Bedanya:

  • Linear regression: digunakan untuk memprediksi angka kontinyu dengan range -Inf to Inf
  • Logistic regression: digunakan untuk memprediksi probability dengan range: 0 to 1

Basic Intuition Classification

Probability (Kemungkinan)

Pada dasarnya, ketika kita melakukan klasifikasi, kita menghitung probabilitas.

\[P(yes) = \frac{n(yes)}{n(yes) + n(no)}\]

Dimana:

  • P = Probabilitas
  • n = Jumlah kejadian

Kindly Reminder: Range dari Probability: 0 - 1

Case study:

Saat H-2 Lebaran, terdapat 100 penerbangan di Soekarno-Hatta airport, dari 100 penerbangan tersebut, terdapat 20 penerbangan delay.

Diketahui:

  • Penerbangan delay: 20 penerbangan

  • Penerbangan tidak delay: 80 penerbangan

  • Berapakah probability suatu penerbangan delay di Soekarno-Hatta?

# Please type your answer 

p_delay <- 20 / 100
p_delay
## [1] 0.2
  • Berapakah probability suatu penerbangan tidak delay di Soekarno-Hatta?
# Please type your answer 

p_no_delay <- 80 / 100
p_no_delay
## [1] 0.8

Odds

Odds merupakan bentuk lain dari probabilitas, yaitu perbandingan antara probabilitas kejadian terjadi/probabilitas kejadian tidak terjadi.

\[Odds(yes) = \frac{P(yes)}{1-P(yes)}\]

Dimana:

  • P = Probabilitas

Case study:

Saat H-2 Lebaran, terdapat 100 penerbangan di Soekarno-Hatta airport, dari 100 penerbangan tersebut, terdapat 20 penerbangan delay.

  • Berapakah odds penerbangan terbang tepat waktu?
# Odds tepat waktu dibandingkan dengan peluang delay
p_no_delay/(1 - p_no_delay)
## [1] 4
0.8 / (1 - 0.8)
## [1] 4

Interpretasi: Odds penerbangan tepat waktu itu 4 KALI lebih mungkin dibandingkan penerbangan tidak tepat waktu (delay).

Range dari Odds: 0 - Inf

Log of Odds

Log of odds adalah nilai odds yang dilogaritmikan

\[LogOfOdds = log(\frac{P}{1-P})\]

Case Study

Disini kita sudah mengetahu bahwa Odds dari penerbangan tepat waktu adalah 4 kali lebih mungkin dari penerbangan tidak tepat waktu.

  • Berapakah nilai Log of Odds penerbangan tepat waktu?
# Please type your answer
log(4)
## [1] 1.386294

Additional Notes:

  • Disini kenapa kita mempelajari Log of Odds karena Log of Odds adalah hasil dari Logistic Regression.
  • Nilai dari Log of Odds tidak dapat kita interpretasikan.

Follow up question dari additional notes: > Lalu bagaimana ketika kita ingin mengubah nilai dari Log of Odds menjadi nilai odds agar bisa di-interpretasikan?

Untuk mengubah Log of Odds -> Odds, kita dapat menfaatkan exponential. Di R, sudah tersedia sebuah fungsi bernama exp(). Mari kita coba untuk menggubank fungsi tersebut untuk mengembalikan nilai Oddsnya.

# Please type your answer
exp(1.386294)
## [1] 3.999999

Additional:

  • Ketika kita ingin mengubah nilai Odds -> Probability, kita bisa melakukan perhitungan manual dengan menggunakan rumus seperti di bawah ini.

\[P = \frac{Odds}{1+Odds}\]

# Please type your answer
4 / (1+4)
## [1] 0.8

Logit & Inversere Logit

Sebelumnya kita sudah belajar, bagaimana mengtransformasi nilai Odds menjadi Log of Odds. Sekarang kita akan mencoba mempelajari, bagaimana mengtransformasi nilai Probability menjadi Log of Odds. Untuk melakukan transformasi tersebut, kita dapat memanfaatkan fungsi logit() dari library(gtools).

#install.packages("gtools")
library(gtools)

Case Study

  • Kita ingin mengubah peluang tidak delay menjadi Log of Odds. Sebelumnya kita sudah menyimpang peluang tidak delay ke dalam object p_no_delay, mari kita coba ubah nilai probabilitynya dari object tersebut.
# Please type your answer
p_no_delay
## [1] 0.8
logit(p_no_delay)
## [1] 1.386294

Follow up question: > Lalu bagaimana ketika kita ingin mengubah nilai dari Log of Odds menjadi nilai probability agar bisa di-interpretasikan?

Untuk mengubah Log of Odds ke peluang dengan fungsi inv.logit().

# Please type your answer
inv.logit(1.386294)
## [1] 0.7999999

Fun Fact :D Fungsi inv.logit() sering juga disebut sigmoidal logistic function.

# sigmoid function
curve(inv.logit(x), from = -10, to=10, 
      xlab = "Log of Odds", 
      ylab = "Probabolity")

Cheatsheet Probability, Odds & Log of Odds

Model Machine Learning - Logistic Regression

Warm Up Study Case

Anda adalah seorang Data Scientist di Universitas Algoritma. Anda ditugaskan untuk memprediksi status kelulusan siswa dengan honors (cumlaude).

# Please run the code down below
library(dplyr)

honors <- read.csv("data_input/sample.csv") %>% 
  select(-femalexmath) %>% 
  mutate(female = as.factor(female),
         hon = as.factor(hon))

head(honors)

Deskripsi variabel:

  • female: gender of student (1 for female, 0 for male)
  • read: score in reading test
  • write: score in writing test
  • math: score in math test
  • hon: status of graduating in honors (1 for honors, 0 for not honors)

Build Model

Untuk membuat model logistic regression bisa menggunakan fungsi glm(), terdapat 3 paramater yang kita gunakan yaitu

  • formula : tempat mendefinisikan target dan predictor (y/target ~ x/predictor)
  • data : data yang digunakan untuk membuat model
  • family : gunakan binomial bila ingin menggunakan logistic regression pada pemodelan ini

Syntax: glm(formula = target ~ predictor, data = , family = binomial)

Model W/O Predictor

Pertama kita akan mencoba untuk membuat sebuah model tanpa prediktor, lalu simpan ke sebuah objet bernama model_wo_predictor.

Diketahui:

  • Target: hon
  • Prediktor: 1 -> artinya tidak ada predictor
model_wo_predictor <- glm(formula = hon ~ 1, data = honors, family = binomial)

Untuk melihat hasil dari model yang telah kita buat, kita dapat memanfaatkan fungsi summary().

summary(model_wo_predictor)
## 
## Call:
## glm(formula = hon ~ 1, family = binomial, data = honors)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -0.7497  -0.7497  -0.7497  -0.7497   1.6772  
## 
## Coefficients:
##             Estimate Std. Error z value         Pr(>|z|)    
## (Intercept)  -1.1255     0.1644  -6.845 0.00000000000762 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 222.71  on 199  degrees of freedom
## Residual deviance: 222.71  on 199  degrees of freedom
## AIC: 224.71
## 
## Number of Fisher Scoring iterations: 4

Jika kita lihat dari hasil model yang telah dibuat, kita mengetahui bahwa model tanpa prediktor memiliki intercept sebesar -1.1255

Follow up question: > Dari mana nilai intercept/koefisien tersebut?

# proportion
table(honors$hon)
## 
##   0   1 
## 151  49
# peluang tidak mendapatkan honors
p_0 <- 151/(151+49)
p_0
## [1] 0.755
# log of odds
logit(p_0)
## [1] 1.12546
# peluang mendapatkan honors
p_1 <- 49/(49 +151)
p_1
## [1] 0.245
# log of odds
logit(p_1)
## [1] -1.12546

Y = B0 + B1.X1 Y = -1.125

Dari pembuktian di atas, kita mengetahui bahwa nilai koefisien merupakan nilai log of odds.

Model All Predictor

Pada tahapan berikutnya kita akan mencoba untuk membuat model dengan keseluruhan prediktor.

# Please type your answer
model_all_predictor <- glm(formula = hon ~ ., data = honors, family = binomial)
summary(model_all_predictor)
## 
## Call:
## glm(formula = hon ~ ., family = binomial, data = honors)
## 
## Deviance Residuals: 
##          Min            1Q        Median            3Q           Max  
## -0.000245237  -0.000000021  -0.000000021  -0.000000021   0.000176979  
## 
## Coefficients:
##                 Estimate   Std. Error z value Pr(>|z|)
## (Intercept)  -2176.87191 282900.61006  -0.008    0.994
## female1         -4.44248  18078.08748   0.000    1.000
## read             0.07478    489.40463   0.000    1.000
## write           36.30917   4837.98255   0.008    0.994
## math            -0.36898   1362.81267   0.000    1.000
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 222.71004668627  on 199  degrees of freedom
## Residual deviance:   0.00000013527  on 195  degrees of freedom
## AIC: 10
## 
## Number of Fisher Scoring iterations: 25
  • Interpretasi Nilai AIC

Seperti pada materi RM minggu lalu, kita menginginkan model kita terdiri dari beberapa variable yang memiliki nilai AIC serendah mungkin.

AIC = Information Loss

model_all_predictor$aic
## [1] 10
  • Interpretasi Signifikansi Prediktor (P-Value)

p-values: merupakan nilai p-values untuk melihat apakah variabel prediktor berpengaruh cukup signifikan terhadap variabel target. Variabel prediktor(x) dapat dikatakan signifikan jika \(p-values < 0.05\).

Hipotesis: - \(H_0\) : Prediktor tidak memengaruhi Target - \(H_1\) : Prediktor memengaruhi Target

Kita bisa melihat nilai signifikasi berdasarkan jumlah bintang - Jika 3 bintang *** -> prediktor tersebut secara signifikan mempengaruhi target - Jika 2 bintang ** -> prediktor tersebut mempengaruhi target - Jika 1 bintang * -> prediktor tersebut mempengaruhi target tp tidak terlalu kuat

  • Interpretasi dari nilai estimate/ coefficient yang peroleh untuk setiap predictornya

Untuk dapat melakukan interpretasi, kita harus melakukan transformasi nilai log of odds -> odds, dengan menggunakan fungsi exp().

Contoh 1: Interpretasi nilai read

# Interpretasi nilai read
exp(0.07478)
## [1] 1.077647

Kesimpulan: Setiap kenaikan 1 nilai pada math, maka odds seseorang mendapatkan honor naik sebesar 1.07 KALI.

Contoh 2: Interpretasi gender

Sama seperti model RM, model Logistic juga akan membuat dummy variable

# Interpretasi gender
exp(4.44248)
## [1] 84.98544

Kesimpulan: Kejadian student female mendapatkan honors 84.98 KALI lebih tidak mungkin dibandingkan male mendapatkan honors, dengan catatan prediktor yang lain memiliki nilai yg sama.

Kesimpulan 2: > Bila student merupakan female maka akan menurunkan peluang untuk lulus sebagai honors.

Contoh 3: Interpretasi Formula

Ketika membuat formula, tidak usah mengubah ke bentuk odds (masih dlm bentuk log of odds):

Honor Formula = -2176.87191 + female1 * -4.44248 + read * 0.07478 + write * 36.30917 + math * -0.36898

# Student Male, Read 70, Write 75, Math 60
-2176.87191 + 0 * -4.44248 + 70 * 0.07478 + 75 * 36.30917 + 60 * -0.36898
## [1] 529.4116

Additional Notes: Hasil dari formula tersebut dapat kita interepteasikan dengan mengubahnya menjadi bentuk probabilitas, untuk mengetahui apakah student tersebut memiliki kemungkinan mendapatkan honors atau tidak.

Perfect Separation

Untuk membahas Perfect Separation, mari kita coba lihat lagi hasil summary dari model Logistic Regression yang menggunakan keseluruhan predictor.

# Please type your answer  
summary(model_all_predictor)
## 
## Call:
## glm(formula = hon ~ ., family = binomial, data = honors)
## 
## Deviance Residuals: 
##          Min            1Q        Median            3Q           Max  
## -0.000245237  -0.000000021  -0.000000021  -0.000000021   0.000176979  
## 
## Coefficients:
##                 Estimate   Std. Error z value Pr(>|z|)
## (Intercept)  -2176.87191 282900.61006  -0.008    0.994
## female1         -4.44248  18078.08748   0.000    1.000
## read             0.07478    489.40463   0.000    1.000
## write           36.30917   4837.98255   0.008    0.994
## math            -0.36898   1362.81267   0.000    1.000
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 222.71004668627  on 199  degrees of freedom
## Residual deviance:   0.00000013527  on 195  degrees of freedom
## AIC: 10
## 
## Number of Fisher Scoring iterations: 25

Perfect Separation adalah sebuah kondisi dimana ada 1 variabel yang dapat memisahkan kelas target secara sempurna. Cara mendeteksi:

  • tidak ada prediktor yang signifikan padahal aic sangat kecil
  • terdapat 1 koefisien yang nilainya cukup besar dibandingkan yang lain

Mari kita coba analisis secara spesifik prediktor tersebut, debgan melihat proporsi antara kolom predictor yang disangka ada hal yang janggal dengan target variable.

# Please type your answer
table(honors$hon, honors$write)
##    
##     31 33 35 36 37 38 39 40 41 42 43 44 45 46 47 49 50 52 53 54 55 57 59 60 61
##   0  4  4  2  2  3  1  5  3 10  2  1 12  1  9  2 11  2 15  1 17  3 12 25  4  0
##   1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  4
##    
##     62 63 65 67
##   0  0  0  0  0
##   1 18  4 16  7
table(honors$hon, honors$math)
##    
##     33 35 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
##   0  1  1  1  2  6 10  6  7  7  4  7  8  3  3  9  7  6  6  6  9  4  4 10  3  2
##   1  0  0  0  0  0  0  1  0  0  0  1  0  0  2  1  0  2  0  1  1  1  3  3  3  0
##    
##     60 61 62 63 64 65 66 67 68 69 70 71 72 73 75
##   0  2  4  2  2  3  1  1  0  0  0  1  2  0  0  1
##   1  3  3  2  3  2  2  3  2  1  2  0  2  3  1  1
table(honors$hon, honors$read)
##    
##     28 31 34 35 36 37 39 41 42 43 44 45 46 47 48 50 52 53 54 55 57 60 61 63 65
##   0  1  1  6  1  3  2  8  2 13  2 13  2  1 22  1 15 11  0  0  9  9  6  1 10  3
##   1  0  0  0  0  0  0  0  0  0  0  0  0  0  5  0  3  3  1  1  4  5  3  0  6  6
##    
##     66 68 71 73 76
##   0  0  7  0  1  1
##   1  1  4  2  4  1

Action plan ketika bertemu kondisi perfect separation:

  • Kita tidak perlu menggunakan/membuat machine learning. Bisa menggunakan kondisi ifelse saja
  • Disarankan untuk jangan menggunakan varibel tersebut sebagai prediktor.

Assumption

Logistic Regression menganut 3 asumsi:

  • Linearity of Predictor & Log of Odds: cara interpretasi model mengacu pada asumsi ini (contoh: untuk variabel numerik, peningkatan 1 nilai akan meningkatkan log of odds)

Handoyo adalah seorang murid laki-laki yang memperoleh nilai math sebesar 70, berapa probability Handoyo mendapatkan honors?

Diketahui Nilai Slope:

Intercept: -10.80595 Gender: 0.965311 Nilai Math: 0.16422

Rumus: Y = B0 + B1.X1 + B2.X2

# log of odds
-10.80595 + (0.965311 * 0) + (0.16422 * 70)
## [1] 0.68945
inv.logit(0.68945)
## [1] 0.6658446
  • Multicollinearity: antar prediktor tidak saling berkorelasi terlalu kuat (hingga nilai 1 / -1) -> uji vif()
library(car)
vif(model_all_predictor)
##    female      read     write      math 
##  6.999657  3.938737  1.070529 11.508350

Ketika ada 2 nilai/predicot yang nilai vif > 10. Maka kita hanya boleh memilih salah satunya saja.

  • Independence of Observations: antar observasi saling independen & tidak berasal dari pengukuran berulang (repeated measurement)

Contoh Untuk observasi saling independen: -> kita harus ambil data secara random sampling

Target: Mencari apakah seseorang akan beli atau tidak? - Mas Hadnoyo; Beli, beliau tidak puas - Mba Diva: Tidak beli, karena ada pengaruh dari Mas Handoyo

Contoh tidak bersal dari pengukuran berulang: -> Kita coba hilangkan data yang sebelumnya

Mengukur tinggi badan sebuah buah: Hari 1 : 10 cm . . Hari 10 : 14 cm

Asumsi logistic regression menuntut kita untuk memahami data secara mendalam dan memastikan data sudah siap dipakai untuk membuat model.

Case Study 2

Buat model untuk memprediksi peluang customer akan gagal bayar pinjaman (loan default), untuk mengindikasikan apakah customer tersebut baik atau tidak untuk diberikan pinjaman.

Workflow Case Study 2:

  1. Read Data + Data understanding
  2. Data Wrangling
  3. EDA
  4. Cross Validation -> New
  5. Build Model
  6. Predict -> New
  7. Evaluation -> New

Read Data

loans <- read.csv("data_input/loan2017Q4.csv")
head(loans)

Descriptions:

  • initial_list_status: Either w (whole) or f (fractional). This variable indicates if the loan was a whole loan or fractional loan. For background: Some institutional investors have a preference to purchase loans in their entirety to obtain legal and accounting treatment specific to their situation - with the added benefit of “instant funding” to borrowers
  • purpose: Simplified from the original data; One of: credit_card, debt_consolidation, home_improvement, major_purchase and small_business
  • int_rate: Interest rate in percentages
  • installment: Monthly payment owed by the borrower
  • annual_inc: Self-reported annual income provided by the borrower / co-borrowers during application
  • dti: A ratio of the borrower’s total monthly debt payments on his/her total obligations to the self-reported monthly income
  • verification_status: is the reported income verified, not verified, or if the income source was verified
  • grade: software-assigned loan grade
  • revol_bal: total credit revolving balance (in the case of credit card, it refers to the portion of credit card spending that goes unpaid at the end of a billing cycle)
  • inq_last_12m: number of credit inquiries in the last 12 months
  • delinq_2yrs: number of 30+ days past-due incidences of delinquency in the borrower’s credit file for the past 2 years
  • home_ownership: one of MORTGAGE, OWN and RENT
  • not_paid: 0 for fully-paid loans, 1 for charged-off, past-due / grace period or defaulted
  • log_inc: log of annual_inc
  • verified: 0 for “Not verified” under verification_status, 1 otherwise
  • grdCtoA: 1 for a grade of A, B or C, 0 otherwise

Data Wrangling

  • Target:
    not_paid (paid = 0, not_paid = 1)
  • Adakah variabel yang tipe datanya belum sesuai?
~ not_paid -> factor
verified -> factor
grade -> factor
home_ownership -> factor
purpose-> factor
initial_list_status -> factor
  • Adakah variabel di bawah ini ada yang dapat dibuang?

  • grade ->

  • log_inc ->

  • verified_status ->

loans_clean <- loans %>%
  mutate(not_paid = as.factor(not_paid),
         verified = as.factor(verified),
         grade = as.factor(grade),
         home_ownership= as.factor(home_ownership),
         purpose=as.factor(purpose),
         initial_list_status=as.factor(initial_list_status))%>%
  select(-c(verification_status,grdCtoA,log_inc))

glimpse(loans_clean)
## Rows: 1,556
## Columns: 13
## $ initial_list_status <fct> w, f, w, w, w, w, w, w, w, w, w, w, w, f, w, w, w,…
## $ purpose             <fct> debt_consolidation, debt_consolidation, debt_conso…
## $ int_rate            <dbl> 14.08, 9.44, 28.72, 13.59, 15.05, 10.91, 15.05, 10…
## $ installment         <dbl> 675.99, 480.08, 1010.30, 484.19, 476.33, 130.79, 3…
## $ annual_inc          <dbl> 156700, 50000, 25000, 175000, 109992, 49000, 65000…
## $ dti                 <dbl> 19.11, 19.35, 65.58, 12.60, 10.00, 5.12, 22.38, 33…
## $ grade               <fct> C, B, F, C, C, B, C, B, D, D, F, C, C, E, B, C, C,…
## $ revol_bal           <int> 21936, 5457, 23453, 31740, 2284, 2016, 14330, 2758…
## $ inq_last_12m        <int> 3, 1, 0, 0, 3, 5, 0, 1, 8, 1, 0, 12, 4, 8, 1, 3, 0…
## $ delinq_2yrs         <int> 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,…
## $ home_ownership      <fct> MORTGAGE, RENT, OWN, MORTGAGE, MORTGAGE, MORTGAGE,…
## $ not_paid            <fct> 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1,…
## $ verified            <fct> 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,…

Eksploratory Data Analysis

  • Check missing value
# Please type your answer
anyNA(loans_clean)
## [1] FALSE
  • Cek class-imbalance new
# Please type your answer
prop.table(table(loans_clean$not_paid))
## 
##   0   1 
## 0.5 0.5

Apakah proporsi antara target variable seimbang? Seimbang

Follow up question: > Kenapa kita harus mencari tahu apakah proporsi taretnya seimbang?

Proporsi yang seimbang penting agar model dapat mempelajari karakteristik kelas positif maupun negatif secara seimbang, tidak belajar dari satu kelas saja. Hal ini mencegah model dari hanya baik memprediksi 1 kelas saja. Note: Proporsi yang imbalance sebenarnya cukup subjektif dan tidak ada aturan bakunya. Akan tetapi ketika proporsinya targetnya 90%:10% atau 95%:5%, target variable tersebut akan dianggap tidak seimbang.

Target Variable:

  • 1/Paid: 80%
  • 0/Not Paid: 20%

Kalau datanya imbalance:

  • Tambah data real -> memerlukan waktu

  • Metode downSampling -> Membuang observasi dari kelas mayoritas, sehingga seimbang. Contoh: Paid: 800 observasi -> akan dicut/dihilangkan secara random -> 200 observasi Not Paid: 200 Observasi

  • Metode upSampling -> Duplikasi observasi dari kelas minoritas, sehingga seimbang. Contoh: Paid: 800 Observasi Not Paid: 200 Observasi -> akan diduplicate secara random -> 800 observasi

Materi tersebut akan dipelajari di C2

Kenapa kita harus tau kelas dari target variable kita balance atau tidak? Memastikan bahwa nanti data yang dimasukan ke model kita, itu datanya memiliki proporsi target yang seimbang. Jadinya model Machine Learning kita tidak hanya belajar untuk salah satu target kelasnya saja.

Contoh Proporsi Target Variable: Paid: 57% Not Paid: 43% Proporsi Balanced

Contoh dari Instructor: Paid: 65% Not Paid: 35% Proporsi Balanced

Cross Validation new

Cross Validation merupakan sebuah tahapan dimana kita akan membagi data menjadi 2 bagian yaitu data train dan data test.

  • Data train akan digunakan untuk training model.
  • Data test akan digunakan untuk pengujian performa model. Model akan diuji untuk memprediksi data test. Hasil prediksi dan data aktual dari data test akan dibandingkan untuk validasi performa model.

Tujuan dari cross validation adalah untuk mengetahui seberapa baik model untuk memprediksi unseen data.

Contoh:

  • 100 soal
  • 80 soal saya pakai untuk belajar (data train) -> Dipilih secara random
  • 20 soal saya pakai untuk ujian (data test) -> Sisa dari soal yang sudah dipilih secara random dari data train

Contoh Lainnya:

  • 10 Soal Latihan Matetmatika 5+3 1-1 7+8 9+9 6+4 8-2 7+4 1+4 5-1 7+10

  • Ulangan 5 soal -> untuk melihat pemahaman ataupun untuk nilai apakah murid bisa atau tidak 5-3 1+1 7-6 9+19 6-8

Untuk memilih secara random data yang akan dimasukan kedalam Data Train, kita akan memanfaatkan bantuan fungsi set.seed() dan RNGkind().

Intuisi:

# Agar hasil yang dikeluarkan pada R versi 3.x sama dengan R versi 4.x
RNGkind(sample.kind = "Rounding") 
# set.seed digunakan untuk mengunci sifat random dari fungsi sample()
set.seed(123)

sample(x = c("Victor", "Handoyo", "Diva"), size = 2)
## [1] "Victor"  "Handoyo"

Follow up question: > Kenapa kita harus mengunci sifat random yang ada?

  • Agar kita akan selalu memiliki Data train dan Data test yang sama.
    • Jadinya pada saat proses pembelajaran, kita akan mendapatkan hasil yang sama.
    • Ketika kita ingin melakukan adjustment/tunning pada model yang sudah ada, data yang akan dimasukan kembali ke model tersebut sama dengan model yang sebelumnya. Sehingga kita bisa melakukan komparasi yang apple to apple, terhadap kedua model tersebut.
# Agar hasil yang dikeluarkan pada R versi 3.x sama dengan R versi 4.x
RNGkind(sample.kind = "Rounding") 
# set.seed digunakan untuk mengunci sifat random dari fungsi sample()
set.seed(123)

# index sampling
index <- sample(x = nrow(loans_clean), # untuk menghitung jumlah dari observasi data kita
                size = nrow(loans_clean)*0.8) # Untuk mengambil seberapa banyak proporsi data yang ingin kita ambil

# splitting
loans_train <- loans_clean[index, ]
loans_test <- loans_clean[-index, ]
nrow(loans_train)
## [1] 1244
1556 *0.8
## [1] 1244.8

NOTE: Pembagian proporsi antara Data Train & Data Test tidak ada aturan bakunya, akan tetapi kebanyakan orang akan memberikan proporsi yang lebih banyak pada Data Train.

Build Model

Buatlah model logistic regression untuk memprediksi status loan (not_paid). Silahkan menggunakan keseluruhan predictor yang ada pada data kita.

# Please type your answer
model_credit_risk <- glm(formula = not_paid ~ ., data = loans_train, family = binomial)
# summary model
summary(model_credit_risk)
## 
## Call:
## glm(formula = not_paid ~ ., family = binomial, data = loans_train)
## 
## Deviance Residuals: 
##    Min      1Q  Median      3Q     Max  
## -1.919  -1.100   0.554   1.107   1.677  
## 
## Coefficients:
##                               Estimate   Std. Error z value  Pr(>|z|)    
## (Intercept)               -0.895253816  0.467909249  -1.913    0.0557 .  
## initial_list_statusw      -0.048747890  0.148032695  -0.329    0.7419    
## purposedebt_consolidation  0.115336589  0.155024560   0.744    0.4569    
## purposehome_improvement    0.204093183  0.230295537   0.886    0.3755    
## purposemajor_purchase      0.737075738  0.355047479   2.076    0.0379 *  
## purposesmall_business      0.938694313  0.526603436   1.783    0.0747 .  
## int_rate                  -0.018378629  0.051945000  -0.354    0.7235    
## installment                0.001110541  0.000228727   4.855 0.0000012 ***
## annual_inc                -0.000003243  0.000001321  -2.456    0.0141 *  
## dti                        0.000021291  0.004807931   0.004    0.9965    
## gradeB                     0.182773836  0.269467189   0.678    0.4976    
## gradeC                     0.605594745  0.422222941   1.434    0.1515    
## gradeD                     0.993606286  0.657471666   1.511    0.1307    
## gradeE                     1.034959679  0.951289595   1.088    0.2766    
## gradeF                     1.080915152  1.240401733   0.871    0.3835    
## gradeG                     0.150604983  1.381648411   0.109    0.9132    
## revol_bal                  0.000001796  0.000003377   0.532    0.5948    
## inq_last_12m              -0.031628334  0.024697577  -1.281    0.2003    
## delinq_2yrs                0.166826833  0.083625900   1.995    0.0461 *  
## home_ownershipOWN          0.439661888  0.185875847   2.365    0.0180 *  
## home_ownershipRENT         0.237032187  0.137641085   1.722    0.0851 .  
## verified1                  0.227585954  0.125577982   1.812    0.0699 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1724.5  on 1243  degrees of freedom
## Residual deviance: 1630.4  on 1222  degrees of freedom
## AIC: 1674.4
## 
## Number of Fisher Scoring iterations: 4

Additional Info:

Dalam membuat sebuah model, kita dapat memilih predictor apa saja yang kiranya memiliki pengaruh yang tinggi terhadap target varialbe, kita bisa melakukan Feature Selection dengan menggunakan fungsi step().

model_step <- step(object = model_credit_risk,
                   direction = "both",
                   trace = F)
summary(model_step)
## 
## Call:
## glm(formula = not_paid ~ installment + annual_inc + grade + delinq_2yrs + 
##     home_ownership + verified, family = binomial, data = loans_train)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.9162  -1.1142   0.6502   1.1104   1.6614  
## 
## Coefficients:
##                        Estimate   Std. Error z value    Pr(>|z|)    
## (Intercept)        -1.016867074  0.211758025  -4.802 0.000001571 ***
## installment         0.001129976  0.000225011   5.022 0.000000512 ***
## annual_inc         -0.000003002  0.000001133  -2.651    0.008029 ** 
## gradeB              0.120955536  0.203135292   0.595    0.551547    
## gradeC              0.449697161  0.199287045   2.257    0.024037 *  
## gradeD              0.757091610  0.213986088   3.538    0.000403 ***
## gradeE              0.698809943  0.275943528   2.532    0.011327 *  
## gradeF              0.650505301  0.424713120   1.532    0.125613    
## gradeG             -0.280828387  0.635944022  -0.442    0.658784    
## delinq_2yrs         0.162157394  0.082759891   1.959    0.050069 .  
## home_ownershipOWN   0.472482689  0.183936211   2.569    0.010207 *  
## home_ownershipRENT  0.278843394  0.130350327   2.139    0.032421 *  
## verified1           0.235884735  0.124633872   1.893    0.058408 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1724.5  on 1243  degrees of freedom
## Residual deviance: 1639.3  on 1231  degrees of freedom
## AIC: 1665.3
## 
## Number of Fisher Scoring iterations: 4

Interpretasi Model:

  • Variable yang meningkatkan peluang: Grade (kecuali grade G), installment, delinq_2yrs, home_ownership dan verified
  • Variable yang menurunkan peluang: annual inc dan grade G
  • Signifikansi Variable: installment dan grade (2 variable yang paling signifikan)

Predict New

Ketika kita sudah berhasil membuat model, kita akan mencoba melakukan prediksi terhadapat data test yang sudah kita persiapkan pada tahapan cross validation.

Syntax: predict(object model, newdata, type)

Terdapat parameter tambahan yang akan kita gunakan pada fungsi predict(), yaitu parameter type. Parameter type dapat kita isi dengan:

  • link: menghasilkan log of odds
  • response: menghasilkan probability

Contoh prediksi dengan menggunakan type = link, untuk 5 data teratas

# Please type your answer
predict(object = model_step, 
        newdata = loans_test[1:5,], 
        type = "link")
##           8          13          16          24          44 
##  0.13220652 -0.05171338  0.24003330  0.45283669  0.97379450

Contoh prediksi dengan menggunakan type = response, untuk 5 data teratas

# Please type your answer
predict(object = model_step, 
        newdata = loans_test[1:5,], 
        type = "response")
##         8        13        16        24        44 
## 0.5330036 0.4870745 0.5597219 0.6113135 0.7258752

Mari kita lakukan prediksi probability not_paid pada data loan_test, lalu disimpan pada kolom baru bernama prediction di object loan_test.

# Please type your answer
loans_test$prediction <- predict(object = model_step, # nama/object model yang ingin kita gunakan
                                 newdata = loans_test, # data test
                                 type = "response") # memilih hasil prediksinya 

Transformasi hasil predict

Setelah mendapatkan hasil prediksi yang masih bernilai probability, kita harus mengubah niali tersebut menjadi sebuah label yang sesuai dengan label pada target variable. Dalam kasus ini kita akan menggubah nilai probability menjadi 1 atau 0.

Untuk melakukan transformasi kita akan memanfaatkan fungsi ifelse(), fungsi tersebut dapat membantu kita untuk membuat fungsi logic if-else sederhana.

Syntax: ifelse(test = , yes = , no =)

  • test: kondisi yang ditentukan
  • yes: hasil yang di-inginkan jika kondisinya terpenuhi
  • no:hasil yang di-inginkan jika kondisinya tidak terpenuhi

Kondisi penentu ketika kita ingin mentranformasikan hasil prediksi kita ke sebuah kelas, kondisi itu sering disebuh dengan Threshold.

Threshold awal yang bisa gunakan adalah 0.5.

Ketika hasil prediksi probability > 0.5 -> 1/gagal bayar

Ketika hasil prediksi probability <=0.5 -> 0/berhasil bayar
# Please type your answer
loans_test$pred_label <- ifelse(test = loans_test$prediction > 0.3,
                                yes = "1",
                                no = "0")

loans_test

Model Evaluation New

Setelah dilakukan prediksi menggunakan model, masih ada saja prediksi yang salah. Pada klasifikasi, kita mengevaluasi model berdasarkan confusion matrix:

  • Penentuan kelas:

    • kelas positif: kelas yang lebih difokuskan
    • kelas negatif: kelas yang tidak difokuskan
  • Contoh kasus:

    • Machine learning untuk deteksi pasien covid:
      • kelas positif: terdeteksi covid -> karena kalo orang kena covid bisa berjalan bebas, orang tersebut bisa menularkan kepada orang lain
      • kelas negatif: terdeteksi sehat
    • Mahcine learning untuk deteksi apakah seseorang bisa bayar pinjaman atau tidak
      • kelas positf: yang tidak bisa bayar -> karena apa biar gk rugi
      • kelas negatif: yang bisa bayar
  • Isi dari Confusion Matrix:

    • true positive (TP): diprediksi positif dan benar (prediksi positif; aktual positif)
      • Aktualnya: gagal bayar
      • Prediksinya: gagal bayar
    • true negative (TN): diprediksi negatif dan benar (prediksi negatif; aktual negatif)
      • Aktualnya: bisa bayar
      • Prediksinya: bisa bayar
    • false positive (FP): diprediksi positif namun salah (prediksi positif; aktual negatif)
      • Aktualnya: bisa bayar
      • prediksinya: gagal bayar
    • false negative (FN): diprediksi negatif namun salah (prediksi negatif; aktual positif)
      • Aktualny: gagal bayar
      • Prediksi: bisa bayar

Untuk melakukan perhitungan confusion matrix kita akan menggunakan fungsi confusionMatrix() dari library(caret). Pada fungsi tersebut terdapat 3 parameter yang dapat kita manfaatkan, yaitu:

  • data = Data atau kolom hasil prediksi yang sudah ditransformasi menjadi label.
  • reference = Data atau kolom yang berisikan data real
  • positive = target apa yang ingin dijadikan positif value atau target apa yang kita petingkan.
loans_test$pred_label <- as.factor(loans_test$pred_label)
str(loans_test$pred_label)
##  Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...
# confusion matrix
library(caret)
confusionMatrix(data = loans_test$pred_label,
                reference = loans_test$not_paid,
                positive = "1")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0  19   1
##          1 140 152
##                                               
##                Accuracy : 0.5481              
##                  95% CI : (0.491, 0.6042)     
##     No Information Rate : 0.5096              
##     P-Value [Acc > NIR] : 0.09631             
##                                               
##                   Kappa : 0.1111              
##                                               
##  Mcnemar's Test P-Value : < 0.0000000000000002
##                                               
##             Sensitivity : 0.9935              
##             Specificity : 0.1195              
##          Pos Pred Value : 0.5205              
##          Neg Pred Value : 0.9500              
##              Prevalence : 0.4904              
##          Detection Rate : 0.4872              
##    Detection Prevalence : 0.9359              
##       Balanced Accuracy : 0.5565              
##                                               
##        'Positive' Class : 1                   
## 

TP: 96 TN: 90 FP: 69 FN: 57

4 metrics performa model: Accuracy, Sensitivity/Recall, Precision, Specificity

Accuracy

Seberapa banyak yang benar diprediksi dari keseluruhan data (positif maupun negatif).

TP+TN/TOTAL

# total data: nrow(loans.test)
(96 + 90) / nrow(loans_test)
## [1] 0.5961538

Note: tidak ada batasan mutlak berapa akurasi yang dianggap akurat (sudah baik), dikembalikan ke kebutuhan bisnis masing-masing.

Digunakan ketika:

  • Kelas target sama penting:
    • Mau memprediksi apakah customer masuk ke kelompok customer tertentu, dengan kasusnya kita punya strategi marketing untuk tiap kelompok.
  • Data balance -> Taret variable -> prob.table(table())

Ada kondisi ketika accuracy bukanlah metrics terpenting. Umumnya ketika:

  • Kita mementingkan salah satu kelas (misal, kelas target/positif)
  • Data kita imbalance

Slide link: https://docs.google.com/presentation/d/1Mvyl9BDUhnjuWjv3c2_JGiRBksq-MvfZa_7MjNpmjtY/edit#slide=id.g12b052d7607_0_136

Saat kita mementingkan kelas tertentu, maka kita dapat memilih antara menggunakan metrics Recall / Precision:

Sensitivity/Recall

Seberapa banyak yang benar diprediksi positif, dari yang reality-nya (aktualnya) positif.

TP/(TP+FN)

96 / (96 + 57)
## [1] 0.627451

Precision/Pos Pred Value

Seberapa banyak yang benar diprediksi positif, dari yang diprediksi positif.

TP/(TP+FP)

96 / (96 + 69)
## [1] 0.5818182

Specificity

Seberapa banyak yang tepat diprediksi negatif, dari yang reality-nya negatif. Jarang dipakai karena kita tidak sering fokus pada kelas negatif.

TN/(TN+FP)

90 / (90 + 69)
## [1] 0.5660377

Model Machine Learning - K-NN

k-NN adalah K-nearest neighboor. Metode ini akan mengkasifikasi data baru dengan membandingkan karakteristik data baru (data test) dengan data yang ada (data train). Kedekatan karakteristik tersebut diukur dengan Euclidean Distance hingga didapatkan jarak. Kemudian akan dipilih k tetangga terdekat dari data baru tersebut, kemudian ditentukan kelasnya menggunakan majority voting.

Picking Optimum k

  • Jangan terlalu besar: pemilihan kelas hanya berdasarkan kelas yang dominan dan mengabaikan pola kecil yang ternyata penting.
  • Jangan terlalu kecil: rentan mengklasifikasikan data baru ke kelas outlier.
  • k optimum adalah akar dari jumlah data kita: sqrt(nrow(data))

Contoh kasus: (honors not-honors) -> kelas target = 2 (low medium high) -> kelas target = 3

  • untuk menghindari seri ketika majority voting:
    • k harus ganjil bila jumlah kelas target genap
      (honors / not-honors) -> kelas target = 2
    • k harus genap bila jumlah kelas target ganjil
      (low / medium / high) -> kelas target = 3
  • bila hasil majority voting seri, maka kelas akan dipilih secara random.

Karakteristik k-NN

  • tidak membuat model: langsung mengklasifikasi saat itu juga, tidak belajar dari data, setiap ingin mengklasifikasi harus menyediakan data train lagi.
  • tidak ada asumsi
  • dapat memprediksi multiclass
  • baik untuk prediktor numerik (karena mengklasifikasikan berdasarkan jarak), tidak baik untuk prediktor kategorik
  • robust: performa nya bagus -> error nya kecil
  • tidak interpretable

Case Study

Melanjutkan dari studi kasus sebelumnya, kita akan coba bila klasifikasi peluang customer akan gagal bayar pinjaman dengan menggunakan k-NN. Apakah k-NN akan lebih baik dari logistic regression? Bagaimana performanya?

  1. Read Data + Data understanding Done
  2. Data Wrangling Done
  3. EDA Done
  4. Cross Validation Done
  5. Pemilihan Ulang Variable Numerik
  6. Data Pre-Processing new
  7. Predict
  8. Evaluation

Pemilihan Ulang Variable Numerik

Dikarenakan karakterisik dari K-NN hanya baik untuk prediktor yang bertipe numerik, maka dari itu kita akan mencoba membuang prediktor kategorik yang sudah kita buat pada model logistic regression.

model_step
## 
## Call:  glm(formula = not_paid ~ installment + annual_inc + grade + delinq_2yrs + 
##     home_ownership + verified, family = binomial, data = loans_train)
## 
## Coefficients:
##        (Intercept)         installment          annual_inc              gradeB  
##       -1.016867074         0.001129976        -0.000003002         0.120955536  
##             gradeC              gradeD              gradeE              gradeF  
##        0.449697161         0.757091610         0.698809943         0.650505301  
##             gradeG         delinq_2yrs   home_ownershipOWN  home_ownershipRENT  
##       -0.280828387         0.162157394         0.472482689         0.278843394  
##          verified1  
##        0.235884735  
## 
## Degrees of Freedom: 1243 Total (i.e. Null);  1231 Residual
## Null Deviance:       1725 
## Residual Deviance: 1639  AIC: 1665
# Data Train
loans_train_knn <- loans_train %>% 
  select(not_paid, installment, annual_inc, delinq_2yrs)

# Data Test  
loans_test_knn <- loans_test %>% 
  select(not_paid, installment, annual_inc, delinq_2yrs)

Data Pre-processing

Scaling

Scaling: menyamaratakan range variable prediktor

Scaling bisa menggunakan min-max normalization atau z-score standarization.

  • 1. Min-Max Normalization

Rumus = x-min(x) / max(x)-min(x)

normalize <- function(x){
  return ( 
    (x - min(x))/(max(x) - min(x)) 
           )
}
# contoh:
normalize(c(1,2,3,4,5)) # memampatkan range nilai menjadi 0-1
## [1] 0.00 0.25 0.50 0.75 1.00
  • Hasil akhirnya itu sudah pasti 0 - 1
    • Kita harus tau, berapakan nilai minimal dan nilai maksimal pada data kita
      • Karena jarak antara nilai maksimal dari setiap observasinya itu harus sama persis

Contoh:

Untuk kasus nilai ulangan -> range 0 - 100

  • Nilai Mat: 20 - 40 -> nilai min:0 & nilai max:100

  • Nilai Read: 70 - 100 -> nilai min:0 & nilai max:100

  • 2. Z-score Standarization: dapat menggunakan function scale()

Rumus = x-mean(x) / sd(x)

# contoh:
scale(c(1,2,3,4,5)) # data kita seberapa menyimpang (sd) dari pusatnya (mean)
##            [,1]
## [1,] -1.2649111
## [2,] -0.6324555
## [3,]  0.0000000
## [4,]  0.6324555
## [5,]  1.2649111
## attr(,"scaled:center")
## [1] 3
## attr(,"scaled:scale")
## [1] 1.581139

Note: untuk 1 data harus menggunakan 1 tipe scaling yang sama

Untuk k-NN, dipisahkan antara prediktor dan label (target variabelnya).

library(dplyr)
# prediktor train
loans_train_predictor <- loans_train_knn %>% 
  select(-not_paid)

# target train
loans_train_target <- loans_train_knn %>% 
  pull(not_paid) # untuk menarik vector/value yang tedapat pada kolom di data frame kita


# prediktor test
loans_test_predictor <- loans_test_knn %>% 
  select(-not_paid)

# taget test
loans_test_target <- loans_test_knn %>% 
  pull(not_paid)

Data prediktor akan discaling menggunakan z-score standarization. Data test juga harus discaling menggunakan parameter dari data train (karena menganggap data test adalah unseen data).

  • fungsi scale() terdiri dari beberapa parameter
    • object = object yang ingin di scaling
    • center = nilai center (diambil dari dilai center pada data train yang sudah discale)
    • scale = nilai sd (diambil dari dilai sd pada data train yang sudah discale)
# scaling data prediktor
loans_train_scale <- scale(x = loans_train_predictor)

loans_test_scale <- scale(x = loans_test_predictor,
                     center = attr(loans_train_scale, "scaled:center"),
                     scale = attr(loans_train_scale, "scaled:scale"))

Predict

Step 1: Kita akan melakukan kalkuasi berapakah nilai k paling optimum, dengan menggunakan fungsi sqrt() dari jumlah data kita.

# find optimum k
sqrt(nrow(loans_train_predictor))
## [1] 35.27038

Step 2: Kita akan langsung memprediksi dengan menggunakan fungsi knn() dari library(class).

Pada fungsi knn() terdapat 4 parameter yang akan kita isi, yaitu:

  • train = data train - prediktor, yang sudah discaling, tipe numerik
  • test = data test - prediktor, yang sudah discaling, tipe numerik
  • cl = data train - label (target) aktual (kategorikal)
  • k = jumlah k yang ditentukan dari nilai
library(class) # package untuk fungsi `knn()`

loans_pred_knn <- knn(train = loans_train_scale,
                   test = loans_test_scale,
                   cl = loans_train_target,
                   k = 35,
                   prob = T)
# cek hasil prediksi
loans_pred_knn
##   [1] 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 1 0 0 1 0 0
##  [38] 1 1 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 0 1 0 0 0 0 0 1 0 0 1 0
##  [75] 0 0 1 1 1 1 0 1 1 1 1 0 0 1 0 0 1 1 0 1 1 1 1 0 0 1 1 1 1 0 0 0 1 0 1 0 0
## [112] 1 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1
## [149] 0 0 0 1 0 1 0 0 0 1 0 0 1 0 1 1 1 1 0 1 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 1 1
## [186] 1 0 1 1 1 1 1 0 0 0 0 1 0 0 1 1 1 1 0 1 0 1 0 0 1 0 1 0 1 1 1 1 0 1 0 0 1
## [223] 0 1 1 1 0 1 0 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 1 1 0 0 1 0 0 1 0 0 1
## [260] 1 1 1 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 1 0 1 0 1 0 1 1
## [297] 1 0 1 1 0 0 0 1 1 1 0 1 0 0 0 0
## attr(,"prob")
##   [1] 0.5142857 0.5428571 0.6285714 0.6285714 0.5142857 0.6571429 0.5142857
##   [8] 0.6857143 0.6285714 0.6857143 0.6571429 0.5142857 0.5142857 0.6000000
##  [15] 0.5714286 0.6571429 0.6000000 0.5142857 0.6857143 0.5714286 0.5714286
##  [22] 0.5142857 0.5142857 0.5714286 0.5714286 0.5142857 0.5142857 0.6571429
##  [29] 0.5428571 0.5428571 0.5714286 0.5142857 0.5142857 0.6571429 0.5714286
##  [36] 0.5428571 0.6000000 0.6000000 0.7714286 0.5428571 0.5142857 0.5142857
##  [43] 0.6000000 0.6285714 0.7428571 0.5142857 0.6285714 0.5428571 0.6000000
##  [50] 0.6000000 0.5428571 0.6000000 0.6000000 0.6000000 0.5428571 0.5142857
##  [57] 0.5142857 0.5142857 0.5142857 0.7142857 0.5428571 0.5142857 0.5142857
##  [64] 0.7142857 0.5142857 0.5714286 0.6571429 0.7142857 0.5142857 0.6285714
##  [71] 0.6285714 0.6285714 0.6000000 0.6000000 0.6000000 0.5142857 0.6000000
##  [78] 0.6285714 0.6857143 0.5714286 0.6571429 0.5714286 0.6285714 0.6285714
##  [85] 0.5428571 0.5428571 0.6571429 0.5428571 0.6000000 0.6571429 0.5714286
##  [92] 0.5714286 0.5714286 0.7142857 0.6571429 0.5142857 0.5428571 0.5714286
##  [99] 0.7142857 0.5714286 0.5142857 0.5142857 0.5142857 0.6000000 0.6000000
## [106] 0.5142857 0.5714286 0.5142857 0.5428571 0.6857143 0.7428571 0.6857143
## [113] 0.7714286 0.6857143 0.5428571 0.5142857 0.6000000 0.5428571 0.6571429
## [120] 0.5142857 0.5714286 0.5428571 0.6571429 0.6000000 0.5142857 0.5714286
## [127] 0.6571429 0.6857143 0.5714286 0.5428571 0.6571429 0.5714286 0.6000000
## [134] 0.5714286 0.7142857 0.7142857 0.5428571 0.6285714 0.5714286 0.5714286
## [141] 0.7142857 0.5142857 0.7428571 0.5428571 0.6571429 0.5428571 0.5428571
## [148] 0.6000000 0.5428571 0.5428571 0.5142857 0.5714286 0.6285714 0.5714286
## [155] 0.6285714 0.5714286 0.5428571 0.5142857 0.6000000 0.6571429 0.5142857
## [162] 0.6857143 0.6285714 0.6000000 0.5428571 0.5142857 0.6000000 0.6857143
## [169] 0.5428571 0.5428571 0.5714286 0.5714286 0.6571429 0.6000000 0.5142857
## [176] 0.6571429 0.5142857 0.5000000 0.6571429 0.5142857 0.5428571 0.5714286
## [183] 0.5142857 0.5142857 0.5428571 0.6857143 0.6000000 0.6571429 0.6571429
## [190] 0.6571429 0.5428571 0.5142857 0.7428571 0.6285714 0.5142857 0.7142857
## [197] 0.5714286 0.5142857 0.6285714 0.6000000 0.5714286 0.6000000 0.5714286
## [204] 0.7142857 0.5714286 0.6857143 0.5428571 0.7142857 0.6571429 0.5142857
## [211] 0.5714286 0.6000000 0.5142857 0.6571429 0.5428571 0.5714286 0.5714286
## [218] 0.6285714 0.5142857 0.5142857 0.6285714 0.6000000 0.7142857 0.5714286
## [225] 0.5142857 0.5714286 0.5142857 0.5428571 0.7142857 0.7142857 0.5714286
## [232] 0.5428571 0.7428571 0.5428571 0.5142857 0.5142857 0.6000000 0.5428571
## [239] 0.5714286 0.5142857 0.5142857 0.5428571 0.5142857 0.5428571 0.5714286
## [246] 0.5428571 0.6571429 0.6571429 0.5428571 0.5142857 0.7142857 0.6571429
## [253] 0.5714286 0.5428571 0.5555556 0.5142857 0.5428571 0.6571429 0.6571429
## [260] 0.6000000 0.6285714 0.5714286 0.6388889 0.7714286 0.6000000 0.5714286
## [267] 0.6000000 0.5277778 0.5714286 0.6285714 0.6000000 0.5142857 0.5142857
## [274] 0.5714286 0.5142857 0.5833333 0.5142857 0.5714286 0.6000000 0.5428571
## [281] 0.6857143 0.6571429 0.6285714 0.5428571 0.7428571 0.5142857 0.7428571
## [288] 0.5714286 0.7142857 0.5428571 0.5428571 0.5945946 0.6000000 0.7142857
## [295] 0.6000000 0.5142857 0.6000000 0.6857143 0.5714286 0.6285714 0.6000000
## [302] 0.7142857 0.6285714 0.5714286 0.6000000 0.5714286 0.5714286 0.5428571
## [309] 0.5714286 0.5142857 0.6000000 0.5142857
## Levels: 0 1

Model evaluation

# confusion matrix
library(caret)

confusionMatrix(data = loans_pred_knn,
                reference = loans_test_target,
                positive = "1")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0  80  51
##          1  79 102
##                                           
##                Accuracy : 0.5833          
##                  95% CI : (0.5265, 0.6386)
##     No Information Rate : 0.5096          
##     P-Value [Acc > NIR] : 0.005326        
##                                           
##                   Kappa : 0.1692          
##                                           
##  Mcnemar's Test P-Value : 0.017882        
##                                           
##             Sensitivity : 0.6667          
##             Specificity : 0.5031          
##          Pos Pred Value : 0.5635          
##          Neg Pred Value : 0.6107          
##              Prevalence : 0.4904          
##          Detection Rate : 0.3269          
##    Detection Prevalence : 0.5801          
##       Balanced Accuracy : 0.5849          
##                                           
##        'Positive' Class : 1               
## 

Model Tuning

attributes(loans_pred_knn)$prob %>% 
  head()
## [1] 0.5142857 0.5428571 0.6285714 0.6285714 0.5142857 0.6571429
confmat_plot(prob = attributes(loans_pred_knn)$prob, # hasil prediksi probability
             ref = loans_test_target, # kolom label aktual
             postarget = "1", # label untuk nilai mendekati 1
             negtarget = "0") # label untuk nilai mendekati 0
loans_pred_knn_2 <- ifelse(test = attributes(loans_pred_knn)$prob > 0.45,
                                 yes = "1",
                                 no = "0")
confusionMatrix(data = as.factor(loans_pred_knn_2),
                reference = loans_test_target,
                positive = "1")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0   0   0
##          1 159 153
##                                              
##                Accuracy : 0.4904             
##                  95% CI : (0.4336, 0.5473)   
##     No Information Rate : 0.5096             
##     P-Value [Acc > NIR] : 0.7692             
##                                              
##                   Kappa : 0                  
##                                              
##  Mcnemar's Test P-Value : <0.0000000000000002
##                                              
##             Sensitivity : 1.0000             
##             Specificity : 0.0000             
##          Pos Pred Value : 0.4904             
##          Neg Pred Value :    NaN             
##              Prevalence : 0.4904             
##          Detection Rate : 0.4904             
##    Detection Prevalence : 1.0000             
##       Balanced Accuracy : 0.5000             
##                                              
##        'Positive' Class : 1                  
##