1. Library

Berikut adalah package yang digunakan dalam analisis ini. Package caret digunakan untuk proses pemodelan dan evaluasi model, tidyverse dan dplyr untuk manipulasi data, serta naivebayes sebagai package utama algoritma Naive Bayes.

library(readxl)
library(caret)
library(tidyverse)
library(dplyr)
library(naivebayes)

2. Import Data

Dataset yang digunakan adalah “Heart Attack Prediction in Indonesia” yang bersumber dari platform Kaggle. Dataset ini terdiri dari 158.355 data rekam kesehatan individu dengan 27 variabel independen dan 1 variabel dependen berupa status serangan jantung (heart_attack) dengan kategori positif (1) dan negatif (0).

Datajantung <- read_excel("C:/Users/User/Downloads/heart_attack_prediction_indonesia.xlsx"
)

cat("Dimensi dataset:", nrow(Datajantung), "baris dan", ncol(Datajantung), "kolom\n")
## Dimensi dataset: 158355 baris dan 28 kolom
head(Datajantung)
## # A tibble: 6 × 28
##     age gender region income_level hypertension diabetes cholesterol_level
##   <dbl> <chr>  <chr>  <chr>               <dbl>    <dbl>             <dbl>
## 1    60 Male   Rural  Middle                  0        1               211
## 2    53 Female Urban  Low                     0        0               208
## 3    62 Female Urban  Low                     0        0               231
## 4    73 Male   Urban  Low                     1        0               202
## 5    52 Male   Urban  Middle                  1        0               232
## 6    52 Male   Urban  Middle                  0        0               231
## # ℹ 21 more variables: obesity <dbl>, waist_circumference <dbl>,
## #   family_history <dbl>, smooking_status <chr>, alcohol_consumption <chr>,
## #   physical_activity <chr>, dietary_habits <chr>,
## #   air_pollution_exposure <chr>, stress_level <chr>, sleep_hours <dbl>,
## #   blood_pressure_systolic <dbl>, blood_pressure_diastolic <dbl>,
## #   fasting_blood_sugar <dbl>, cholesterol_hdl <dbl>, cholesterol_ldl <dbl>,
## #   triglycerides <dbl>, EKG_results <chr>, previous_heart_disease <dbl>, …

3. Sampling Data

Mengingat jumlah data yang sangat besar (158.355 data) sehingga memerlukan komputasi yang berat, maka dilakukan pengambilan sampel menggunakan rumus Slovin dengan tingkat kesalahan sebesar 1% sebagai berikut:

\[n = \frac{N}{1 + N(e)^2} = \frac{158.355}{1 + 158.355(0,01)^2} = \frac{158.355}{16,8355} \approx 9.407 \text{ data}\]

Berdasarkan perhitungan tersebut, diperoleh jumlah sampel sebanyak 9.407 data yang diambil secara acak (random sampling) dari keseluruhan dataset untuk memastikan sampel yang diperoleh bersifat representatif terhadap populasi data.

set.seed(36)
sample_index <- sample(
  1:nrow(Datajantung),
  9407
)
Data_sample <- Datajantung[sample_index, ]

cat("Jumlah sampel:", nrow(Data_sample), "\n")
## Jumlah sampel: 9407

4. Pre-Processing Data

4.1 Konversi Variabel ke Factor

Seluruh variabel kategorikal dikonversi ke dalam tipe data factor agar dapat diproses dengan benar oleh algoritma Naive Bayes. Variabel yang dikonversi meliputi variabel demografis, klinis, gaya hidup, serta variabel target heart_attack.

selected_data_preprocessed_factors <- Data_sample %>%
  mutate(
    gender                         = factor(gender),
    region                         = factor(region),
    income_level                   = factor(income_level),
    hypertension                   = factor(hypertension),
    diabetes                       = factor(diabetes),
    obesity                        = factor(obesity),
    family_history                 = factor(family_history),
    smooking_status                = factor(smooking_status),
    alcohol_consumption            = factor(alcohol_consumption),
    physical_activity              = factor(physical_activity),
    dietary_habits                 = factor(dietary_habits),
    air_pollution_exposure         = factor(air_pollution_exposure),
    stress_level                   = factor(stress_level),
    EKG_results                    = factor(EKG_results),
    previous_heart_disease         = factor(previous_heart_disease),
    medication_usage               = factor(medication_usage),
    participated_in_free_screening = factor(participated_in_free_screening),
    heart_attack                   = factor(heart_attack)
  )

