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)
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>, …
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
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, …
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
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
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
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
)
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,5usekernel : 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,5set.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.
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
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)"
)
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
)
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
##
Berikut adalah ringkasan metrik evaluasi model Naive Bayes yang digunakan dalam penelitian ini:
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")
## ===================================