Klasifikasi bertujuan untuk memprediksi kelas (target variable kategorik):
Berapa range peluang?
Berapa range hasil prediksi model regresi?
Dibutuhkan suatu jembatan agar regression dapat digunakan untuk memprediksi peluang. Jembatan itu adalah Odds dan Log of Odds.
Odds adalah bentuk lain dari peluang, yaitu perbandingan peluang antara peluang kejadian terjadi/peluang kejadian tidak terjadi.
\[\frac{p}{(1-p)}\]
p = peluang suatu kejadian terjadi
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
On Time?
#> [1] 3
Interpretasi:
Note: Kalau oddsnya 1 berarti peluangnya? 0.5
Berapa range nilai dari odds?
#> [1] 0
#> [1] Inf
Log of odds adalah nilai odds yang dilogaritmikkan:
\(logit(p) = log(\frac{p}{1-p})\)
#> [1] 1.098612
Berapa range nilai log of odds?
#> [1] -Inf
#> [1] Inf
Odds dan log of odds mampu menjembatani antara nilai yang dihasilkan oleh model regresi, ke rentang nilai peluang. Logistic regression menghasilkan Log of Odds. Nilai log of odds dapat dikembalikan ke bentuk odds (untuk diinterpretasikan) dan peluang sehingga dapat digunakan untuk klasifikasi.
#> [1] 3.999999
Terdapat cara lain:
logit(): peluang -> log of oddsinv.logit(): log of odds -> peluang#> [1] 1.386294
#> [1] 0.7999999
Fungsi inv.logit() ini juga biasa disebut sigmoid
function.
glm() & InterpretationAnda adalah seorang analis performa student di universitas. Anda ditugaskan untuk memprediksi status kelulusan siswa dengan honors (cumlaude).
# read & inspect data
library(dplyr)
honors <- read.csv("data_input/sample.csv") %>%
select(-femalexmath)
glimpse(honors)#> Rows: 200
#> Columns: 5
#> $ female <int> 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ read <int> 57, 68, 44, 63, 47, 44, 50, 34, 63, 57, 60, 57, 73, 54, 45, 42,…
#> $ write <int> 52, 59, 33, 44, 52, 52, 59, 46, 57, 55, 46, 65, 60, 63, 57, 49,…
#> $ math <int> 41, 53, 54, 47, 57, 51, 42, 45, 54, 52, 51, 51, 71, 57, 50, 43,…
#> $ hon <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 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
Cara membuat model logistic regression:
glm(target ~ prediktor, data, family = "binomial")
#>
#> 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 (student mendapatkan honors (1))
Berikut pembuktiannya:
#>
#> 0 1
#> 151 49
#> [1] -1.12546
Interpretasi: Log of odds tidak dapat diinterpretasikan. Untuk interpretasi, nilai log of odds kita ubah ke odds.
#> [1] 0.3245032
berarti kemungkinan calon siswa mendapatkan honors 0.32 kali lebih mungkin dari pada tidak mendapatkan honors
kemungkinan calon siswa lebih kecil mendapatkan honor dari pada tidak mendapatkan honors
Buat model untuk memprediksi honors berdasarkan gender
female:
honors.logit2 <- glm(formula = hon ~ female , data = honors , family = "binomial")
summary(honors.logit2)#>
#> 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 ***
#> female 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 ratio dari student female mendapatkan honors dibandingkan student male mendapatkan honors.
#> honors
#> female 0 1
#> 0 74 17
#> 1 77 32
# peluang
p_female <- 32/(32+77)
p_male <- 17/91
# odds
o_female <- p_female / (1-p_female)
o_male <- p_male / (1-p_male)
# log of odds
log(o_female/o_male) #> [1] 0.5927822
log dari odds fema
Intercept: log of odds dari student male yang mendapatkan honors (basis)
#> [1] -1.470852
Interpretasi:
#> [1] 1.809014
kemungkinan perempuan mendapatkan honors 1.8 kali lebih mungkin dari pada pria mendapatkan honors
Buat model untuk memprediksi honors berdasarkan nilai
math:
honors.logit3 <- glm(formula = hon ~ math, data = honors, family = "binomial")
summary(honors.logit3)#>
#> 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: -9.79394
Math: 0.15634
Contoh:
hon = -9.79394 + 0.15634 * math
Student A memiliki nilai math 52, student B 53. Hitung masing-masing log of oddsnya, berapa selisihnya?
# hint: substitusi formula model saja
# log of odds
hon52 <- -9.79394 + 0.15634 * 52
hon53 <- -9.79394 + 0.15634 * 53
hon53-hon52#> [1] 0.15634
Interpretasi:
#> [1] 1.169224
dengan menigkatnya 1 point dari nilai matematika maka siswa 1.17 (1.169224) kali lebih mungkin mendapatkan honors
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 ***
#> female 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
kemungkinan female mendapatkan honors 2.63 kali lebih mungkin dari pada pria mendapatkan honors ketika nilai matematikanya sama/konstan
math = 1.178474
setiap pengingkatan 1 point pada matematika mengakibatkan 1.18 kali lebih mungkin mendapatkan honors ketika variable lainnya konstan
jika seorang siswa memiliki nilai 1 point lebih tinggi nilai matematikanya dari siswa lainnya maka dia akan 1.18 kali lebih mungkin mendapatkan honors ketika varible lainnya konstan
Aplikasi:
Final formula: y = -10.80595 + 0.96531 * female1 + 0.16422 * math
Joe adalah seorang male yang nilai math-nya 60, berapa peluang dia mendapatkan honors? Apakah dia akan lulus dengan honors?
#> [1] -0.95275
#> [1] 0.2783321
probability untuk dia lulus dengan honors adalah 27.8 %
#> [1] "tidak honors"
glm( formula, data, family = "binomial")exp()Interpretasi koefisien dapat dilakukan dan berbeda untuk masing-masing kondisi:
Bila koefisien variable:
Umumnya semakin banyak prediktor maka residual deviance akan semakin kecil.
#>
#> 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
#> [1] 222.71
#> [1] 222.71
#> [1] 219.6062
#> [1] 167.0732
#> [1] 161.3454
Mari buat model honors.logit5 untuk memprediksi
honors berdasarkan semua prediktor yang ada:
#> Warning: glm.fit: algorithm did not converge
#> Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
#>
#> 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
#> female -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
NOTE:
Perfect Separation adalah sebuah kondisi dimana ada 1 variabel yang dapat memisahkan kelas target secara sempurna. Cara mendeteksi:
Pada kasus ini, nilai write dapat memisahkan kelas honor dengan sempurna:
#>
#> 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
Tidak disarankan menggunakan model dengan perfect separation, karena model amat bias pada salah satu variable dan tidak mempertimbangkan variable lain. Hal ini dapat membuat model tidak akurat (buruk) dalam memprediksi ke data baru.
Apa yang kita lakukan bila bertemu kondisi perfect separation:
ifelse saja.# revisi model
honors.logit6 <- glm(hon ~ female + read + math , data = honors, family = "binomial")
summary(honors.logit6)#>
#> 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 ***
#> female 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
AIC = Jumlah informasi yang hilang. Semakin kecil AIC, semakin baik model. Area Under the Curve (AUC) dan Akaike Information Criterion (AIC) adalah dua metrik yang digunakan untuk mengevaluasi model, tetapi keduanya memiliki tujuan yang berbeda dan diterapkan pada konteks yang berbeda. Berikut adalah perbedaan antara AUC dan AIC pada model regresi logistik:
Area Under the Curve (AUC):
Tujuan: AUC digunakan untuk mengevaluasi kinerja model klasifikasi, seperti regresi logistik. AUC mengukur seberapa baik model membedakan antara dua kelas dengan memplot kurva karakteristik operasi penerima (ROC). Interpretasi: Nilai AUC berkisar antara 0 dan 1. Model yang sempurna memiliki AUC setara dengan 1, sementara model yang tidak dapat membedakan antara kelas memiliki AUC sekitar 0.5 (sebagai acak). Akaike Information Criterion (AIC):
Tujuan: AIC digunakan untuk membandingkan model statistik yang berbeda berdasarkan kemungkinan (likelihood) model dan kompleksitasnya. Tujuannya adalah untuk memilih model yang memberikan keseimbangan terbaik antara kemungkinan model dan kompleksitasnya. Interpretasi: Pada AIC, model yang memiliki nilai AIC yang lebih rendah dianggap lebih baik. AIC memperhitungkan baik kecocokan model terhadap data (melalui likelihood) maupun kompleksitas model (melalui jumlah parameter). Dengan kata lain, AUC fokus pada kemampuan model untuk membedakan kelas (klasifikasi), sementara AIC fokus pada keseimbangan antara kecocokan model terhadap data dan kompleksitas model.
#> [1] 224.71
#> [1] 223.6062
#> [1] 171.0732
#> [1] 167.3454
#> [1] 164.1696
#> [1] 10
Important Notes:
Dalam menseleksi model, model yang baik adalah:
Logistic Regression menganut 3 asumsi:
vif()Asumsi logistic regression menuntut kita untuk memahami data secara mendalam dan memastikan data sudah siap dipakai untuk membuat model. Coba analisis kasus di bawah:
Berikut data penerbangan pesawat dalam
flight_sm.csv:
flight <- read.csv("data_input/flight_sm.csv") %>%
mutate(DepDel15 = as.factor(DepDel15))
glimpse(flight)#> Rows: 538,363
#> Columns: 10
#> $ Year <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013…
#> $ Month <int> 9, 9, 9, 7, 5, 7, 10, 10, 5, 6, 7, 8, 7, 10, 4, 10, 10, 8,…
#> $ DayofMonth <int> 16, 23, 7, 15, 16, 28, 6, 9, 12, 30, 21, 4, 17, 20, 15, 2,…
#> $ DayofWeek <int> 1, 1, 6, 1, 4, 7, 7, 3, 7, 7, 7, 7, 3, 7, 1, 3, 5, 6, 2, 1…
#> $ Carrier <chr> "DL", "WN", "AS", "OO", "DL", "UA", "WN", "AA", "UA", "OO"…
#> $ CRSDepTime <int> 1539, 1400, 810, 804, 805, 1251, 2000, 1010, 1522, 1404, 9…
#> $ DepDel15 <fct> 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0…
#> $ CRSArrTime <int> 1824, 1425, 1614, 1027, 1117, 1700, 2135, 1240, 2017, 1507…
#> $ OriginState <chr> "FL", "PA", "WA", "IL", "NY", "TX", "CA", "IL", "NV", "CA"…
#> $ DestState <chr> "NY", "IL", "DC", "OH", "FL", "DC", "NV", "TX", "TX", "CA"…
Dekspripsi kolom:
Year, Month, DayofMonth, DayofWeek:
self-explanatoryCarrier: maskapaiCRSDepTime & CRSArrTime: jadwal departure &
arrival (hhmm)DepDel15: status delay (1 = delay)OriginState, DestState: lokasi keberangkatan &
tujuanBuat 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
flight_clean <- flight %>%
mutate(Month = as.factor(Month),
DayofWeek = as.factor(DayofWeek))
glimpse(flight_clean)#> Rows: 538,363
#> Columns: 10
#> $ Year <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013…
#> $ Month <fct> 9, 9, 9, 7, 5, 7, 10, 10, 5, 6, 7, 8, 7, 10, 4, 10, 10, 8,…
#> $ DayofMonth <int> 16, 23, 7, 15, 16, 28, 6, 9, 12, 30, 21, 4, 17, 20, 15, 2,…
#> $ DayofWeek <fct> 1, 1, 6, 1, 4, 7, 7, 3, 7, 7, 7, 7, 3, 7, 1, 3, 5, 6, 2, 1…
#> $ Carrier <chr> "DL", "WN", "AS", "OO", "DL", "UA", "WN", "AA", "UA", "OO"…
#> $ CRSDepTime <int> 1539, 1400, 810, 804, 805, 1251, 2000, 1010, 1522, 1404, 9…
#> $ DepDel15 <fct> 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0…
#> $ CRSArrTime <int> 1824, 1425, 1614, 1027, 1117, 1700, 2135, 1240, 2017, 1507…
#> $ OriginState <chr> "FL", "PA", "WA", "IL", "NY", "TX", "CA", "IL", "NV", "CA"…
#> $ DestState <chr> "NY", "IL", "DC", "OH", "FL", "DC", "NV", "TX", "TX", "CA"…
flight.model_baru <- glm(DepDel15 ~ Month + DayofWeek , data = flight_clean, family = "binomial")
summary(flight.model_baru)#>
#> Call:
#> glm(formula = DepDel15 ~ Month + DayofWeek, family = "binomial",
#> data = flight_clean)
#>
#> 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
Studi Kasus: Credit Risk Analysis
Buat model untuk memprediksi peluang customer akan gagal bayar pinjaman (loan default), untuk mengindikasikan apakah customer tersebut baik atau tidak untuk diberikan pinjaman.
#> Rows: 1,556
#> Columns: 16
#> $ 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…
#> $ verification_status <fct> Source Verified, Not Verified, Verified, Not Verif…
#> $ 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 <int> 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1,…
#> $ log_inc <dbl> 11.962088, 10.819778, 10.126631, 12.072541, 11.608…
#> $ verified <int> 1, 0, 1, 0, 0, 0, 0, 0, 1, 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, 0,…
Target: not_paid (paid = 0, not_paid = 1)
Adakah variabel yang tipe datanya belum sesuai?
Adakah variabel yang dapat dibuang?
library(dplyr)
loan_clean <- loans %>%
select(-c(verification_status, grade, annual_inc)) %>%
mutate(grdCtoA = as.factor(grdCtoA),
not_paid = as.factor(not_paid),
verified = as.factor(verified))
glimpse(loan_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…
#> $ dti <dbl> 19.11, 19.35, 65.58, 12.60, 10.00, 5.12, 22.38, 33…
#> $ 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,…
#> $ log_inc <dbl> 11.962088, 10.819778, 10.126631, 12.072541, 11.608…
#> $ verified <fct> 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
#> $ grdCtoA <fct> 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,…
Cek missing value
#> [1] FALSE
Cek persebaran/pattern data
#> 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
#> dti revol_bal inq_last_12m delinq_2yrs
#> Min. : 0.00 Min. : 0 Min. : 0.000 Min. :0.0000
#> 1st Qu.: 11.00 1st Qu.: 4974 1st Qu.: 1.000 1st Qu.:0.0000
#> Median : 17.18 Median : 10163 Median : 2.000 Median :0.0000
#> Mean : 18.86 Mean : 15258 Mean : 2.359 Mean :0.3059
#> 3rd Qu.: 24.53 3rd Qu.: 18094 3rd Qu.: 3.000 3rd Qu.:0.0000
#> Max. :198.56 Max. :258897 Max. :18.000 Max. :8.0000
#> home_ownership not_paid log_inc verified grdCtoA
#> MORTGAGE:776 0:778 Min. : 7.824 0:578 0:961
#> OWN :201 1:778 1st Qu.:10.779 1:978 1:595
#> RENT :579 Median :11.127
#> Mean :11.123
#> 3rd Qu.:11.469
#> Max. :13.998
Literature: Higher debt-to-income ratio (dti) and amount of credit card debts are both associated with a greater likelihood of loan defaults.
# numeric predictor vs target variable
boxplot(loan_clean$dti , loan_clean$not_paid, ylim = c(0,10))#>
#> 0 1
#> 0 422 539
#> 1 356 239
Cek class-imbalance
#>
#> 0 1
#> 0.5 0.5
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.
Proporsi yang imbalance umumnya 90/10 atau 95/5.
Kalau datanya imbalance:
Cross Validation
Analogi:
tujuan dari cross validation adalah untuk mengetahui seberapa baik model yg sudah kita buat.
# # intuisi set seed: mengunci random number kita
set.seed(417) # pakai set.seed -> random number dikunci, hasil sampling selalu sama
sample(c("Angela", "Anthony", "Rizky", "Kevin"), 2)#> [1] "Kevin" "Angela"
RNGkind(sample.kind = "Rounding") # tambahan khusus u/ R 3.6 ke atas
set.seed(417) # mengunci random number yang dipilih
# index sampling
index <- sample(x = nrow(loan_clean) , size = nrow(loan_clean) * 0.8)
# splitting
loans.train <- loan_clean[index , ]
loans.test <- loan_clean[-index , ]NOTE: Proporsi 0.8/0.2 tidak mutlak, tergantung kebutuhan kita. Umumnya yang lebih banyak adalah untuk data train.
#>
#> 0 1
#> 0.4959807 0.5040193
#>
#> 0 1
#> 0.5160256 0.4839744
proporsi kelas yang balance penting untuk data train karena kita akan melatih model menggunakan data train.
library(rsample)
set.seed(417)
index_1 <- initial_split(data = loan_clean, prop = 0.8 , strata ="not_paid")
loan_train <- training(index_1)
loan_test <- testing(index_1)
prop.table(table(loan_train$not_paid))#>
#> 0 1
#> 0.5 0.5
#>
#> 0 1
#> 0.5 0.5
Build Model
Buatlah model logistic regression untuk memprediksi status loan (not_paid). Silahkan lakukan feature selection berdasarkan pertimbangan bisnis atau/dan statistik!
pakai data loans.train
model.loans <- glm(not_paid ~ installment + delinq_2yrs + home_ownership + log_inc + verified + grdCtoA , data = loans.train, family = "binomial" )#>
#> Call:
#> glm(formula = not_paid ~ installment + delinq_2yrs + home_ownership +
#> log_inc + verified + grdCtoA, family = "binomial", data = loans.train)
#>
#> Deviance Residuals:
#> Min 1Q Median 3Q Max
#> -2.0236 -1.1157 0.6261 1.1203 1.6859
#>
#> Coefficients:
#> Estimate Std. Error z value Pr(>|z|)
#> (Intercept) 3.1346656 1.1955650 2.622 0.008744 **
#> installment 0.0011201 0.0002211 5.066 0.000000406 ***
#> delinq_2yrs 0.2564169 0.0850741 3.014 0.002578 **
#> home_ownershipOWN 0.3857017 0.1875300 2.057 0.039711 *
#> home_ownershipRENT 0.1647821 0.1296008 1.271 0.203566
#> log_inc -0.3413549 0.1092992 -3.123 0.001789 **
#> verified1 0.2274757 0.1250104 1.820 0.068812 .
#> grdCtoA1 -0.4525553 0.1240481 -3.648 0.000264 ***
#> ---
#> 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: 1644.5 on 1236 degrees of freedom
#> AIC: 1660.5
#>
#> Number of Fisher Scoring iterations: 4
Pilih masing-masing 1 untuk prediktor kategorik dan prediktor numerik, kemudian interpretasikan:
#> [1] 0.7108066
#> [1] 0.6360009
setiap peningkatan 1 point dari log_inc debitur akan 0.71 kali lebih mungkin untuk not paid kelas 1 (gagal bayar).
untuk debitur yang memiliki grad B dan A 0.64 kali lebih mungkin untuk notpaid kelas 1 (gagal bayar)
predict(model, newdata, type)
pada type terdapat pilihan:
Prediksi log of odds not_paid untuk 6 data teratas:
#> 6 8 9 10 26 38
#> -0.85787892 -0.04013106 0.09345395 0.11022883 0.55817539 0.57478151
Prediksi probability not_paid untuk 6 data teratas:
#> 6 8 9 10 26 38
#> 0.2977827 0.4899686 0.5233465 0.5275293 0.6360303 0.6398658
Lakukan 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 , yes = 1 , no = 0)
# pastikan kelas target (aktual dan prediksi) bertipe factor
loans.test$pred.Label <- as.factor(loans.test$pred.Label)
head(loans.test)Note:
Penentuan label yang menjadi angka 1 pada model logistic regression adalah berdasarkan levels.
kelas “0”, “1” -> basis = 0, peluang mendekati 0 -> 0 peluang mendekati 1 -> 1
kelas “honors” “non-honors” -> basis = honors peluang mendekati 0 -> honors peluang mendekati 1 -> non-honors
Notes
Setelah dilakukan prediksi menggunakan model, masih ada saja prediksi yang salah. Pada klasifikasi, kita mengevaluasi model berdasarkan 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 93 56
#> 1 68 95
#>
#> Accuracy : 0.6026
#> 95% CI : (0.5459, 0.6573)
#> No Information Rate : 0.516
#> P-Value [Acc > NIR] : 0.001291
#>
#> Kappa : 0.2063
#>
#> Mcnemar's Test P-Value : 0.323236
#>
#> Sensitivity : 0.6291
#> Specificity : 0.5776
#> Pos Pred Value : 0.5828
#> Neg Pred Value : 0.6242
#> Prevalence : 0.4840
#> Detection Rate : 0.3045
#> Detection Prevalence : 0.5224
#> Balanced Accuracy : 0.6034
#>
#> 'Positive' Class : 1
#>
4 metrics performa model: Accuracy, Sensitivity/Recall, Precision, Specificity
Accuracy
Seberapa banyak yang benar diprediksi dari keseluruhan data (positif maupun negatif).
TP+TN/TOTAL
#> [1] 0.6025641
Digunakan ketika:
Ada kondisi ketika accuracy bukanlah metrics terpenting. Umumnya ketika:
Saat kita mementingkan kelas tertentu (kelas positif), 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)
#> [1] 0.6291391
Pos Pred Value/Precision
Seberapa banyak yang benar diprediksi positif, dari yang diprediksi positif.
TP/(TP+FP)
#> [1] 0.5828221
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)
#> [1] 0.5776398
Metrics yang baik untuk kasus loans adalah? (positif: not paid)
recall
Bila hasil evaluasi (nilai metrics) belum memuaskan, dapat dilakukan Model Tuning:
# label baru dari threshold baru
loans.test$pred.Label <- ifelse(loans.test$pred.Risk > 0.4 , yes = 1,no = 0)
loans.test$pred.Label <- as.factor(loans.test$pred.Label)
# confusion matrix
confusionMatrix(data =loans.test$pred.Label , reference = loans.test$not_paid, positive = "1")#> Confusion Matrix and Statistics
#>
#> Reference
#> Prediction 0 1
#> 0 42 22
#> 1 119 129
#>
#> Accuracy : 0.5481
#> 95% CI : (0.491, 0.6042)
#> No Information Rate : 0.516
#> P-Value [Acc > NIR] : 0.1409
#>
#> Kappa : 0.1129
#>
#> Mcnemar's Test P-Value : 0.0000000000000006234
#>
#> Sensitivity : 0.8543
#> Specificity : 0.2609
#> Pos Pred Value : 0.5202
#> Neg Pred Value : 0.6562
#> Prevalence : 0.4840
#> Detection Rate : 0.4135
#> Detection Prevalence : 0.7949
#> Balanced Accuracy : 0.5576
#>
#> 'Positive' Class : 1
#>
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.
sqrt(nrow(data))Kanker payudara adalah kanker yang paling umum menyerang wanita di dunia. Kanker payudara dapat berupa kanker jinak (benign) atau sudah ganas (malignant). Kanker ganas dapat menyebar ke organ-organ tubuh lainnya. Ingin dibuat model prediksi untuk memprediksi apakah kanker masih jinak (benign) atau sudah ganas (malignant).
#> 'data.frame': 569 obs. of 31 variables:
#> $ diagnosis : chr "B" "B" "B" "B" ...
#> $ radius_mean : num 12.3 10.6 11 11.3 15.2 ...
#> $ texture_mean : num 12.4 18.9 16.8 13.4 13.2 ...
#> $ perimeter_mean : num 78.8 69.3 70.9 73 97.7 ...
#> $ area_mean : num 464 346 373 385 712 ...
#> $ smoothness_mean : num 0.1028 0.0969 0.1077 0.1164 0.0796 ...
#> $ compactness_mean : num 0.0698 0.1147 0.078 0.1136 0.0693 ...
#> $ concavity_mean : num 0.0399 0.0639 0.0305 0.0464 0.0339 ...
#> $ points_mean : num 0.037 0.0264 0.0248 0.048 0.0266 ...
#> $ symmetry_mean : num 0.196 0.192 0.171 0.177 0.172 ...
#> $ dimension_mean : num 0.0595 0.0649 0.0634 0.0607 0.0554 ...
#> $ radius_se : num 0.236 0.451 0.197 0.338 0.178 ...
#> $ texture_se : num 0.666 1.197 1.387 1.343 0.412 ...
#> $ perimeter_se : num 1.67 3.43 1.34 1.85 1.34 ...
#> $ area_se : num 17.4 27.1 13.5 26.3 17.7 ...
#> $ smoothness_se : num 0.00805 0.00747 0.00516 0.01127 0.00501 ...
#> $ compactness_se : num 0.0118 0.03581 0.00936 0.03498 0.01485 ...
#> $ concavity_se : num 0.0168 0.0335 0.0106 0.0219 0.0155 ...
#> $ points_se : num 0.01241 0.01365 0.00748 0.01965 0.00915 ...
#> $ symmetry_se : num 0.0192 0.035 0.0172 0.0158 0.0165 ...
#> $ dimension_se : num 0.00225 0.00332 0.0022 0.00344 0.00177 ...
#> $ radius_worst : num 13.5 11.9 12.4 11.9 16.2 ...
#> $ texture_worst : num 15.6 22.9 26.4 15.8 15.7 ...
#> $ perimeter_worst : num 87 78.3 79.9 76.5 104.5 ...
#> $ area_worst : num 549 425 471 434 819 ...
#> $ smoothness_worst : num 0.139 0.121 0.137 0.137 0.113 ...
#> $ compactness_worst: num 0.127 0.252 0.148 0.182 0.174 ...
#> $ concavity_worst : num 0.1242 0.1916 0.1067 0.0867 0.1362 ...
#> $ points_worst : num 0.0939 0.0793 0.0743 0.0861 0.0818 ...
#> $ symmetry_worst : num 0.283 0.294 0.3 0.21 0.249 ...
#> $ dimension_worst : num 0.0677 0.0759 0.0788 0.0678 0.0677 ...
Variabel target: diagnosis
B = benign M = Malignant
#>
#> B M
#> 0.6274165 0.3725835
Insight: data masih cukup balance
#> diagnosis radius_mean texture_mean perimeter_mean area_mean
#> B:357 Min. : 6.981 Min. : 9.71 Min. : 43.79 Min. : 143.5
#> M:212 1st Qu.:11.700 1st Qu.:16.17 1st Qu.: 75.17 1st Qu.: 420.3
#> Median :13.370 Median :18.84 Median : 86.24 Median : 551.1
#> Mean :14.127 Mean :19.29 Mean : 91.97 Mean : 654.9
#> 3rd Qu.:15.780 3rd Qu.:21.80 3rd Qu.:104.10 3rd Qu.: 782.7
#> Max. :28.110 Max. :39.28 Max. :188.50 Max. :2501.0
#> smoothness_mean compactness_mean concavity_mean points_mean
#> Min. :0.05263 Min. :0.01938 Min. :0.00000 Min. :0.00000
#> 1st Qu.:0.08637 1st Qu.:0.06492 1st Qu.:0.02956 1st Qu.:0.02031
#> Median :0.09587 Median :0.09263 Median :0.06154 Median :0.03350
#> Mean :0.09636 Mean :0.10434 Mean :0.08880 Mean :0.04892
#> 3rd Qu.:0.10530 3rd Qu.:0.13040 3rd Qu.:0.13070 3rd Qu.:0.07400
#> Max. :0.16340 Max. :0.34540 Max. :0.42680 Max. :0.20120
#> symmetry_mean dimension_mean radius_se texture_se
#> Min. :0.1060 Min. :0.04996 Min. :0.1115 Min. :0.3602
#> 1st Qu.:0.1619 1st Qu.:0.05770 1st Qu.:0.2324 1st Qu.:0.8339
#> Median :0.1792 Median :0.06154 Median :0.3242 Median :1.1080
#> Mean :0.1812 Mean :0.06280 Mean :0.4052 Mean :1.2169
#> 3rd Qu.:0.1957 3rd Qu.:0.06612 3rd Qu.:0.4789 3rd Qu.:1.4740
#> Max. :0.3040 Max. :0.09744 Max. :2.8730 Max. :4.8850
#> perimeter_se area_se smoothness_se compactness_se
#> Min. : 0.757 Min. : 6.802 Min. :0.001713 Min. :0.002252
#> 1st Qu.: 1.606 1st Qu.: 17.850 1st Qu.:0.005169 1st Qu.:0.013080
#> Median : 2.287 Median : 24.530 Median :0.006380 Median :0.020450
#> Mean : 2.866 Mean : 40.337 Mean :0.007041 Mean :0.025478
#> 3rd Qu.: 3.357 3rd Qu.: 45.190 3rd Qu.:0.008146 3rd Qu.:0.032450
#> Max. :21.980 Max. :542.200 Max. :0.031130 Max. :0.135400
#> concavity_se points_se symmetry_se dimension_se
#> Min. :0.00000 Min. :0.000000 Min. :0.007882 Min. :0.0008948
#> 1st Qu.:0.01509 1st Qu.:0.007638 1st Qu.:0.015160 1st Qu.:0.0022480
#> Median :0.02589 Median :0.010930 Median :0.018730 Median :0.0031870
#> Mean :0.03189 Mean :0.011796 Mean :0.020542 Mean :0.0037949
#> 3rd Qu.:0.04205 3rd Qu.:0.014710 3rd Qu.:0.023480 3rd Qu.:0.0045580
#> Max. :0.39600 Max. :0.052790 Max. :0.078950 Max. :0.0298400
#> radius_worst texture_worst perimeter_worst area_worst
#> Min. : 7.93 Min. :12.02 Min. : 50.41 Min. : 185.2
#> 1st Qu.:13.01 1st Qu.:21.08 1st Qu.: 84.11 1st Qu.: 515.3
#> Median :14.97 Median :25.41 Median : 97.66 Median : 686.5
#> Mean :16.27 Mean :25.68 Mean :107.26 Mean : 880.6
#> 3rd Qu.:18.79 3rd Qu.:29.72 3rd Qu.:125.40 3rd Qu.:1084.0
#> Max. :36.04 Max. :49.54 Max. :251.20 Max. :4254.0
#> smoothness_worst compactness_worst concavity_worst points_worst
#> Min. :0.07117 Min. :0.02729 Min. :0.0000 Min. :0.00000
#> 1st Qu.:0.11660 1st Qu.:0.14720 1st Qu.:0.1145 1st Qu.:0.06493
#> Median :0.13130 Median :0.21190 Median :0.2267 Median :0.09993
#> Mean :0.13237 Mean :0.25427 Mean :0.2722 Mean :0.11461
#> 3rd Qu.:0.14600 3rd Qu.:0.33910 3rd Qu.:0.3829 3rd Qu.:0.16140
#> Max. :0.22260 Max. :1.05800 Max. :1.2520 Max. :0.29100
#> symmetry_worst dimension_worst
#> Min. :0.1565 Min. :0.05504
#> 1st Qu.:0.2504 1st Qu.:0.07146
#> Median :0.2822 Median :0.08004
#> Mean :0.2901 Mean :0.08395
#> 3rd Qu.:0.3179 3rd Qu.:0.09208
#> Max. :0.6638 Max. :0.20750
Range tiap variabel berbeda sehingga perlu dilakukan feature rescaling di tahap data pre-processing.
RNGkind(sample.kind = "Rounding")
set.seed(417)
index <- sample(nrow(wbcd_clean) , nrow(wbcd_clean)*0.8)
wbcd_train <- wbcd_clean[index,]
wbcd_test <- wbcd_clean[-index,]#>
#> B M
#> 0.6175824 0.3824176
Insight: proporsi masih termasuk balance
Scaling bisa menggunakan min-max normalization atau z-score standarization.
Rumus = x-min(x) / max(x)-min(x)
#> [1] 0.00 0.25 0.50 0.75 1.00
#> [1] 0.0000000 1.0000000 0.3866667 0.5200000 0.6533333
-> digunakan ketika tau angka pasti min dan max nya. misalnya nilai ujian matematika pasti nilai min-max nya 0 - 100.
scale()Rumus = x-mean(x) / sd(x)
#> [,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
#> [1] 3
#> [1] 1.581139
#> [1] -1.264911
-> digunakan ketika tidak diketahui angka min dan max pastinya. misalnya temperature bisa dari kisaran -inf s.d +inf
Untuk k-NN, dipisahkan antara prediktor dan label (target variabelnya).
# prediktor
wbcd_train_x <- wbcd_train[,-1]
wbcd_test_x <- wbcd_test[,-1]
# target
wbcd_train_y <- wbcd_train$diagnosis
wbcd_test_y <- wbcd_test$diagnosisData prediktor akan discaling menggunakan z-score standarization. Data test juga harus discaling menggunakan parameter dari data train (karena menganggap data test adalah unseen data).
# scaling data prediktor
wbcd_train_xs <- scale(wbcd_train_x)
wbcd_test_xs <- scale(wbcd_test_x ,
center = attr(wbcd_train_xs,"scaled:center") ,
scale = attr(wbcd_train_xs,"scaled:scale") )k-NN tidak membuat model sehingga langsung ke predict.
#> [1] 21.33073
library(class) # package untuk fungsi `knn()`
wbcd_pred <- knn(train = wbcd_train_xs ,
test = wbcd_test_xs ,
cl = wbcd_train_y,
k = 23
)#> [1] B B B B B B B B B M B B B B B B M B B B B B B B B B B M M B B B B B B B M
#> [38] B B M M B B B B M M M B B M B B B B M B M B M B M B M B B M B M M B B M B
#> [75] M B B B M B B M B M M B M B B B B B M B B B M M B M B M B M M B B B M B B
#> [112] M B B
#> Levels: B M
# confusion matrix
library(caret)
confusionMatrix(data = wbcd_pred, reference = wbcd_test_y, positive = "M")#> Confusion Matrix and Statistics
#>
#> Reference
#> Prediction B M
#> B 76 3
#> M 0 35
#>
#> Accuracy : 0.9737
#> 95% CI : (0.925, 0.9945)
#> No Information Rate : 0.6667
#> P-Value [Acc > NIR] : 0.0000000000000002673
#>
#> Kappa : 0.9396
#>
#> Mcnemar's Test P-Value : 0.2482
#>
#> Sensitivity : 0.9211
#> Specificity : 1.0000
#> Pos Pred Value : 1.0000
#> Neg Pred Value : 0.9620
#> Prevalence : 0.3333
#> Detection Rate : 0.3070
#> Detection Prevalence : 0.3070
#> Balanced Accuracy : 0.9605
#>
#> 'Positive' Class : M
#>
k-NN:
k-NN mengkasifikasi berdasarkan jarak - menghitung jarak ke semua datanya - ditentukan berapa k tetangga terdekat (data terdekat) - dilakukan majority voting dari kelas k tetangga terdekatnya