Analisis dalam LBB C2 ini bertujuan untuk memprediksi (mendiagnosa) penyakit kanker payudara yang dialami seorang pasien berdasarkan data yang telah dilaporkan oleh Dr. William H. Wolberg yang mana datasetnya bisa didapatkan di https://archive.ics.uci.edu/ml/datasets/breast+cancer+wisconsin+(original).
Analisis akan menggunakan pendekatan metode Supervised Learning (Classfication Machine Learning) yaitu dengan Klasifikasi Naive Bayes dan Decision Tree.
bc <- read.csv("breast-cancer-wisconsin.data")
names(bc) <- c("Id_number",
"Clump_thickness",
"Uniformity_of_cell_size",
"Uniformity_of_cell_shape",
"Marginal_adhesion",
"Single_epithelial_cell_Sz",
"Bare_nuclei",
"Bland_chromatin",
"Normal_nucleoli",
"Mitoses",
"Class")
head(bc)#> Id_number Clump_thickness Uniformity_of_cell_size Uniformity_of_cell_shape
#> 1 1002945 5 4 4
#> 2 1015425 3 1 1
#> 3 1016277 6 8 8
#> 4 1017023 4 1 1
#> 5 1017122 8 10 10
#> 6 1018099 1 1 1
#> Marginal_adhesion Single_epithelial_cell_Sz Bare_nuclei Bland_chromatin
#> 1 5 7 10 3
#> 2 1 2 2 3
#> 3 1 3 4 3
#> 4 3 2 1 3
#> 5 8 7 10 9
#> 6 1 2 10 3
#> Normal_nucleoli Mitoses Class
#> 1 2 1 2
#> 2 1 1 2
#> 3 7 1 2
#> 4 1 1 2
#> 5 7 1 4
#> 6 1 1 2
Keterangan:
Kolom Id_number tidak dipakai sehingga dihilangkan.
Kolom lain yang tipe datanya belum sesuai, kita ubah di sini.
library(dplyr)
bc_clean <- bc %>%
select(-c(Id_number)) %>%
mutate ( Bare_nuclei =as.numeric(Bare_nuclei),
Class = as.factor(Class)
)
str(bc_clean)#> 'data.frame': 698 obs. of 10 variables:
#> $ Clump_thickness : int 5 3 6 4 8 1 2 2 4 1 ...
#> $ Uniformity_of_cell_size : int 4 1 8 1 10 1 1 1 2 1 ...
#> $ Uniformity_of_cell_shape : int 4 1 8 1 10 1 2 1 1 1 ...
#> $ Marginal_adhesion : int 5 1 1 3 8 1 1 1 1 1 ...
#> $ Single_epithelial_cell_Sz: int 7 2 3 2 7 2 2 2 2 1 ...
#> $ Bare_nuclei : num 10 2 4 1 10 10 1 1 1 1 ...
#> $ Bland_chromatin : int 3 3 3 3 9 3 3 1 2 3 ...
#> $ Normal_nucleoli : int 2 1 7 1 7 1 1 1 1 1 ...
#> $ Mitoses : int 1 1 1 1 1 1 1 5 1 1 ...
#> $ Class : Factor w/ 2 levels "2","4": 1 1 1 1 2 1 1 1 1 1 ...
is.na(bc_clean) %>% colSums()#> Clump_thickness Uniformity_of_cell_size Uniformity_of_cell_shape
#> 0 0 0
#> Marginal_adhesion Single_epithelial_cell_Sz Bare_nuclei
#> 0 0 16
#> Bland_chromatin Normal_nucleoli Mitoses
#> 0 0 0
#> Class
#> 0
Terdapat missing values (NA) pada kolom Bare-nuclei maka
dilakukan langkah berikut ini:
bc_clean <- bc_clean %>%
filter(complete.cases(.)) # complete cases utk filter data-data yang barisnya tidak ada NA
is.na(bc_clean) %>% colSums()#> Clump_thickness Uniformity_of_cell_size Uniformity_of_cell_shape
#> 0 0 0
#> Marginal_adhesion Single_epithelial_cell_Sz Bare_nuclei
#> 0 0 0
#> Bland_chromatin Normal_nucleoli Mitoses
#> 0 0 0
#> Class
#> 0
prop.table(table(bc_clean$Class))#>
#> 2 4
#> 0.6495601 0.3504399
Proporsi data 64,95% dan 35,50% kurang balance, sehingga di langkah berikutnya kita akan melakukan balancing data.
Split data bc_clean menjadi data training dan data
testing, dengan 75% data akan digunakan sebagai data training.
RNGkind(sample.kind = "Rounding")
set.seed(100)
library(rsample)
# train-test splitting
index <- sample(nrow(bc_clean), nrow(bc_clean)*0.75)
bc_clean_train <- bc_clean[index, ]
bc_clean_test <- bc_clean[-index, ]Cek kembali proporsi kelas target.
# cek proporsi votes dengan data votes_train
prop.table(table(bc_clean_train$Class))#>
#> 2 4
#> 0.6536204 0.3463796
Kita coba melakukan split data menggunakan Stratified Random Sampling seperti berikut.
RNGkind(sample.kind = "Rounding")
set.seed(100)
library(rsample)
# Stratified Random Sampling
index_n <- initial_split(data = bc_clean, # data yang digunakan untuk splitting
prop = 0.75, # proporsi data train
strata = Class) # variabel target
bc_train_n <- training(index_n) # fungsi training bawaan dari library rsample
bc_test_n <- testing(index_n)# cek porporsi votes_train_n
prop.table(table(bc_train_n$Class))#>
#> 2 4
#> 0.6497065 0.3502935
Ternyata proporsi data kelas target masih belum balance. Mari lakukan treatment pada data train yang imbalance menggunakan upSample. Alasan digunakan metode upsample adalah karena datanya sedikit yaitu 511 observasi pada data-train.
RNGkind(sample.kind = "Rounding")
set.seed(100)
library(caret)
bc_train_balance <- upSample (x=bc_clean_train %>% select(-Class), #hanya select variabel prediktor saja
y=bc_clean_train$Class, # hanya selesct variabel target saja
yname="Class") # nama kolom targetprop.table(table(bc_train_balance$Class))#>
#> 2 4
#> 0.5 0.5
Sekarang proporsi data sudah balance. Data sudah siap maka selanjutnya kita buat pemodelan.
Menggunakan argumen naiveBayes(formula, data)
Di sini digunakan metode Laplace Smoothing untuk dapat memastikan model tidak terlalu ekstrim dalam mengklasifikasikan observasi serta tetap dapat mempertimbangkan nilai peluang dari prediktor lainnya.
library(e1071)
model_NB <- naiveBayes(formula= Class~., data= bc_train_balance, laplace = 1)
model_NB#>
#> Naive Bayes Classifier for Discrete Predictors
#>
#> Call:
#> naiveBayes.default(x = X, y = Y, laplace = laplace)
#>
#> A-priori probabilities:
#> Y
#> 2 4
#> 0.5 0.5
#>
#> Conditional probabilities:
#> Clump_thickness
#> Y [,1] [,2]
#> 2 3.011976 1.708442
#> 4 7.550898 2.245205
#>
#> Uniformity_of_cell_size
#> Y [,1] [,2]
#> 2 1.272455 0.8168764
#> 4 6.562874 2.7268984
#>
#> Uniformity_of_cell_shape
#> Y [,1] [,2]
#> 2 1.428144 0.9519625
#> 4 6.431138 2.5970162
#>
#> Marginal_adhesion
#> Y [,1] [,2]
#> 2 1.347305 0.9518633
#> 4 5.502994 3.2648354
#>
#> Single_epithelial_cell_Sz
#> Y [,1] [,2]
#> 2 2.089820 0.8115262
#> 4 5.437126 2.5832561
#>
#> Bare_nuclei
#> Y [,1] [,2]
#> 2 1.341317 1.191927
#> 4 7.670659 3.122029
#>
#> Bland_chromatin
#> Y [,1] [,2]
#> 2 2.095808 1.108165
#> 4 5.997006 2.370361
#>
#> Normal_nucleoli
#> Y [,1] [,2]
#> 2 1.260479 0.9622582
#> 4 5.916168 3.3743658
#>
#> Mitoses
#> Y [,1] [,2]
#> 2 1.023952 0.1716234
#> 4 2.709581 2.5986999
Melalukan prediksi dengan function predict()
# type raw
pred_NB_raw <- predict(object = model_NB, newdata = bc_clean_test, type="raw") # menghasilkan peluangMelakukan prediksi dengan parameter type = "class"
#type class
bc_clean_test$pred.Label <- predict(object = model_NB, newdata = bc_clean_test, type="class") # (default threshold 0.5)Evaluasi model dengan confusion matrix:
library(caret)
# confusion matrix
confusionMatrix(data = bc_clean_test$pred.Label, reference=bc_clean_test$Class)#> Confusion Matrix and Statistics
#>
#> Reference
#> Prediction 2 4
#> 2 100 1
#> 4 9 61
#>
#> Accuracy : 0.9415
#> 95% CI : (0.8951, 0.9716)
#> No Information Rate : 0.6374
#> P-Value [Acc > NIR] : < 0.0000000000000002
#>
#> Kappa : 0.8769
#>
#> Mcnemar's Test P-Value : 0.02686
#>
#> Sensitivity : 0.9174
#> Specificity : 0.9839
#> Pos Pred Value : 0.9901
#> Neg Pred Value : 0.8714
#> Prevalence : 0.6374
#> Detection Rate : 0.5848
#> Detection Prevalence : 0.5906
#> Balanced Accuracy : 0.9507
#>
#> 'Positive' Class : 2
#>
Kelas positive dalam model ini adalah yang bernilai 2, yaitu
benign.
Metrics mana yang akan dijadikan acuan? Karena berkaitan dengan
kondisi medis seseorang, kita ingin menurunkan false positive (dianggap
benign padahal sesungguhnya
malignant).Malignant adalah tumor ganas,
sehingga seseorang yang diprediksi masuk kelas malignant sebaiknya
melakukan pemeriksaan lebih lanjut.
Jika dilihat dari nilai Pos Pred Value atau Precisionnya, model_NB ini mempunyai performa yang baik yaitu dengan nilai precision 99.11%.
catatan: ditetapkan nilai precision yang diharapkan adalah minimal 98%
Selanjutnya mari kita coba membuat model dengan metode decission tree.
Kekurangan dari Decision Tree adalah kecenderungannya untuk overfitting. Hal ini terjadi karena Decision tree mampu membagi-bagi data hingga amat detail (bahkan hingga dalam leaf node hanya terdapat 1 observasi). Hal ini membuat decision tree justru menghafal pola di data train, dan membuat aturan yang terlalu kompleks, bukan mempelajari pola tersebut. Alhasil model menjadi kurang general untuk diaplikasikan ke data yang bukan data train, sehingga cenderung overfit.
Untuk mengatasinya, decision tree perlu tahu kapan ia berhenti membuat cabang sehingga pohon yang dihasilkan tidak terlalu kompleks. Pemotongan/pencegahan cabang pohon itu dinamakan Pruning, dimana kita mencegah Decision Tree untuk membuat cabang berdasarkan kriteria tertentu.
Parameter pruning:
mincriterion: Nilai 1-\(\alpha\). Saat mincriterion 0.95, P-value harus < 0.05 untuk suatu node dapat membuat cabang. (default: 0.95)
minsplit: Jumlah minimal observasi di tiap cabang setelah pemisahan. Bila tidak terpenuhi, tidak dilakukan percabangan. (default: 20)
minbucket: Jumlah minimal observasi di terminal node. Bila tidak terpenuhi, tidak dilakukan percabangan. (default: 7). Ketika nilai terminal masih diatas 7(secara default) tetapi jumlah observasi tidak memenuhi minimum angka yang dibutuhkan pada minsplit, maka percabangan akan dihentikan.
library(partykit)
model_DC <- ctree(formula = Class~., data = bc_train_balance,
control = ctree_control(mincriterion = 0.95,
minsplit = 20,
minbucket = 7))
plot(model_DC, type='simple')Evaluasi performa model_DC
# prediksi kelas di data test
pred_DC <- predict(model_DC, bc_clean_test, type="response")
# confusion matrix data test
confusionMatrix(pred_DC, bc_clean_test$Class, positive = "2")#> Confusion Matrix and Statistics
#>
#> Reference
#> Prediction 2 4
#> 2 106 0
#> 4 3 62
#>
#> Accuracy : 0.9825
#> 95% CI : (0.9496, 0.9964)
#> No Information Rate : 0.6374
#> P-Value [Acc > NIR] : <0.0000000000000002
#>
#> Kappa : 0.9624
#>
#> Mcnemar's Test P-Value : 0.2482
#>
#> Sensitivity : 0.9725
#> Specificity : 1.0000
#> Pos Pred Value : 1.0000
#> Neg Pred Value : 0.9538
#> Prevalence : 0.6374
#> Detection Rate : 0.6199
#> Detection Prevalence : 0.6199
#> Balanced Accuracy : 0.9862
#>
#> 'Positive' Class : 2
#>
Nilai precision dari model ini sebesar 98.21%. Cukup baik dari target yang diharapkan.
Notes : Ketika model diujikan ke 2 data (train/test) dan menghasilkan performa yang masih kurang memuaskan, hal yang bisa dilakukan adalah: - Ketika data imbalance, bisa ditambahkan data agar proporsinya semakin seimbang dan model bisa belajar dengan lebih banyak data (sudah dilakukan) - Coba untuk melakukan tuning lain dengan metode pruning (mengatur mincriterion, minsplit, minbucket, atau parameter lain yang ada di DT)
Performa kedua model yaitu model Naive Bayes dan model Decission Tree untuk memprediksi breast cancer cukup baik yaitu mempunyai nilai precision di atas 98%.
Model Naive Bayes mempunyai performa lebih tinggi yaitu dengan nilai precision 99.01%
Seandainya hasil performa model Naive Bayes dan Decission Tree dirasa masih kurang baik, bisa dipertimbangkan untuk menggunakan pendekatan lain dengan metode ensemble mehod, misalnya dengan Random Forest.