Klasifikasi bertujuan untuk memprediksi target variabel kategorik, seperti menentukan label/kelas. Klasifikasi dapat menentukan antara 2 kelas (binary) atau > 2 kelas (multiclass).
Pada dasarnya, ketika kita melakukan klasifikasi, kita menghitung peluang.
Contoh:
Anda adalah student Algoritma yang akan mengerjakan kuis C1. Pada batch sebelumnya, ada 18 dari 27 student yang berhasil mengerjakan kuis. Apakah Anda akan lulus pada kuis C1 ini?
#> [1] 0.6666667
#> [1] 0.3333333
#> [1] "lulus"
Tahapan:
Berapa range hasil prediksi model regresi?
Berapa range peluang?
Dibutuhkan suatu jembatan agar regression dapat digunakan untuk memprediksi peluang. Jembatan itu adalah Odds dan Log of Odds.
Odds adalah bentuk lain dari peluang yang memiliki rumus sebagai berikut \(\frac{p}{(1-p)}\) dimana p adalah peluang suatu kejadian terjadi. Odds adalah peluang kejadian terjadi/peluang kejadian tidak terjadi.
Contoh 1:
Berapa odds dari Anda lulus mengerjakan kuis C1?
#> [1] 0.6666667
#> [1] 2
Interpretasi:
Contoh 2:
Anda hendak berpergian menggunakan pesawat dari Soekarno Hatta Airport. Bila diketahui dari 100 penerbangan di Soekarno Hatta, terdapat 25 pesawat delay. Berapa odds pesawat Anda tidak delay?
#> [1] 0.75
#> [1] 3
Interpretasi:
Berapa range nilai dari odds?
#> [1] Inf
#> [1] 0
Log of odds adalah nilai odds yang dilogaritmikan \(logit(p) = log(\frac{p}{1-p})\) :
#> [1] 1.098612
#> [1] 0.6931472
Berapa range nilai log of odds?
#> [1] Inf
#> [1] -Inf
Log of Odds dihasilkan oleh Logistic Regression. Nilai log of odds dapat dikembalikan ke bentuk odds dan peluang sehingga dapat digunakan untuk klasifikasi.
#> [1] 2.999999
#> [1] 2
#> [1] 0.75
#> [1] 0.6666667
Apakah Anda akan lulus kuis? Apakah pesawat Anda akan tiba tepat waktu?
Terdapat cara lain untuk mengubah peluang ke log of odds dengan fungsi logit() dan mengubah log of odds ke peluang dengan fungsi inv.logit(). Fungsi inv.logit() yang biasa disebut sigmoidal logistic function.
#> [1] 1.098612
#> [1] 0.6931472
#> [1] 0.7499999
#> [1] 0.6666667
glm() & InterpretationAnda adalah seorang analis performa student di universitas. Anda ditugaskan untuk memprediksi status kelulusan siswa dengan honors (cumlaude).
# read & inspect data
honors <- read.csv("data_input/sample.csv") %>%
select(-femalexmath)
str(honors)#> 'data.frame': 200 obs. of 5 variables:
#> $ female: int 0 1 0 0 0 0 0 0 0 0 ...
#> $ read : int 57 68 44 63 47 44 50 34 63 57 ...
#> $ write : int 52 59 33 44 52 52 59 46 57 55 ...
#> $ math : int 41 53 54 47 57 51 42 45 54 52 ...
#> $ hon : int 0 0 0 0 0 0 0 0 0 0 ...
Deskripsi kolom:
female: gender of student (1 for female)read: score in reading testwrite: score in writing testmath: score in math testhon: status of graduating in honors (1 for honors)#> [1] FALSE
# data wrangling
honors <- honors %>%
mutate(female = as.factor(female),
hon = as.factor(hon))
str(honors)#> 'data.frame': 200 obs. of 5 variables:
#> $ female: Factor w/ 2 levels "0","1": 1 2 1 1 1 1 1 1 1 1 ...
#> $ read : int 57 68 44 63 47 44 50 34 63 57 ...
#> $ write : int 52 59 33 44 52 52 59 46 57 55 ...
#> $ math : int 41 53 54 47 57 51 42 45 54 52 ...
#> $ hon : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
Cara membuat model logistic regression:
glm(target ~ prediktor, data, family)
#>
#> 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
Intercept: log of odds dari target variabelnya (hon).
#>
#> 0 1
#> 151 49
#> [1] -1.12546
#> [1] -1.12546
Interpretasi:
Log of odds tidak dapat diinterpretasikan. Untuk interpretasi, nilai log of odds kita ubah ke odds/peluang.
# log of odds -> odds
odds <- exp(-1.1255)
# odds -> probability
prob <- odds/(odds+1)
# log of odds -> probability
inv.logit(-1.1255)#> [1] 0.2449925
#> [1] 0.3244902
#> [1] 0.2449925
Kejadian student lulus dengan predikat honors 0.32 KALI lebih mungkin dibandingkan student lulus tanpa predikat honors.
Peluang student lulus dengan predikat honors adalah 0.24.
Student lebih mungkin untuk lulus tanpa predikat honors.
Buat model untuk memprediksi honors berdasarkan gender female:
#>
#> Call:
#> glm(formula = hon ~ female, family = "binomial", data = honors)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -0.8337 -0.8337 -0.6431 -0.6431 1.8317
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -1.4709 0.2690 -5.469 0.0000000453 ***
#> female1 0.5928 0.3414 1.736 0.0825 .
#> ---
#> 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: 219.61 on 198 degrees of freedom
#> AIC: 223.61
#>
#> Number of Fisher Scoring iterations: 4
Female: log of odds dari female mendapat honor dibandingkan male mendapat honor.
#>
#> 0 1
#> 91 109
#> [1] 0.1804884
#> female
#> honors 0 1
#> 0 74 77
#> 1 17 32
# peluang female dapat honors
honf <- 32/(77+32)
# peluang male dapat honors
honm <- 17/(17+74)
# odds
oddsf <- honf/(1-honf)
oddsm <- honm/(1-honm)#> [1] 0.5927822
Intercept: log of odds dari male mendapatkan honors (basis).
#> [1] -1.470852
Interpretasi:
#> [1] 1.809014
Kejadian female mendapatkan honors 1.8 KALI lebih mungkin dibandingkan male mendapatkan honors.
Memiliki gender female menaikan kemungkinan student mendapatkan honors.
Aplikasi:
Misalkan student ke-1 seorang wanita, berapa peluang dia mendapatkan honors?
formula: hon = -1.4709 + 0.5928 * female
#> [1] 0.2935717
female = 0.2935717
Misalkan student ke-2 seorang pria, berapa peluang dia mendapatkan honors?
#> [1] 0.1868059
male = 0.1868059
“Student wanita memiliki peluang lebih tinggi untuk mendapatkan honors dibandingkan student pria (0.29 > 0.19), namun keduanya masih memiliki peluang yang rendah untuk mendapat honors.”
Buat model untuk memprediksi honors berdasarkan nilai math:
#>
#> Call:
#> glm(formula = hon ~ math, family = "binomial", data = honors)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -2.0332 -0.6785 -0.3506 -0.1565 2.6143
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -9.79394 1.48174 -6.610 0.0000000000385 ***
#> math 0.15634 0.02561 6.105 0.0000000010294 ***
#> ---
#> 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: 167.07 on 198 degrees of freedom
#> AIC: 171.07
#>
#> Number of Fisher Scoring iterations: 5
Intercept: Log of odds dari student yang nilai mathnya 0.
Math: Peningkatan log of odds setiap peningkatan 1 nilai di math.
contoh:
hon = -9.79394 + 0.15634 * math
Student ke-1 memiliki nilai math 52, student kedua 53. Hitung masing-masing log of oddsnya, berapa selisihnya?
#> [1] 0.15634
Interpretasi:
#> [1] 1.169224
Setiap kenaikan 1 nilai pada math maka odds seseorang mendapatkan honor naik sebesar 1.17 KALI.
#> [1] 1.169224
Siswa dengan nilai 53 akan 1.17 KALI lebih mungkin mendapatkan honors dibandingkan yang mendapat nilai 52.
Memiliki nilai math yang lebih tinggi meningkatkan peluang student mendapatkan honors.
#> [1] 0.2588311
#> [1] 0.258831
Buat model untuk memprediksi honors berdasarkan gender female dan nilai math:
honors.logit4 <- glm(hon ~ female + math , data = honors, family = "binomial")
summary(honors.logit4)#>
#> Call:
#> glm(formula = hon ~ female + math, family = "binomial", data = honors)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -1.8494 -0.6506 -0.3471 -0.1361 2.5105
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -10.80595 1.61654 -6.685 0.0000000000232 ***
#> female1 0.96531 0.41599 2.321 0.0203 *
#> math 0.16422 0.02665 6.161 0.0000000007206 ***
#> ---
#> 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: 161.35 on 197 degrees of freedom
#> AIC: 167.35
#>
#> Number of Fisher Scoring iterations: 5
Interpretasi koefisien:
cari odds dari masing masing predictor:
#> [1] 2.625601
#> [1] 1.178474
female = 2.625601
kejadian female mendapatkan honor 2.6 kali lebih mungkin dibandingkan male mendapatkan honor dengan catatan variabel lainnya memiliki nilai yang sama.
math = 1.178474
setiap kenaikan 1 nilai pada math, odds mendapatkan honor naik sebesar 1.18 kali dengan catatan nilai variabel lainnya sama.
Aplikasi:
hon = -10.80595 + (0.96531 * female) + (0.16422 * math)
Handoyo adalah seorang male yang nilai math-nya 60, berapa peluang dia mendapatkan honors? Apakah dia akan lulus dengan honors?
#> [1] 0.5081418
Nabiilah adalah seorang female dan nilai math-nya 70, berapa peluang dia mendapatkan honors? Apakah dia akan lulus dengan honors?
#> [1] 0.8395333
#> [1] "honors"
AIC mengestimasi jumlah informasi yang hilang dari suatu model. Semakin kecil AIC, semakin baik model.
#> [1] 224.71
#> [1] 223.6062
#> [1] 171.0732
#> [1] 167.3454
Deviance is defined as the difference of likelihoods between the fitted model and the perfect (saturated) model.
Ambil model dengan selisih antara null deviance dan residual deviance yang paling tinggi.
#> [1] 222.71
#> [1] 219.6062
#> [1] 167.0732
#> [1] 161.3454
Reference: https://bookdown.org/egarpor/SSS2-UC3M/logreg-deviance.html
—End of Day 1—
Summary: 1. Apa hubungan Logistic Regression dengan Klasifikasi? klasifikasi <- probability <-> odds <-> log of odds <- logistic regression
Klasifikasi membutuhkan peluang dengan range 0-1. Regresi akan mengasilkan range -Inf - +Inf. Logistic regression menghasilkan log of odds yang bisa diubah kembali ke peluang. Nilai peluang tersebut kemudian digunakan untuk klasifikasi (menggunakan ifelse()).
Logistic regression menghasilkan? Log of odds
Untuk interpretasi model logistic regression, harus dilakukan apa, menggunakan fungsi apa? Log of odds harus dieksponenkan untuk menghasilkan odds, menggunakan fungsi exp().
Interpretasi koefisien dapat dilakukan untuk model dan berbeda untuk masing-masing kondisi: - tanpa prediktor - 1 prediktor kategorik - 1 prediktor numerik - banyak prediktor
Log of odds harus diubah ke peluang, pakai fungsi inv.logit(). Peluang kemudian di ifelse() kan, untuk menentukan masuk ke kelas yang mana (negatif(0)/positif(1))
— DAY 2 —
Review
Buat model prediksi honors.logit5 untuk memprediksi hon berdasarkan gender female dan nilai read. Tampilkan summary-nya!
#>
#> Call:
#> glm(formula = hon ~ female + read, family = "binomial", data = honors)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -1.6076 -0.6785 -0.4254 -0.1566 2.3410
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -8.58001 1.33490 -6.427 0.00000000013 ***
#> female1 0.94474 0.39743 2.377 0.0174 *
#> read 0.12567 0.02187 5.745 0.00000000917 ***
#> ---
#> 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: 174.81 on 197 degrees of freedom
#> AIC: 180.81
#>
#> Number of Fisher Scoring iterations: 5
Interpretasikan koefisien female:
#> [1] 2.572145
Kejadian kelulusan student female yang dapat honors adalah 2.6 KALI lebih mungkin dibandingkan student male yang dapat honors dengan catatan variable lainnya memiliki nilai yang sama
Interpretasikan koefisien read:
#> [1] 1.133908
Setiap kenaikan 1 unit (nilai) dari read akan meningkatkan odds student mendapatkan honors sebesar 1.1 KALI
Nabiilah mempunyai nilai read 50. Berapa peluang dia lulus dengan predikat honors?
#> [1] 1.03596
#> [1] 0.7380697
Apakah Nabiilah akan lulus dengan predikat honors?…
#> [1] "non-honors"
Bila tidak lulus dengan honors, apa yang harus dilakukan Nabiilah agar dapat lulus dengan honors? (hint: lihat interpretasi model)
Buat model ‘honors.logit6’ untuk memprediksi honors berdasarkan semua prediktor yang ada:
#> Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
#>
#> Call:
#> glm(formula = hon ~ ., family = "binomial", data = honors, maxit = 50)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -0.0000126860 -0.0000000211 -0.0000000211 -0.0000000211 0.0000092044
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -2892.73023 5439827.02909 -0.001 1
#> female1 -4.38394 354822.87467 0.000 1
#> read 0.07349 9635.55727 0.000 1
#> write 48.13764 92977.35476 0.001 1
#> math -0.36424 26760.81457 0.000 1
#>
#> (Dispersion parameter for binomial family taken to be 1)
#>
#> Null deviance: 222.71004668626614 on 199 degrees of freedom
#> Residual deviance: 0.00000000036453 on 195 degrees of freedom
#> AIC: 10
#>
#> Number of Fisher Scoring iterations: 31
Perfect Separation adalah sebuah kondisi dimana ada 1 variabel yang dapat memisahkan kelas target secara sempurna. Cara mendeteksi:
#> [1] 805214197686575955908
Pada kasus ini adalah nilai write dapat memisahkan kelas honor dengan baik:
#>
#> 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
ada 2 hal yg bisa kita lakukan:
ifelse saja.# revisi model
honors.logit7 <- glm(hon~female + read + math, data = honors, family = "binomial")
summary(honors.logit7)#>
#> Call:
#> glm(formula = hon ~ female + read + math, family = "binomial",
#> data = honors)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -1.8305 -0.6327 -0.3300 -0.1258 2.3896
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -11.77025 1.71068 -6.880 0.00000000000597 ***
#> female1 0.97995 0.42163 2.324 0.0201 *
#> read 0.05906 0.02655 2.224 0.0261 *
#> math 0.12296 0.03128 3.931 0.00008442731719 ***
#> ---
#> 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: 156.17 on 196 degrees of freedom
#> AIC: 164.17
#>
#> Number of Fisher Scoring iterations: 5
Logistic Regression menganut 3 asumsi:
Asumsi logistic regression menuntut kita untuk memahami data secara mendalam dan memastikan data sudah siap dipakai untuk membuat model.
Dive Deeper
Berikut data penerbangan pesawat dalam flight_sm.csv:
flight <- read.csv("data_input/flight_sm.csv") %>%
mutate(DepDel15 = as.factor(DepDel15))
str(flight)#> 'data.frame': 538363 obs. of 10 variables:
#> $ Year : int 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
#> $ Month : int 9 9 9 7 5 7 10 10 5 6 ...
#> $ DayofMonth : int 16 23 7 15 16 28 6 9 12 30 ...
#> $ DayofWeek : int 1 1 6 1 4 7 7 3 7 7 ...
#> $ Carrier : Factor w/ 16 levels "9E","AA","AS",..: 5 15 3 11 5 12 15 2 12 11 ...
#> $ CRSDepTime : int 1539 1400 810 804 805 1251 2000 1010 1522 1404 ...
#> $ DepDel15 : Factor w/ 2 levels "0","1": 1 2 1 1 1 2 2 1 1 2 ...
#> $ CRSArrTime : int 1824 1425 1614 1027 1117 1700 2135 1240 2017 1507 ...
#> $ OriginState: Factor w/ 36 levels "AK","AZ","CA",..: 7 28 35 10 24 32 3 10 23 3 ...
#> $ DestState : Factor w/ 36 levels "AK","AZ","CA",..: 24 10 6 25 7 6 23 32 32 3 ...
Dekspripsi kolom:
Year, Month, DayofMonth, DayofWeek: self-explanatoryCarrier: maskapaiCRSDepTime & CRSArrTime: jadwal departure & arrival (hhmm)DepDel15: status delay (1 = delay)OriginState, DestState: lokasi keberangkatan & tujuan#> [1] 5
Discussion:
Buat model flight.model untuk memprediksi DepDel15 berdasarkan Month + DayofWeek, kemudian tampilkan summary-nya:
flight.model <- glm(DepDel15 ~ Month + DayofWeek, data = flight, family = "binomial")
summary(flight.model)#>
#> Call:
#> glm(formula = DepDel15 ~ Month + DayofWeek, family = "binomial",
#> data = flight)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -0.7308 -0.6911 -0.6518 -0.6168 1.8786
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -0.935641 0.013900 -67.312 < 0.0000000000000002 ***
#> Month -0.060895 0.001718 -35.454 < 0.0000000000000002 ***
#> DayofWeek -0.004576 0.001710 -2.676 0.00744 **
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> (Dispersion parameter for binomial family taken to be 1)
#>
#> Null deviance: 541635 on 538362 degrees of freedom
#> Residual deviance: 540365 on 538360 degrees of freedom
#> AIC: 540371
#>
#> Number of Fisher Scoring iterations: 4
Perhatikan model dan diskusikan bersama kelompok Anda:
#> Month
#> 0.9409219
#> DayofWeek
#> 0.9954342
#> Month DayofWeek
#> 1.000017 1.000017
# penyesuaian
flight$Month <- as.factor(flight$Month)
flight$DayofWeek <- as.factor(flight$DayofWeek)
# pembuatan model baru
flight.model2 <- glm(DepDel15 ~ Month + DayofWeek, data = flight, family = "binomial")
summary(flight.model2)#>
#> Call:
#> glm(formula = DepDel15 ~ Month + DayofWeek, family = "binomial",
#> data = flight)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -0.8740 -0.7155 -0.6314 -0.5429 2.0641
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -1.34623 0.01196 -112.608 < 0.0000000000000002 ***
#> Month5 -0.10637 0.01292 -8.235 < 0.0000000000000002 ***
#> Month6 0.35314 0.01222 28.899 < 0.0000000000000002 ***
#> Month7 0.23991 0.01225 19.585 < 0.0000000000000002 ***
#> Month8 -0.01661 0.01270 -1.308 0.191
#> Month9 -0.36450 0.01382 -26.368 < 0.0000000000000002 ***
#> Month10 -0.32892 0.01351 -24.350 < 0.0000000000000002 ***
#> DayofWeek2 -0.16516 0.01275 -12.954 < 0.0000000000000002 ***
#> DayofWeek3 -0.05737 0.01251 -4.586 0.0000045233803 ***
#> DayofWeek4 0.22770 0.01206 18.879 < 0.0000000000000002 ***
#> DayofWeek5 0.13083 0.01224 10.690 < 0.0000000000000002 ***
#> DayofWeek6 -0.29298 0.01384 -21.172 < 0.0000000000000002 ***
#> DayofWeek7 -0.08550 0.01280 -6.677 0.0000000000243 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> (Dispersion parameter for binomial family taken to be 1)
#>
#> Null deviance: 541635 on 538362 degrees of freedom
#> Residual deviance: 534556 on 538350 degrees of freedom
#> AIC: 534582
#>
#> Number of Fisher Scoring iterations: 4
Month ke-6 dan Day of Week ke-4 memiliki kemungkinan paling tinggi untuk Delay
Buat model untuk memprediksi peluang customer akan gagal bayar pinjaman (loan default), untuk mengindikasikan apakah customer tersebut baik atau tidak untuk diberikan pinjaman.
#> Observations: 1,556
#> Variables: 16
#> $ initial_list_status <fct> w, f, w, w, w, w, w, w, w, w, w, w, w, f, w, w,...
#> $ purpose <fct> debt_consolidation, debt_consolidation, debt_co...
#> $ int_rate <dbl> 14.08, 9.44, 28.72, 13.59, 15.05, 10.91, 15.05,...
#> $ installment <dbl> 675.99, 480.08, 1010.30, 484.19, 476.33, 130.79...
#> $ annual_inc <dbl> 156700, 50000, 25000, 175000, 109992, 49000, 65...
#> $ dti <dbl> 19.11, 19.35, 65.58, 12.60, 10.00, 5.12, 22.38,...
#> $ verification_status <fct> Source Verified, Not Verified, Verified, Not Ve...
#> $ grade <fct> C, B, F, C, C, B, C, B, D, D, F, C, C, E, B, C,...
#> $ revol_bal <int> 21936, 5457, 23453, 31740, 2284, 2016, 14330, 2...
#> $ inq_last_12m <int> 3, 1, 0, 0, 3, 5, 0, 1, 8, 1, 0, 12, 4, 8, 1, 3...
#> $ delinq_2yrs <int> 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,...
#> $ home_ownership <fct> MORTGAGE, RENT, OWN, MORTGAGE, MORTGAGE, MORTGA...
#> $ not_paid <int> 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1,...
#> $ log_inc <dbl> 11.962088, 10.819778, 10.126631, 12.072541, 11....
#> $ verified <int> 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,...
#> $ grdCtoA <int> 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0,...
Target: not_paid
Adakah variabel yang tipe datanya belum sesuai?
#> initial_list_status purpose int_rate installment
#> f: 323 credit_card :321 Min. : 5.32 Min. : 31.04
#> w:1233 debt_consolidation:996 1st Qu.:10.42 1st Qu.: 247.26
#> home_improvement :161 Median :14.08 Median : 381.23
#> major_purchase : 51 Mean :14.71 Mean : 468.72
#> small_business : 27 3rd Qu.:18.06 3rd Qu.: 635.86
#> Max. :30.94 Max. :1503.89
#>
#> annual_inc dti verification_status grade
#> Min. : 2500 Min. : 0.00 Not Verified :578 A:210
#> 1st Qu.: 48000 1st Qu.: 11.00 Source Verified:538 B:385
#> Median : 68000 Median : 17.18 Verified :440 C:464
#> Mean : 81630 Mean : 18.86 D:326
#> 3rd Qu.: 95700 3rd Qu.: 24.53 E:118
#> Max. :1200000 Max. :198.56 F: 38
#> G: 15
#> revol_bal inq_last_12m delinq_2yrs home_ownership
#> Min. : 0 Min. : 0.000 Min. :0.0000 MORTGAGE:776
#> 1st Qu.: 4974 1st Qu.: 1.000 1st Qu.:0.0000 OWN :201
#> Median : 10163 Median : 2.000 Median :0.0000 RENT :579
#> Mean : 15258 Mean : 2.359 Mean :0.3059
#> 3rd Qu.: 18094 3rd Qu.: 3.000 3rd Qu.:0.0000
#> Max. :258897 Max. :18.000 Max. :8.0000
#>
#> not_paid log_inc verified grdCtoA
#> Min. :0.0 Min. : 7.824 Min. :0.0000 Min. :0.0000
#> 1st Qu.:0.0 1st Qu.:10.779 1st Qu.:0.0000 1st Qu.:0.0000
#> Median :0.5 Median :11.127 Median :1.0000 Median :0.0000
#> Mean :0.5 Mean :11.123 Mean :0.6285 Mean :0.3824
#> 3rd Qu.:1.0 3rd Qu.:11.469 3rd Qu.:1.0000 3rd Qu.:1.0000
#> Max. :1.0 Max. :13.998 Max. :1.0000 Max. :1.0000
#>
# data wrangling
loans <- loans %>%
select(-log_inc, -verification_status, -grade) %>%
mutate(not_paid = as.factor(not_paid),
verified = as.factor(verified),
grdCtoA = as.factor(grdCtoA))#> initial_list_status purpose int_rate installment
#> 0 0 0 0
#> annual_inc dti revol_bal inq_last_12m
#> 0 0 0 0
#> delinq_2yrs home_ownership not_paid verified
#> 0 0 0 0
#> grdCtoA
#> 0
#> initial_list_status purpose int_rate installment
#> f: 323 credit_card :321 Min. : 5.32 Min. : 31.04
#> w:1233 debt_consolidation:996 1st Qu.:10.42 1st Qu.: 247.26
#> home_improvement :161 Median :14.08 Median : 381.23
#> major_purchase : 51 Mean :14.71 Mean : 468.72
#> small_business : 27 3rd Qu.:18.06 3rd Qu.: 635.86
#> Max. :30.94 Max. :1503.89
#> annual_inc dti revol_bal inq_last_12m
#> Min. : 2500 Min. : 0.00 Min. : 0 Min. : 0.000
#> 1st Qu.: 48000 1st Qu.: 11.00 1st Qu.: 4974 1st Qu.: 1.000
#> Median : 68000 Median : 17.18 Median : 10163 Median : 2.000
#> Mean : 81630 Mean : 18.86 Mean : 15258 Mean : 2.359
#> 3rd Qu.: 95700 3rd Qu.: 24.53 3rd Qu.: 18094 3rd Qu.: 3.000
#> Max. :1200000 Max. :198.56 Max. :258897 Max. :18.000
#> delinq_2yrs home_ownership not_paid verified grdCtoA
#> Min. :0.0000 MORTGAGE:776 0:778 0:578 0:961
#> 1st Qu.:0.0000 OWN :201 1:778 1:978 1:595
#> Median :0.0000 RENT :579
#> Mean :0.3059
#> 3rd Qu.:0.0000
#> Max. :8.0000
Take away: delinq2yrs kurang baik untuk dijadikan prediktor karena nilainya dominan di angka nol (kurang informatif).
Literature: Higher debt-to-income ratio (dti) and amount of credit card debts are both associated with a greater likelihood of loan defaults.
Ternyata dari hasil eksplorasi, dti tidak terlalu memberikan perbedaan antara yang gagal bayar (not_paid = 1) dan berhasil bayar (not_paid = 0). Namun bila berdasarkan business knowledge variabel tersebut dibutuhkan, maka tetap digunakan untuk pembuatan model.
Small business memiliki proporsi not_paid paling besar, dan masing-masing purpose memiliki perbedaan proporsi antara yang not_paid dan paid. Variable purpose sepertinya baik untuk digunakan sebagai prediktor.
3. Cek class-imbalance
#>
#> 0 1
#> 778 778
Proporsi yang seimbang penting untuk training model klasifikasi agar model secara seimbang mempelajari karakteristik kelas positif maupun negatif, tidak dari satu kelas saja.
Proporsi yang imbalance umumnya 90/10 atau 95/5.
Analogi:
tujuan dari cross validation adalah untuk mengetahui seberapa baik model yg sudah kita buat.
# splitting
set.seed(417)
intrain <- sample(nrow(loans), nrow(loans)*0.8)
loans.train <- loans[intrain, ]
loans.test <- loans[-intrain, ]#>
#> 0 1
#> 617 627
Membuat model berdasarkan business knowledge dan arahan yang sudah ada:
creditrisk <- glm(not_paid ~ verified + purpose + installment + int_rate + home_ownership + grdCtoA + annual_inc, loans.train, family="binomial")
summary(creditrisk)#>
#> Call:
#> glm(formula = not_paid ~ verified + purpose + installment + int_rate +
#> home_ownership + grdCtoA + annual_inc, family = "binomial",
#> data = loans.train)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -2.004 -1.133 0.606 1.124 1.615
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -0.735669776 0.331601065 -2.219 0.0265 *
#> verified1 0.264041602 0.123878393 2.131 0.0331 *
#> purposedebt_consolidation 0.179765076 0.151680779 1.185 0.2360
#> purposehome_improvement 0.272064596 0.227839274 1.194 0.2324
#> purposemajor_purchase 0.395435735 0.340497446 1.161 0.2455
#> purposesmall_business 1.241226717 0.504183127 2.462 0.0138 *
#> installment 0.000999802 0.000224562 4.452 0.0000085 ***
#> int_rate 0.016724595 0.016155807 1.035 0.3006
#> home_ownershipOWN 0.266724768 0.188172699 1.417 0.1564
#> home_ownershipRENT 0.075821488 0.131458306 0.577 0.5641
#> grdCtoA1 -0.339721466 0.179992880 -1.887 0.0591 .
#> annual_inc -0.000002898 0.000001176 -2.465 0.0137 *
#> ---
#> 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: 1648.7 on 1232 degrees of freedom
#> AIC: 1672.7
#>
#> Number of Fisher Scoring iterations: 4
Interpretasi:
#> [1] 2.325071
#> [1] 1.012386
Kejadian loan default (not_paid) dengan purpose small business adalah 2.3 KALI lebih mungkin dibandingkan kalau purposenya credit card dengan catatan variabel lainnya memiliki nilai yang sama
Kenaikan int_rate sebesar 1 unit akan menaikan odds loan default sebesar 1.01 KALI dengan catatan variabel lainnya memiliki nilai yang sama.
Apakah ada prediktor yang dapat dibuang?
#> Start: AIC=1672.7
#> not_paid ~ verified + purpose + installment + int_rate + home_ownership +
#> grdCtoA + annual_inc
#>
#> Df Deviance AIC
#> - home_ownership 2 1650.8 1670.8
#> - int_rate 1 1649.8 1671.8
#> <none> 1648.7 1672.7
#> - purpose 4 1656.7 1672.7
#> - grdCtoA 1 1652.3 1674.3
#> - verified 1 1653.2 1675.2
#> - annual_inc 1 1656.0 1678.0
#> - installment 1 1669.4 1691.4
#>
#> Step: AIC=1670.75
#> not_paid ~ verified + purpose + installment + int_rate + grdCtoA +
#> annual_inc
#>
#> Df Deviance AIC
#> - int_rate 1 1651.9 1669.9
#> <none> 1650.8 1670.8
#> - purpose 4 1659.0 1671.0
#> - grdCtoA 1 1654.3 1672.3
#> - verified 1 1655.2 1673.2
#> - annual_inc 1 1658.5 1676.5
#> - installment 1 1671.2 1689.2
#>
#> Step: AIC=1669.87
#> not_paid ~ verified + purpose + installment + grdCtoA + annual_inc
#>
#> Df Deviance AIC
#> <none> 1651.9 1669.9
#> - purpose 4 1660.5 1670.5
#> - verified 1 1656.6 1672.6
#> - annual_inc 1 1660.3 1676.3
#> - grdCtoA 1 1667.0 1683.0
#> - installment 1 1675.4 1691.4
#>
#> Call: glm(formula = not_paid ~ verified + purpose + installment + grdCtoA +
#> annual_inc, family = "binomial", data = loans.train)
#>
#> Coefficients:
#> (Intercept) verified1
#> -0.389177154 0.268124157
#> purposedebt_consolidation purposehome_improvement
#> 0.187632632 0.269026076
#> purposemajor_purchase purposesmall_business
#> 0.420716146 1.279922730
#> installment grdCtoA1
#> 0.001040645 -0.478750911
#> annual_inc
#> -0.000003108
#>
#> Degrees of Freedom: 1243 Total (i.e. Null); 1235 Residual
#> Null Deviance: 1724
#> Residual Deviance: 1652 AIC: 1670
# save model hasil stepwise
creditrisk2 <- glm(formula = not_paid ~ verified + purpose + installment + grdCtoA +
annual_inc, family = "binomial", data = loans.train)
summary(creditrisk2)#>
#> Call:
#> glm(formula = not_paid ~ verified + purpose + installment + grdCtoA +
#> annual_inc, family = "binomial", data = loans.train)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -1.9464 -1.1367 0.6484 1.1191 1.6000
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) -0.389177154 0.186974237 -2.081 0.037393 *
#> verified1 0.268124157 0.123523261 2.171 0.029959 *
#> purposedebt_consolidation 0.187632632 0.150880916 1.244 0.213654
#> purposehome_improvement 0.269026076 0.222377945 1.210 0.226367
#> purposemajor_purchase 0.420716146 0.339730644 1.238 0.215575
#> purposesmall_business 1.279922730 0.501421368 2.553 0.010693 *
#> installment 0.001040645 0.000219656 4.738 0.00000216 ***
#> grdCtoA1 -0.478750911 0.123153857 -3.887 0.000101 ***
#> annual_inc -0.000003108 0.000001173 -2.650 0.008057 **
#> ---
#> 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: 1651.9 on 1235 degrees of freedom
#> AIC: 1669.9
#>
#> Number of Fisher Scoring iterations: 4
predict(model, newdata, type)
type memiliki 2 nilai yaitu response dan link. nilai response akan mengembalikan probability, sedangakan nilai link akan mengembalikan log of odds.
Prediksi log of odds not_paid untuk 6 data teratas:
#> 2 9 10 24 26 28
#> -0.3360959 0.4247721 0.2277538 0.3442791 0.5447256 -0.2581772
Prediksi probability not_paid untuk 6 data teratas:
#> 2 9 10 24 26 28
#> 0.4167581 0.6046246 0.5566936 0.5852296 0.6329110 0.4358119
Prediksi probability not_paid untuk data loans.test dan disimpan pada kolom baru bernama pred.Risk.
Klasifikasikan data loans.test berdasarkan pred.Risk dan simpan pada kolom baru bernama pred.Label.
# ifelse(kondisi, benar, salah)
loans.test$pred.Label <- ifelse(loans.test$pred.Risk > 0.5, "1", "0")
# ubah kelas target (aktual dan prediksi) menjadi factor
loans.test <- loans.test %>%
mutate(pred.Label = as.factor(pred.Label))— End Day 2 —
Setelah dilakukan prediksi menggunakan model, masih ada saja prediksi yang salah. Pada klasifikasi, selain menggunakan AIC, kita mengevaluasi model berdasarkan confusion matrix:
# confusion matrix sederhana
# table(predicted = loans.test$pred.Label,
# actual = loans.test$not_paid)# melihat persebaran hasil prediksi
# hist(loans.test$pred.Risk, breaks = 20)
# abline(v=0.5, col="blue", lwd=3)4 metrics performa model: Accuracy, Sensitivity/Recall, Precision, Specificity
6.1 Accuracy
seberapa baik model kita memprediksi kelas target (positif maupun negatif). dipakai ketika kelas positif dan negatif sama pentingnya atau ketika proporsi kelas seimbang.
(TP+TN/TOTAL)
Dalam bisnis/real-case, tak selamanya kita hanya mementingkan metric accuracy. Sering kali harus memilih antara meninggikan recall/precision. Hal ini tergantung pada kasus bisnis/efek yang ditimbulkan dari hasil prediksi tersebut.
6.2 Sensitivity/Recall
seberapa banyak yang tepat diprediksi positif, dari yang reality-nya positif.
(TP/(TP+FN))
6.3 Pos Pred Value/Precision
seberapa banyak yang tepat diprediksi positif, dari yang diprediksi positif.
(TP/(TP+FP))
ROLE PLAY:
Bos: Seller:
6.4 Specificity
ukuran kebaikan model terhadap kelas negatif. seberapa banyak yang tepat diprediksi negatif, dari yang reality-nya negatif.
(TN/(TN+FP))
Bila sudah membuat beberapa model atau melakukan tuning treshold, dapat dibandingkan nilai pada confusion matrixnya kemudian pilih yang memberikan nilai terbaik menurut kebutuhan Anda (Accuracy/Recall/Precision).