glimpse(selected_data_preprocessed_factors)
## Rows: 9,407
## Columns: 28
## $ age                            <dbl> 64, 44, 36, 75, 46, 49, 57, 72, 67, 47,…
## $ gender                         <fct> Male, Female, Female, Male, Female, Fem…
## $ region                         <fct> Urban, Urban, Urban, Urban, Urban, Urba…
## $ income_level                   <fct> Low, Middle, Low, Middle, Low, Middle, …
## $ hypertension                   <fct> 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, …
## $ diabetes                       <fct> 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ cholesterol_level              <dbl> 261, 230, 292, 217, 199, 165, 193, 243,…
## $ obesity                        <fct> 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, …
## $ waist_circumference            <dbl> 105, 108, 93, 100, 80, 115, 117, 91, 85…
## $ family_history                 <fct> 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, …
## $ smooking_status                <fct> Past, Never, Never, Never, Never, Past,…
## $ alcohol_consumption            <fct> None, None, None, None, High, None, Non…
## $ physical_activity              <fct> Moderate, Low, Moderate, Low, Low, Low,…
## $ dietary_habits                 <fct> Unhealthy, Unhealthy, Healthy, Unhealth…
## $ air_pollution_exposure         <fct> Low, Low, Moderate, Moderate, Moderate,…
## $ stress_level                   <fct> Moderate, Moderate, Moderate, Moderate,…
## $ sleep_hours                    <dbl> 5.504516, 6.668030, 8.058486, 7.335143,…
## $ blood_pressure_systolic        <dbl> 125, 138, 114, 130, 148, 145, 129, 120,…
## $ blood_pressure_diastolic       <dbl> 74, 93, 76, 98, 82, 88, 87, 75, 76, 92,…
## $ fasting_blood_sugar            <dbl> 116, 111, 84, 147, 85, 138, 176, 96, 70…
## $ cholesterol_hdl                <dbl> 46, 66, 44, 46, 51, 46, 40, 45, 46, 34,…
## $ cholesterol_ldl                <dbl> 185, 121, 107, 156, 176, 70, 109, 50, 1…
## $ triglycerides                  <dbl> 145, 243, 140, 192, 107, 178, 223, 125,…
## $ EKG_results                    <fct> Abnormal, Normal, Normal, Normal, Norma…
## $ previous_heart_disease         <fct> 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, …
## $ medication_usage               <fct> 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, …
## $ participated_in_free_screening <fct> 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, …
## $ heart_attack                   <fct> 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, …

4.2 Definisi Variabel Target

Variabel target (dependent variable) yang digunakan adalah heart_attack, sedangkan seluruh variabel lainnya berperan sebagai fitur (independent variable) dalam proses pemodelan.

y <- selected_data_preprocessed_factors$heart_attack

cat("Distribusi variabel target:\n")
## Distribusi variabel target:
table(y)
## y
##    0    1 
## 5581 3826

4.3 Split Data Training dan Testing (80:20)

Dataset dibagi menjadi dua bagian yang saling independen, yaitu 80% data training untuk membangun model dan 20% data testing untuk mengevaluasi performa model. Pembagian ini bertujuan untuk mengurangi potensi bias serta menghindari terjadinya overfitting pada saat evaluasi model.

set.seed(36)
train_index <- createDataPartition(
  y,
  p = 0.8,
  list = FALSE
)

train_data <- selected_data_preprocessed_factors[train_index, ]
test_data  <- selected_data_preprocessed_factors[-train_index, ]

cat("Jumlah data training:", nrow(train_data), "\n")
## Jumlah data training: 7526
cat("Jumlah data testing :", nrow(test_data), "\n")
## Jumlah data testing : 1881

4.4 Proporsi Kelas Target

Pemeriksaan proporsi kelas target dilakukan untuk memastikan distribusi kelas pada data training dan testing cukup seimbang, sehingga model tidak condong (bias) terhadap salah satu kelas.

cat("Proporsi heart_attack pada data training:\n")
## Proporsi heart_attack pada data training:
prop.table(table(train_data$heart_attack))
## 
##         0         1 
## 0.5932766 0.4067234
cat("\nProporsi heart_attack pada data testing:\n")
## 
## Proporsi heart_attack pada data testing:
prop.table(table(test_data$heart_attack))
## 
##         0         1 
## 0.5933014 0.4066986

