Pendahuluan

Dalam proyek ini, saya bertujuan untuk melakukan prediksi terhadap penumpang kapal Titanic yang selamat berdasarkan dataset yang berisi biodata mereka. Saya akan menggunakan algoritma Decision Tree dan Naive Bayes Classifier dalam supervised learning untuk menghasilkan prediksi apakah seorang penumpang akan selamat atau tidak berdasarkan informasi pada biodatanya. *** # Eksplorasi Data

Library

library(dplyr)
library(gtools)
library(gmodels)
library(ggplot2)
library(class)
library(tidyr)
library(e1071)
library(ModelMetrics)
library(partykit)

Data Import

Dataset Titanic yang digunakan berasal dari Kaggle. Data tersebut digunakan untuk menganalisis dan melakukan prediksi terkait kejadian di kapal Titanic.

titanic <- read.csv("train.csv")
head(titanic)

Data Dictionary

glimpse(titanic)
#> Rows: 891
#> Columns: 12
#> $ PassengerId <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,…
#> $ Survived    <int> 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1…
#> $ Pclass      <int> 3, 1, 3, 1, 3, 3, 1, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3, 2, 3, 3…
#> $ Name        <chr> "Braund, Mr. Owen Harris", "Cumings, Mrs. John Bradley (Fl…
#> $ Sex         <chr> "male", "female", "female", "female", "male", "male", "mal…
#> $ Age         <dbl> 22, 38, 26, 35, 35, NA, 54, 2, 27, 14, 4, 58, 20, 39, 14, …
#> $ SibSp       <int> 1, 1, 0, 1, 0, 0, 0, 3, 0, 1, 1, 0, 0, 1, 0, 0, 4, 0, 1, 0…
#> $ Parch       <int> 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 5, 0, 0, 1, 0, 0, 0…
#> $ Ticket      <chr> "A/5 21171", "PC 17599", "STON/O2. 3101282", "113803", "37…
#> $ Fare        <dbl> 7.2500, 71.2833, 7.9250, 53.1000, 8.0500, 8.4583, 51.8625,…
#> $ Cabin       <chr> "", "C85", "", "C123", "", "", "E46", "", "", "", "G6", "C…
#> $ Embarked    <chr> "S", "C", "S", "S", "S", "Q", "S", "S", "S", "C", "S", "S"…
  1. Survived (Survival): Kolom ini menunjukkan apakah penumpang tersebut selamat atau tidak. Nilai 0 berarti tidak selamat, sedangkan nilai 1 berarti selamat.

  2. pclass (Ticket class): Kolom ini menunjukkan kelas tiket yang dibeli oleh penumpang. Nilai 1 menandakan kelas tiket pertama, nilai 2 menandakan kelas tiket kedua, dan nilai 3 menandakan kelas tiket ketiga.

  3. sex (Jenis kelamin): Kolom ini menunjukkan jenis kelamin penumpang. Nilai “male” menandakan laki-laki, sedangkan nilai “female” menandakan perempuan.

  4. Age (Usia): Kolom ini menunjukkan usia penumpang dalam tahun.

  5. Sibsp (# of siblings/spouses aboard the Titanic): Kolom ini menunjukkan jumlah saudara kandung atau pasangan yang juga berada di kapal Titanic bersama penumpang.

  6. Parch (# of parents/children aboard the Titanic): Kolom ini menunjukkan jumlah orang tua atau anak yang juga berada di kapal Titanic bersama penumpang.

  7. Ticket (Nomor tiket): Kolom ini menunjukkan nomor tiket penumpang.

  8. Fare (Tarif penumpang): Kolom ini menunjukkan tarif yang dibayarkan oleh penumpang.

  9. Cabin (Nomor kabin): Kolom ini menunjukkan nomor kabin tempat penumpang menginap di kapal Titanic.

  10. Embarked (Pelabuhan Keberangkatan): Kolom ini menunjukkan pelabuhan keberangkatan penumpang. Nilai “C” menandakan Cherbourg, “Q” menandakan Queenstown, dan “S” menandakan Southampton.

  11. PassengerId : Id Penumpang

  12. Name : Nama penumpang


Data Cleansing

Terdapat beberapa variabel yang tidak perlu digunakan seperti Name, PassengerId, Ticket dan Cabin. Dan terdapat beberapa variabel yang belum sesuai untuk tipe datanya , sehingga perlu diperbaiki:

titanic <-titanic %>% 
  select(-Name, -PassengerId, -Ticket, -Cabin) %>% 
  mutate(Survived = as.factor(Survived),
         Pclass = as.factor(Pclass),
         Sex = as.factor(Sex),
         SibSp = as.factor(SibSp),
         Parch = as.factor(Parch),
         Embarked = as.factor(Embarked))
glimpse(titanic)
#> Rows: 891
#> Columns: 8
#> $ Survived <fct> 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0…
#> $ Pclass   <fct> 3, 1, 3, 1, 3, 3, 1, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3, 2, 3, 3, 2…
#> $ Sex      <fct> male, female, female, female, male, male, male, male, female,…
#> $ Age      <dbl> 22, 38, 26, 35, 35, NA, 54, 2, 27, 14, 4, 58, 20, 39, 14, 55,…
#> $ SibSp    <fct> 1, 1, 0, 1, 0, 0, 0, 3, 0, 1, 1, 0, 0, 1, 0, 0, 4, 0, 1, 0, 0…
#> $ Parch    <fct> 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 5, 0, 0, 1, 0, 0, 0, 0…
#> $ Fare     <dbl> 7.2500, 71.2833, 7.9250, 53.1000, 8.0500, 8.4583, 51.8625, 21…
#> $ Embarked <fct> S, C, S, S, S, Q, S, S, S, C, S, S, S, S, S, S, Q, S, S, C, S…
colSums(is.na(titanic))
#> Survived   Pclass      Sex      Age    SibSp    Parch     Fare Embarked 
#>        0        0        0      177        0        0        0        0

Terdapat outlier pada dataset Titanic yaitu pada kolom Age sehingga harus diatasi. Pada kolom Age akan diatasi missing valuenya mengisi dengan nilai mean nya.

# Mengatasi missing value pada titanic_train kolom `Age` 
mean_age <- mean(titanic$Age, na.rm = TRUE)
titanic$Age[is.na(titanic$Age)] <- mean_age
colSums(is.na(titanic))
#> Survived   Pclass      Sex      Age    SibSp    Parch     Fare Embarked 
#>        0        0        0        0        0        0        0        0

Sudah tidak terdapat missing value pada dataset titanic


Pre-Processing Data

Sebelum melakukan pemodelan, perlu memperhatikan proporsi dari variabel target yaitu Survived.

prop.table(table(titanic$Survived))
#> 
#>         0         1 
#> 0.6161616 0.3838384
table(titanic$Survived)
#> 
#>   0   1 
#> 549 342

Jika dilihat dari proporsi kedua kelas masih balance, karena masih 62:38 (Imbalance itu ketika lebih besar dari 70:30), sehingga kita tidak terlalu membutuhkan pre-processing tambahan untuk menyeimbangkan proporsi antar dua kelas target variabel.


Cross Validation

RNGkind(sample.kind = "Rounding")
set.seed(123)

# index sampling
index <- sample(x = nrow(titanic),
                size = nrow(titanic)*0.8) 

# splitting
titanic_train <- titanic[index, ]
titanic_test <- titanic[-index, ] 

Pembuatan Model

Naive Bayes

Naive Bayes adalah salah satu metode klasifikasi yang didasari oleh Bayes’ Theorem of Probability. Faktanya, teorema bayes sering digunakan dalam kehidupan sehari-hari. Model Naive Bayes dapat dibuat dengan menggunakan fungsi naiveBayes() library e1071. Pada analisis ini, pertama kita akan membuat model dengan menggunakan Naive Bayes. Pada pembuatan model akan menggunakan seluruh prediktor pada dataset. Salah satu kelemahan dari naive bayes adalah dapat terjadi scarcity, yaitu kondisi dimana suatu predictor tidak hadir sama sekali di suatu kelas. Sehingga kita menambahkan parameter laplace = 1.

model_nb <- naiveBayes(formula = Survived ~ . , data = titanic, laplace = 1)
model_nb
#> 
#> Naive Bayes Classifier for Discrete Predictors
#> 
#> Call:
#> naiveBayes.default(x = X, y = Y, laplace = laplace)
#> 
#> A-priori probabilities:
#> Y
#>         0         1 
#> 0.6161616 0.3838384 
#> 
#> Conditional probabilities:
#>    Pclass
#> Y           1         2         3
#>   0 0.1467391 0.1775362 0.6757246
#>   1 0.3971014 0.2550725 0.3478261
#> 
#>    Sex
#> Y      female      male
#>   0 0.1488203 0.8511797
#>   1 0.6802326 0.3197674
#> 
#>    Age
#> Y       [,1]     [,2]
#>   0 30.41510 12.45737
#>   1 28.54978 13.77250
#> 
#>    SibSp
#> Y            0          1          2          3          4          5
#>   0 0.71762590 0.17625899 0.02877698 0.02338129 0.02877698 0.01079137
#>   1 0.60458453 0.32378223 0.04011461 0.01432665 0.01146132 0.00286533
#>    SibSp
#> Y            8
#>   0 0.01438849
#>   1 0.00286533
#> 
#>    Parch
#> Y             0           1           2           3           4           5
#>   0 0.802158273 0.097122302 0.073741007 0.005395683 0.008992806 0.008992806
#>   1 0.670487106 0.189111748 0.117478510 0.011461318 0.002865330 0.005730659
#>    Parch
#> Y             6
#>   0 0.003597122
#>   1 0.002865330
#> 
#>    Fare
#> Y       [,1]     [,2]
#>   0 22.11789 31.38821
#>   1 48.39541 66.59700
#> 
#>    Embarked
#> Y                         C           Q           S
#>   0 0.001808318 0.137432188 0.086799277 0.773960217
#>   1 0.008670520 0.271676301 0.089595376 0.630057803

Lakukan predict dengan data test

pred_nb <- predict(object = model_nb, newdata = titanic_test, type = "class")

Evaluasi hasil dengan confusion matrix

#code here
confusionMatrix(pred_nb, titanic_test$Survived)
#>      [,1] [,2]
#> [1,]    0    0
#> [2,]    0  130

🏥 Resiko

  • Target variabel = Selamat(1) atau Tidak Selamat (0)
  • Kelas Positif : Tidak Selamat (0)
  • FN : Penumpang diprediksi selamat, padahal tidak selamat
  • FP : Penumpang diprediksi tidak selamat, padahal selamat
  • Risiko yang concerning adalah jika terjadi kesalahan dalam memprediksi penumpang yang sebenarnya tidak selamat sebagai selamat (False Positive).

Kesimpulan: Metrics yang perlu diprioritaskan atau dievaluasi adalah Precision.

Dari output model klaisifikasi Naive Bayes terlihat bahwa tingkat akurasi model sebesar 77,65% dan Precision/Pos Pred Value sebesar 79,23%

Decision Tree

Decision Tree merupakan tree-based model yang cukup sederhana dengan performa yang robust/powerful untuk prediksi. Decision Tree menghasilkan visualisasi berupa pohon keputusan yang dapat diinterpretasi dengan mudah.

Sebelumnya kita periksa proporsi dari data target kita.

prop.table(table(titanic_train$Survived))
#> 
#>         0         1 
#> 0.6081461 0.3918539

Apabila diperhatikan, proporsi titanic_train sebenarnya masih bisa dianggap balance. Namun kita bisa coba membuatnya lebih balance lagi sehingga proporsinya 50:50 menggunakan downsample.

library(caret)
RNGkind(sample.kind = "Rounding")
set.seed(100)

titanic_train <- downSample(
  x = titanic_train %>% select(-Survived),
  y = titanic_train$Survived,
  yname = "Survived")

Kekurangan utama dari Decision Tree adalah kecenderungannya untuk overfitting. Hal ini disebabkan kemampuannya yang dapat membagi data dengan sangat detail hingga mencapai tingkat leaf node yang hanya berisi satu observasi.Untuk mengatasi overfitting, teknik Pruning digunakan untuk memutuskan kapan harus menghentikan pembuatan cabang dalam pohon keputusan, sehingga menghasilkan pohon yang lebih sederhana dan general dalam mengenali pola, dan mencegah model menjadi terlalu khusus untuk data pelatihan saja.

Membangun Model tanpa Pruning

Selanjutnya mari kita uji dataset menggunakan klasifikasi Decision Tree tanpa melakukan tuning model.

library(partykit)
set.seed(100)
dt_model_pra <- ctree(formula = Survived~ .,
                  data = titanic)
plot(dt_model_pra, type="simple")

Setelah kita latih data train maka kita bisa gunakan langsung pada data test. Evaluasi performa model complex

# prediksi kelas di data test
pred_surv_pra_test <- predict(dt_model_pra,titanic_test,type = "response")

# confusion matrix data test
conf_matrix_dt_pra_test <- confusionMatrix(pred_surv_pra_test, titanic_test$Survived)
conf_matrix_dt_pra_test
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 108  17
#>          1   8  46
#>                                           
#>                Accuracy : 0.8603          
#>                  95% CI : (0.8008, 0.9075)
#>     No Information Rate : 0.648           
#>     P-Value [Acc > NIR] : 0.0000000001466 
#>                                           
#>                   Kappa : 0.6835          
#>                                           
#>  Mcnemar's Test P-Value : 0.1096          
#>                                           
#>             Sensitivity : 0.9310          
#>             Specificity : 0.7302          
#>          Pos Pred Value : 0.8640          
#>          Neg Pred Value : 0.8519          
#>              Prevalence : 0.6480          
#>          Detection Rate : 0.6034          
#>    Detection Prevalence : 0.6983          
#>       Balanced Accuracy : 0.8306          
#>                                           
#>        'Positive' Class : 0               
#> 
# prediksi kelas di data train
pred_surv_pra_train <- predict(dt_model_pra, titanic_train, type="response")

# confusion matrix data train
conf_matrix_dt_pra_train <- confusionMatrix(pred_surv_pra_train, as.factor(titanic_train$Survived))
conf_matrix_dt_pra_train
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 245  79
#>          1  34 200
#>                                                
#>                Accuracy : 0.7975               
#>                  95% CI : (0.7617, 0.8301)     
#>     No Information Rate : 0.5                  
#>     P-Value [Acc > NIR] : < 0.00000000000000022
#>                                                
#>                   Kappa : 0.595                
#>                                                
#>  Mcnemar's Test P-Value : 0.00003486           
#>                                                
#>             Sensitivity : 0.8781               
#>             Specificity : 0.7168               
#>          Pos Pred Value : 0.7562               
#>          Neg Pred Value : 0.8547               
#>              Prevalence : 0.5000               
#>          Detection Rate : 0.4391               
#>    Detection Prevalence : 0.5806               
#>       Balanced Accuracy : 0.7975               
#>                                                
#>        'Positive' Class : 0                    
#> 

🏥 Resiko

  • Target variabel = Selamat(1) atau Tidak Selamat (0)
  • Kelas Positif : Tidak Selamat (0)
  • FN : Penumpang diprediksi selamat, padahal tidak selamat
  • FP : Penumpang diprediksi tidak selamat, padahal selamat
  • Risiko yang concerning adalah jika terjadi kesalahan dalam memprediksi penumpang yang sebenarnya tidak selamat sebagai selamat (False Positive).

Kesimpulan: Metrics yang perlu diprioritaskan atau dievaluasi adalah Precision.

Untuk nilai Precision pada dt_model_pra : > Data train = 75.6% & Data test = 86.4%

Membangun Model dengan Pruning

Dan kita akan coba juga untuk melakukan tuning model dengan mengatur parameter mincriterion = 0.90 dan minsplit = 15.

library(partykit)
set.seed(100)
dt_model_pas <- ctree(formula = Survived~ .,
                  data = titanic,
                  control = ctree_control(mincriterion = 0.9,
                                          minsplit = 15,
                                          minbucket = 0))
plot(dt_model_pas, type="simple")

Setelah kita latih data train maka kita bisa gunakan langsung pada data test.

# prediksi kelas di data test
pred_surv_pas_test <- predict(dt_model_pas,titanic_test,type = "response")

# confusion matrix data test
conf_matrix_dt_pas_test <- confusionMatrix(pred_surv_pas_test, titanic_test$Survived)
conf_matrix_dt_pas_test
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 108  17
#>          1   8  46
#>                                           
#>                Accuracy : 0.8603          
#>                  95% CI : (0.8008, 0.9075)
#>     No Information Rate : 0.648           
#>     P-Value [Acc > NIR] : 0.0000000001466 
#>                                           
#>                   Kappa : 0.6835          
#>                                           
#>  Mcnemar's Test P-Value : 0.1096          
#>                                           
#>             Sensitivity : 0.9310          
#>             Specificity : 0.7302          
#>          Pos Pred Value : 0.8640          
#>          Neg Pred Value : 0.8519          
#>              Prevalence : 0.6480          
#>          Detection Rate : 0.6034          
#>    Detection Prevalence : 0.6983          
#>       Balanced Accuracy : 0.8306          
#>                                           
#>        'Positive' Class : 0               
#> 
# prediksi kelas di data train
pred_surv_pas_train <- predict(dt_model_pas, titanic_train, type="response")

# confusion matrix data train
conf_matrix_dt_pas_train <- confusionMatrix(pred_surv_pas_train, titanic_train$Survived)
conf_matrix_dt_pas_train
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 245  79
#>          1  34 200
#>                                                
#>                Accuracy : 0.7975               
#>                  95% CI : (0.7617, 0.8301)     
#>     No Information Rate : 0.5                  
#>     P-Value [Acc > NIR] : < 0.00000000000000022
#>                                                
#>                   Kappa : 0.595                
#>                                                
#>  Mcnemar's Test P-Value : 0.00003486           
#>                                                
#>             Sensitivity : 0.8781               
#>             Specificity : 0.7168               
#>          Pos Pred Value : 0.7562               
#>          Neg Pred Value : 0.8547               
#>              Prevalence : 0.5000               
#>          Detection Rate : 0.4391               
#>    Detection Prevalence : 0.5806               
#>       Balanced Accuracy : 0.7975               
#>                                                
#>        'Positive' Class : 0                    
#> 

Untuk nilai Precision pada dt_model_past : > Data train = 75.6% & Data test = 86.4%

Kesimpulan Dari hasil evaluasi performa model complex dan model tuning didapat bahwa tidak ada perubahan pada hasil nilai precision.


Kesimpulan

Jika kita bandingkan secara keseluruhan dengan mengurutkan dan mempertimbangkan nilai akurasi dan precision/Pos Pred Value dari yang tertinggi dan terendah bisa dilihat seperti dibawah ini :

conf_matrix_dt_pas_test
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 108  17
#>          1   8  46
#>                                           
#>                Accuracy : 0.8603          
#>                  95% CI : (0.8008, 0.9075)
#>     No Information Rate : 0.648           
#>     P-Value [Acc > NIR] : 0.0000000001466 
#>                                           
#>                   Kappa : 0.6835          
#>                                           
#>  Mcnemar's Test P-Value : 0.1096          
#>                                           
#>             Sensitivity : 0.9310          
#>             Specificity : 0.7302          
#>          Pos Pred Value : 0.8640          
#>          Neg Pred Value : 0.8519          
#>              Prevalence : 0.6480          
#>          Detection Rate : 0.6034          
#>    Detection Prevalence : 0.6983          
#>       Balanced Accuracy : 0.8306          
#>                                           
#>        'Positive' Class : 0               
#> 
confusionMatrix(pred_nb, titanic_test$Survived)
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction   0   1
#>          0 103  27
#>          1  13  36
#>                                           
#>                Accuracy : 0.7765          
#>                  95% CI : (0.7084, 0.8353)
#>     No Information Rate : 0.648           
#>     P-Value [Acc > NIR] : 0.0001365       
#>                                           
#>                   Kappa : 0.4839          
#>                                           
#>  Mcnemar's Test P-Value : 0.0398326       
#>                                           
#>             Sensitivity : 0.8879          
#>             Specificity : 0.5714          
#>          Pos Pred Value : 0.7923          
#>          Neg Pred Value : 0.7347          
#>              Prevalence : 0.6480          
#>          Detection Rate : 0.5754          
#>    Detection Prevalence : 0.7263          
#>       Balanced Accuracy : 0.7297          
#>                                           
#>        'Positive' Class : 0               
#> 

Berdasarkan urutan tingkat akurasi dan nilai recall, model klasifikasi Decision Tree adalah model terbaik. Dengan tingkat akurasi 86,03% dan Precision 86,40% sedangkan Naive Bayes (Acc = 77,65% Recall = 79,2%).