5. Pemodelan Naive Bayes

5.1 Konfigurasi Cross Validation

Metode validasi yang digunakan adalah 5-Fold Cross Validation, yaitu dataset training dibagi menjadi 5 bagian (fold) secara bergantian sebagai data validasi, sementara 4 bagian lainnya digunakan sebagai data latih. Metode ini bertujuan untuk menghasilkan evaluasi model yang lebih stabil dan konsisten serta meminimalkan kemungkinan terjadinya overfitting.

train_control <- trainControl(
  method = "cv",
  number = 5
)

5.2 Training Model dengan Grid Search CV

Model Naive Bayes dilatih menggunakan Grid Search Cross Validation untuk mencari kombinasi hyperparameter yang paling optimal. Terdapat tiga parameter yang diuji, yaitu:

  • laplace : Nilai Laplace smoothing untuk menangani probabilitas nol, diuji dari 0 hingga 2 dengan interval 0,5
  • usekernel : Menentukan apakah estimasi kernel density digunakan (TRUE) atau distribusi Gaussian (FALSE)
  • adjust : Nilai penyesuaian lebar bandwidth pada kernel density, diuji dari 0,5 hingga 2 dengan interval 0,5
set.seed(36)
nb_model <- train(
  heart_attack ~ .,
  data       = train_data,
  method     = "naive_bayes",
  preProcess = c("center", "scale"),
  trControl  = train_control,
  tuneGrid   = expand.grid(
    laplace   = seq(0, 2, by = 0.5),
    usekernel = c(TRUE, FALSE),
    adjust    = seq(0.5, 2, by = 0.5)
  )
)

print(nb_model)
## Naive Bayes 
## 
## 7526 samples
##   27 predictor
##    2 classes: '0', '1' 
## 
## Pre-processing: centered (33), scaled (33) 
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 6021, 6021, 6020, 6021, 6021 
## Resampling results across tuning parameters:
## 
##   laplace  usekernel  adjust  Accuracy   Kappa     
##   0.0      FALSE      0.5     0.7168481  0.40579078
##   0.0      FALSE      1.0     0.7168481  0.40579078
##   0.0      FALSE      1.5     0.7168481  0.40579078
##   0.0      FALSE      2.0     0.7168481  0.40579078
##   0.0       TRUE      0.5     0.5987243  0.01645006
##   0.0       TRUE      1.0     0.5981929  0.01454892
##   0.0       TRUE      1.5     0.5983261  0.01469687
##   0.0       TRUE      2.0     0.5975289  0.01238071
##   0.5      FALSE      0.5     0.7168481  0.40579078
##   0.5      FALSE      1.0     0.7168481  0.40579078
##   0.5      FALSE      1.5     0.7168481  0.40579078
##   0.5      FALSE      2.0     0.7168481  0.40579078
##   0.5       TRUE      0.5     0.5987243  0.01645006
##   0.5       TRUE      1.0     0.5981929  0.01454892
##   0.5       TRUE      1.5     0.5983261  0.01469687
##   0.5       TRUE      2.0     0.5975289  0.01238071
##   1.0      FALSE      0.5     0.7168481  0.40579078
##   1.0      FALSE      1.0     0.7168481  0.40579078
##   1.0      FALSE      1.5     0.7168481  0.40579078
##   1.0      FALSE      2.0     0.7168481  0.40579078
##   1.0       TRUE      0.5     0.5987243  0.01645006
##   1.0       TRUE      1.0     0.5981929  0.01454892
##   1.0       TRUE      1.5     0.5983261  0.01469687
##   1.0       TRUE      2.0     0.5975289  0.01238071
##   1.5      FALSE      0.5     0.7168481  0.40579078
##   1.5      FALSE      1.0     0.7168481  0.40579078
##   1.5      FALSE      1.5     0.7168481  0.40579078
##   1.5      FALSE      2.0     0.7168481  0.40579078
##   1.5       TRUE      0.5     0.5987243  0.01645006
##   1.5       TRUE      1.0     0.5981929  0.01454892
##   1.5       TRUE      1.5     0.5983261  0.01469687
##   1.5       TRUE      2.0     0.5975289  0.01238071
##   2.0      FALSE      0.5     0.7168481  0.40579078
##   2.0      FALSE      1.0     0.7168481  0.40579078
##   2.0      FALSE      1.5     0.7168481  0.40579078
##   2.0      FALSE      2.0     0.7168481  0.40579078
##   2.0       TRUE      0.5     0.5987243  0.01645006
##   2.0       TRUE      1.0     0.5981929  0.01454892
##   2.0       TRUE      1.5     0.5983261  0.01469687
##   2.0       TRUE      2.0     0.5975289  0.01238071
## 
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were laplace = 0, usekernel = FALSE
##  and adjust = 0.5.

5.3 Parameter Terbaik

Parameter terbaik dipilih berdasarkan kombinasi nilai laplace, usekernel, dan adjust yang menghasilkan akurasi tertinggi selama proses Grid Search Cross Validation. Kombinasi parameter inilah yang digunakan sebagai konfigurasi final model Naive Bayes.

cat("Kombinasi parameter terbaik:\n")
## Kombinasi parameter terbaik:
print(nb_model$bestTune)
##   laplace usekernel adjust
## 1       0     FALSE    0.5

5.4 Plot Hasil Tuning

Grafik berikut menunjukkan hubungan antara kombinasi hyperparameter dan akurasi model selama proses tuning. Kombinasi parameter dengan akurasi tertinggi dipilih sebagai model final.

plot(
  nb_model,
  main = "Akurasi Naive Bayes berdasarkan Hyperparameter",
  xlab = "Parameter",
  ylab = "Akurasi (Cross Validation)"
)


6. Evaluasi Model

6.1 Prediksi Data Testing

Setelah model Naive Bayes terbaik diperoleh, dilakukan prediksi terhadap data testing yang belum pernah dilihat oleh model sebelumnya. Hasil prediksi ini kemudian dibandingkan dengan label sebenarnya untuk mengukur performa model secara objektif.

nb_predictions <- predict(
  nb_model,
  newdata = test_data
)

6.2 Confusion Matrix

Confusion Matrix digunakan untuk mengevaluasi performa model secara menyeluruh dengan membandingkan hasil prediksi terhadap nilai aktual. Kelas positif yang digunakan adalah 1 yang merepresentasikan individu dengan risiko serangan jantung.

cm <- confusionMatrix(
  nb_predictions,
  test_data$heart_attack,
  positive = "1"
)

print(cm)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 892 312
##          1 224 453
##                                           
##                Accuracy : 0.715           
##                  95% CI : (0.6941, 0.7354)
##     No Information Rate : 0.5933          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.3987          
##                                           
##  Mcnemar's Test P-Value : 0.0001714       
##                                           
##             Sensitivity : 0.5922          
##             Specificity : 0.7993          
##          Pos Pred Value : 0.6691          
##          Neg Pred Value : 0.7409          
##              Prevalence : 0.4067          
##          Detection Rate : 0.2408          
##    Detection Prevalence : 0.3599          
##       Balanced Accuracy : 0.6957          
##                                           
##        'Positive' Class : 1               
## 

6.3 Ringkasan Performa Model

Berikut adalah ringkasan metrik evaluasi model Naive Bayes yang digunakan dalam penelitian ini:

  • Accuracy : Proporsi keseluruhan prediksi yang benar terhadap total data uji
  • Precision : Proporsi prediksi positif yang benar-benar merupakan kasus positif
  • Recall : Kemampuan model dalam mendeteksi seluruh kasus positif yang sesungguhnya
  • F1-Score : Rata-rata harmonik antara precision dan recall
cat("===================================\n")
## ===================================
cat("  Ringkasan Performa Model Naive Bayes\n")
##   Ringkasan Performa Model Naive Bayes
cat("===================================\n")
## ===================================
cat("Accuracy :", round(cm$overall["Accuracy"] * 100, 2), "%\n")
## Accuracy : 71.5 %
cat("Precision:", round(cm$byClass["Precision"] * 100, 2), "%\n")
## Precision: 66.91 %
cat("Recall   :", round(cm$byClass["Recall"] * 100, 2), "%\n")
## Recall   : 59.22 %
cat("F1-Score :", round(cm$byClass["F1"] * 100, 2), "%\n")
## F1-Score : 62.83 %
cat("===================================\n")
## ===================================