1 Pendahuluan

Kesehatan ibu hamil merupakan salah satu isu penting dalam pembangunan kesehatan karena komplikasi selama kehamilan dan persalinan dapat meningkatkan risiko kematian ibu maupun bayi. Oleh karena itu, identifikasi risiko kesehatan ibu hamil perlu dilakukan secara cepat, objektif, dan konsisten. Pendekatan data mining dapat digunakan untuk membantu mengenali pola risiko berdasarkan indikator fisiologis seperti usia, tekanan darah, kadar gula darah, suhu tubuh, dan denyut jantung.

Penelitian ini membandingkan dua algoritma klasifikasi, yaitu Decision Tree dan Naïve Bayes, dalam mendeteksi tingkat risiko kesehatan ibu hamil. Evaluasi dilakukan menggunakan metrik accuracy, precision, recall, dan F1-score. Selain itu, dilakukan optimasi hyperparameter dengan pendekatan Random Search untuk melihat apakah proses tuning mampu meningkatkan performa model.

2 Rumusan Masalah

  1. Bagaimana perbandingan performa algoritma Decision Tree dan Naïve Bayes dalam mendeteksi risiko kesehatan ibu hamil?
  2. Apakah optimasi hyperparameter mampu meningkatkan performa model dibandingkan model sebelum optimasi?

3 Tujuan Penelitian

  1. Membandingkan performa Decision Tree dan Naïve Bayes dalam mengklasifikasikan tingkat risiko kesehatan ibu hamil.
  2. Mengetahui pengaruh optimasi hyperparameter terhadap performa Decision Tree dan Naïve Bayes.

4 Persiapan Package dan Data

library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)
library(caret)
library(rpart)
library(rpart.plot)
library(e1071)
library(klaR)
library(pROC)
library(knitr)
# Letakkan file data Excel di folder yang sama dengan file R Markdown ini.
# Jika nama file berbeda, ganti bagian data_path sesuai nama file Anda.
library(readxl)
data_path <- "data uas_maternal risk.xlsx"

Risk <- read_excel(data_path)
Risk$RiskLevel <- as.factor(Risk$RiskLevel)

head(Risk)

Interpretasi: Dataset yang digunakan adalah Maternal Health Risk dengan variabel prediktor berupa indikator fisiologis ibu hamil dan variabel target berupa RiskLevel. Variabel target perlu diubah menjadi faktor karena analisis yang dilakukan merupakan klasifikasi, bukan regresi.

5 Deskripsi Data

info_tipe <- data.frame(
  Variabel = names(Risk),
  Jumlah_Observasi = sapply(Risk, function(x) sum(!is.na(x))),
  Tipe_Data = sapply(Risk, class)
)

kable(info_tipe, caption = "Informasi Tipe Data")
Informasi Tipe Data
Variabel Jumlah_Observasi Tipe_Data
Age Age 1014 numeric
SystolicBP SystolicBP 1014 numeric
DiastolicBP DiastolicBP 1014 numeric
BS BS 1014 numeric
BodyTemp BodyTemp 1014 numeric
HeartRate HeartRate 1014 numeric
RiskLevel RiskLevel 1014 factor

Interpretasi: Dataset terdiri atas enam variabel prediktor, yaitu Age, SystolicBP, DiastolicBP, BS, BodyTemp, dan HeartRate, serta satu variabel target, yaitu RiskLevel. Variabel prediktor berbentuk numerik, sedangkan RiskLevel berbentuk kategorik. Struktur ini sudah sesuai untuk proses klasifikasi menggunakan Decision Tree dan Naïve Bayes.

library(dplyr)
library(tidyr)
data_num <- Risk %>%
  dplyr::select(Age, SystolicBP, DiastolicBP, BS, BodyTemp, HeartRate)

statdesk <- data_num %>%
  summarise(across(
    everything(),
    list(
      Min = min,
      Max = max,
      Mean = mean,
      SD = sd
    ),
    na.rm = TRUE
  )) %>%
  pivot_longer(
    cols = everything(),
    names_to = c("Variabel", ".value"),
    names_sep = "_"
  )

kable(statdesk, digits = 2, caption = "Statistik Deskriptif Variabel Numerik")
Statistik Deskriptif Variabel Numerik
Variabel Min Max Mean SD
Age 10 70 29.87 13.47
SystolicBP 70 160 113.20 18.40
DiastolicBP 49 100 76.46 13.89
BS 6 19 8.73 3.29
BodyTemp 98 103 98.67 1.37
HeartRate 7 90 74.30 8.09

Interpretasi: Statistik deskriptif menunjukkan bahwa data memiliki variasi karakteristik kesehatan ibu hamil. Rentang usia, tekanan darah, kadar gula darah, suhu tubuh, dan denyut jantung menunjukkan adanya perbedaan kondisi fisiologis antarobservasi. Namun, nilai minimum pada HeartRate perlu diperhatikan karena terdapat nilai yang sangat rendah dan berpotensi menjadi anomali data.

6 Eksplorasi Data

library(dplyr)
dist_target <- Risk %>%
  count(RiskLevel) %>%
  mutate(Persentase = round(n / sum(n) * 100, 2))

kable(dist_target, caption = "Distribusi Variabel Target RiskLevel")
Distribusi Variabel Target RiskLevel
RiskLevel n Persentase
High Risk 272 26.82
Low Risk 406 40.04
Mid Risk 336 33.14
ggplot(dist_target, aes(x = RiskLevel, y = n, fill = RiskLevel)) +
  geom_col() +
  geom_text(aes(label = paste0(n, " (", Persentase, "%)")), vjust = -0.3) +
  labs(
    title = "Distribusi Data Variabel Target",
    x = "RiskLevel",
    y = "Jumlah Observasi"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "none"
  )

Interpretasi: Distribusi RiskLevel digunakan untuk melihat apakah terdapat ketidakseimbangan kelas. Apabila jumlah setiap kelas relatif mendekati, maka data tidak mengalami class imbalance yang berat. Kondisi ini penting karena data yang terlalu tidak seimbang dapat membuat model cenderung memprediksi kelas mayoritas dan mengabaikan kelas minoritas.

7 Preprocessing Data

7.1 Pengecekan Missing Value

missing_value <- data.frame(
  Variabel = names(Risk),
  Jumlah_Missing = colSums(is.na(Risk))
)

kable(missing_value, caption = "Pengecekan Missing Value")
Pengecekan Missing Value
Variabel Jumlah_Missing
Age Age 0
SystolicBP SystolicBP 0
DiastolicBP DiastolicBP 0
BS BS 0
BodyTemp BodyTemp 0
HeartRate HeartRate 0
RiskLevel RiskLevel 0

Interpretasi: Hasil pengecekan menunjukkan apakah terdapat nilai kosong pada setiap variabel. Jika seluruh variabel memiliki jumlah missing value sebesar nol, maka data dapat langsung dilanjutkan ke tahap berikutnya tanpa imputasi. Jika terdapat nilai kosong, maka perlu dilakukan penanganan agar proses pemodelan tidak terganggu.

7.2 Deteksi Outlier dengan IQR

hitung_outlier <- function(x){
  Q1 <- quantile(x, 0.25, na.rm = TRUE)
  Q3 <- quantile(x, 0.75, na.rm = TRUE)
  IQR_val <- IQR(x, na.rm = TRUE)
  batas_bawah <- Q1 - 1.5 * IQR_val
  batas_atas  <- Q3 + 1.5 * IQR_val
  sum(x < batas_bawah | x > batas_atas, na.rm = TRUE)
}

tabel_outlier <- data.frame(
  Variabel = names(data_num),
  Jumlah_Outlier = sapply(data_num, hitung_outlier)
)

kable(tabel_outlier, caption = "Jumlah Outlier Berdasarkan Metode IQR")
Jumlah Outlier Berdasarkan Metode IQR
Variabel Jumlah_Outlier
Age Age 1
SystolicBP SystolicBP 10
DiastolicBP DiastolicBP 0
BS BS 210
BodyTemp BodyTemp 210
HeartRate HeartRate 2

Interpretasi: Deteksi outlier dilakukan untuk melihat apakah terdapat pengamatan yang berada jauh dari sebaran utama data. Tidak semua outlier harus dihapus karena dalam konteks kesehatan, nilai ekstrem dapat mencerminkan kondisi medis tertentu. Oleh karena itu, keputusan penghapusan perlu dilakukan secara hati-hati, terutama jika nilai tersebut masih masuk akal secara fisiologis.

data_long <- Risk %>%
  dplyr::select(Age, SystolicBP, DiastolicBP, BS, BodyTemp, HeartRate) %>%
  pivot_longer(
    cols = everything(),
    names_to = "Variabel",
    values_to = "Nilai"
  )

ggplot(data_long, aes(x = Variabel, y = Nilai, fill = Variabel)) +
  geom_boxplot() +
  labs(
    title = "Boxplot Maternal Health Risk",
    x = "Variabel",
    y = "Nilai"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "none"
  )

Interpretasi: Boxplot memperlihatkan pola sebaran setiap variabel numerik. Beberapa variabel memiliki outlier, tetapi sebagian besar masih dapat dianggap sebagai variasi kondisi kesehatan. Perhatian utama diberikan pada HeartRate karena terdapat nilai yang sangat jauh dari rentang denyut jantung normal, sehingga perlu diperiksa lebih lanjut.

7.3 Penanganan Anomali Denyut Jantung

jumlah_hr_7 <- sum(Risk$HeartRate == 7)
jumlah_hr_7
## [1] 2
data_hr_7 <- Risk %>%
  filter(HeartRate == 7)

kable(data_hr_7, caption = "Observasi dengan HeartRate sebesar 7")
Observasi dengan HeartRate sebesar 7
Age SystolicBP DiastolicBP BS BodyTemp HeartRate RiskLevel
16 120 75 7.9 98 7 Low Risk
16 120 75 7.9 98 7 Low Risk

Interpretasi: Observasi dengan HeartRate sebesar 7 perlu diperlakukan sebagai anomali karena nilainya tidak realistis untuk denyut jantung manusia dalam kondisi normal. Jika observasi tersebut juga memiliki karakteristik yang sama, maka terdapat indikasi duplikasi sekaligus kesalahan input. Oleh karena itu, penghapusan observasi ini dapat diterima untuk menjaga kualitas data.

Risk <- Risk %>%
  filter(HeartRate != 7)

jumlah_setelah_hapus <- sum(Risk$HeartRate == 7)
jumlah_data_bersih <- nrow(Risk)

jumlah_setelah_hapus
## [1] 0
jumlah_data_bersih
## [1] 1012

Interpretasi: Setelah observasi dengan HeartRate sebesar 7 dihapus, dataset menjadi lebih bersih dan lebih representatif untuk proses pemodelan. Penghapusan ini tidak dilakukan terhadap seluruh outlier, melainkan hanya terhadap nilai yang secara substansi tidak wajar.

8 Pembagian Data Training dan Testing

set.seed(123)

index_train <- createDataPartition(
  Risk$RiskLevel,
  p = 0.70,
  list = FALSE
)

train_data <- Risk[index_train, ]
test_data  <- Risk[-index_train, ]

train_data$RiskLevel <- factor(train_data$RiskLevel)
test_data$RiskLevel  <- factor(test_data$RiskLevel)

split_table <- data.frame(
  Data = c("Training", "Testing"),
  Jumlah = c(nrow(train_data), nrow(test_data)),
  Persentase = c(
    round(nrow(train_data) / nrow(Risk) * 100, 2),
    round(nrow(test_data) / nrow(Risk) * 100, 2)
  )
)

kable(split_table, caption = "Pembagian Data 70:30")
Pembagian Data 70:30
Data Jumlah Persentase
Training 710 70.16
Testing 302 29.84

Interpretasi: Data dibagi menggunakan rasio 70:30, yaitu 70% untuk pelatihan model dan 30% untuk pengujian. Pembagian ini memberikan keseimbangan antara kebutuhan model untuk mempelajari pola dari data training dan kebutuhan evaluasi pada data testing. Penggunaan createDataPartition() juga membantu mempertahankan proporsi kelas pada data training dan testing.

9 Fungsi Evaluasi Model

evaluasi_model <- function(actual, pred){
  actual <- factor(actual)
  pred <- factor(pred, levels = levels(actual))
  
  cm <- confusionMatrix(pred, actual)
  
  accuracy <- cm$overall["Accuracy"]
  precision <- mean(cm$byClass[, "Precision"], na.rm = TRUE)
  recall <- mean(cm$byClass[, "Recall"], na.rm = TRUE)
  f1 <- mean(cm$byClass[, "F1"], na.rm = TRUE)
  
  data.frame(
    Accuracy = round(as.numeric(accuracy), 4),
    Precision = round(precision, 4),
    Recall = round(recall, 4),
    F1_Score = round(f1, 4)
  )
}

Interpretasi: Fungsi evaluasi digunakan untuk menghitung empat metrik utama, yaitu accuracy, precision, recall, dan F1-score. Karena target memiliki lebih dari dua kelas, precision, recall, dan F1-score dihitung per kelas lalu dirata-ratakan. Pendekatan ini lebih informatif daripada hanya melihat accuracy karena setiap kelas risiko perlu diperhatikan.

10 Pemodelan Decision Tree

10.1 Decision Tree Sebelum Tuning

set.seed(123)

dt_baseline <- rpart(
  RiskLevel ~ .,
  data = train_data,
  method = "class"
)

rpart.plot(dt_baseline)

pred_dt <- predict(
  dt_baseline,
  test_data,
  type = "class"
)

hasil_dt <- evaluasi_model(
  test_data$RiskLevel,
  pred_dt
)

kable(hasil_dt, caption = "Evaluasi Model Decision Tree Sebelum Tuning")
Evaluasi Model Decision Tree Sebelum Tuning
Accuracy Precision Recall F1_Score
0.6523 0.6423 0.6626 0.6459

Interpretasi: Model Decision Tree sebelum tuning digunakan sebagai model dasar. Model ini membentuk pohon keputusan berdasarkan pola hubungan antara indikator kesehatan ibu hamil dan tingkat risiko. Nilai evaluasi pada tahap ini menjadi acuan awal untuk melihat apakah tuning mampu meningkatkan performa model.

11 Pemodelan Naïve Bayes

11.1 Naïve Bayes Sebelum Tuning

nb_baseline <- naiveBayes(
  RiskLevel ~ .,
  data = train_data
)

pred_nb <- predict(
  nb_baseline,
  test_data
)

hasil_nb <- evaluasi_model(
  test_data$RiskLevel,
  pred_nb
)

kable(hasil_nb, caption = "Evaluasi Model Naïve Bayes Sebelum Tuning")
Evaluasi Model Naïve Bayes Sebelum Tuning
Accuracy Precision Recall F1_Score
0.6258 0.6252 0.6086 0.5799

Interpretasi: Model Naïve Bayes baseline dibangun berdasarkan pendekatan probabilistik. Model ini menghitung peluang setiap kelas risiko berdasarkan nilai prediktor. Kelebihan Naïve Bayes adalah sederhana dan cepat, tetapi kelemahannya terletak pada asumsi independensi antarvariabel yang sering kali sulit terpenuhi pada data kesehatan.

12 Pemilihan Model Terbaik

tabel_semua_model <- rbind(
  data.frame(Model = "Decision Tree Baseline", hasil_dt),
  data.frame(Model = "Decision Tree + Tuning", hasil_dt_tuning),
  data.frame(Model = "Naïve Bayes Baseline", hasil_nb),
  data.frame(Model = "Naïve Bayes + Tuning", hasil_nb_tuning)
)

tabel_semua_model <- tabel_semua_model %>%
  arrange(desc(Accuracy), desc(F1_Score), desc(Recall), desc(Precision))

kable(tabel_semua_model, caption = "Perbandingan Seluruh Model")
Perbandingan Seluruh Model
Model Accuracy Precision Recall F1_Score
Decision Tree + Tuning 0.7715 0.7722 0.7782 0.7743
Naïve Bayes + Tuning 0.6887 0.7174 0.6773 0.6887
Decision Tree Baseline 0.6523 0.6423 0.6626 0.6459
Naïve Bayes Baseline 0.6258 0.6252 0.6086 0.5799

Interpretasi: Model terbaik dipilih berdasarkan performa pada data testing dengan mempertimbangkan accuracy, precision, recall, dan F1-score. Pemilihan tidak sebaiknya hanya menggunakan accuracy karena pada konteks kesehatan, kesalahan dalam mengenali risiko dapat memiliki dampak serius. Model yang ideal adalah model dengan performa tinggi sekaligus seimbang pada seluruh metrik.

model_terbaik <- tabel_semua_model[1, ]
kable(model_terbaik, caption = "Model Terbaik Berdasarkan Evaluasi Testing")
Model Terbaik Berdasarkan Evaluasi Testing
Model Accuracy Precision Recall F1_Score
Decision Tree + Tuning 0.7715 0.7722 0.7782 0.7743

Interpretasi: Berdasarkan hasil perbandingan, model pada baris pertama merupakan model dengan performa terbaik secara keseluruhan. Jika model terbaik adalah Decision Tree + Tuning, maka model tersebut dapat dianggap lebih sesuai karena mampu menangkap pola pemisahan kelas melalui struktur pohon yang mudah diinterpretasikan. Namun, kesimpulan tetap perlu dibatasi pada dataset yang digunakan dan tidak langsung digeneralisasikan ke seluruh populasi ibu hamil.

13 Hasil Klasifikasi Model Terbaik

cm_dt_tuning <- confusionMatrix(
  factor(pred_tuning, levels = levels(test_data$RiskLevel)),
  test_data$RiskLevel
)

cm_dt_tuning$table
##            Reference
## Prediction  High Risk Low Risk Mid Risk
##   High Risk        73        3       11
##   Low Risk          3       96       25
##   Mid Risk          5       22       64

Interpretasi: Confusion matrix menunjukkan jumlah prediksi benar dan salah pada setiap kelas risiko. Nilai diagonal menunjukkan data yang berhasil diklasifikasikan dengan benar, sedangkan nilai di luar diagonal menunjukkan kesalahan klasifikasi. Bagian ini penting karena dapat memperlihatkan kelas mana yang paling sering tertukar oleh model.

classification_report <- data.frame(
  Class = rownames(cm_dt_tuning$byClass),
  Precision = round(cm_dt_tuning$byClass[, "Precision"], 4),
  Recall = round(cm_dt_tuning$byClass[, "Recall"], 4),
  F1_Score = round(cm_dt_tuning$byClass[, "F1"], 4),
  Support = as.numeric(table(test_data$RiskLevel))
)

kable(classification_report, caption = "Classification Report Model Decision Tree + Tuning")
Classification Report Model Decision Tree + Tuning
Class Precision Recall F1_Score Support
Class: High Risk Class: High Risk 0.8391 0.9012 0.8690 81
Class: Low Risk Class: Low Risk 0.7742 0.7934 0.7837 121
Class: Mid Risk Class: Mid Risk 0.7033 0.6400 0.6702 100

Interpretasi: Classification report memperlihatkan performa model pada masing-masing kelas. Precision menunjukkan ketepatan prediksi pada suatu kelas, recall menunjukkan kemampuan model mengenali seluruh data aktual pada kelas tersebut, sedangkan F1-score menunjukkan keseimbangan antara precision dan recall. Jika terdapat kelas dengan recall rendah, maka model masih kurang mampu mengenali kelas tersebut secara optimal.

14 Kurva ROC dan AUC Multiclass

prob_dt <- predict(
  dt_tuning,
  test_data,
  type = "prob"
)

kelas <- levels(test_data$RiskLevel)
roc_list <- list()
auc_values <- c()

for(i in seq_along(kelas)){
  roc_obj <- roc(
    response = ifelse(test_data$RiskLevel == kelas[i], 1, 0),
    predictor = prob_dt[, i],
    quiet = TRUE
  )
  roc_list[[i]] <- roc_obj
  auc_values[i] <- auc(roc_obj)
}

mean_auc <- mean(auc_values)
roc_df <- data.frame()

for(i in seq_along(kelas)){
  roc_temp <- data.frame(
    FPR = 1 - roc_list[[i]]$specificities,
    TPR = roc_list[[i]]$sensitivities,
    Class = kelas[i]
  )
  roc_df <- rbind(roc_df, roc_temp)
}

ggplot(roc_df, aes(x = FPR, y = TPR, color = Class)) +
  geom_line(linewidth = 1.2) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed") +
  annotate(
    "text",
    x = 0.65,
    y = 0.15,
    label = paste("Mean AUC =", round(mean_auc, 4)),
    size = 5,
    fontface = "bold"
  ) +
  labs(
    title = "Kurva ROC Multiclass Model Decision Tree + Tuning",
    x = "False Positive Rate (1 - Specificity)",
    y = "True Positive Rate (Sensitivity)",
    color = "Class"
  ) +
  theme_bw(base_size = 14)

auc_table <- data.frame(
  Class = kelas,
  AUC = round(as.numeric(auc_values), 4)
)

kable(auc_table, caption = "Nilai AUC per Kelas")
Nilai AUC per Kelas
Class AUC
High Risk 0.9576
Low Risk 0.8790
Mid Risk 0.8402

Interpretasi: Kurva ROC dan nilai AUC digunakan untuk melihat kemampuan model dalam membedakan setiap kelas risiko melalui pendekatan one-vs-rest. Nilai AUC yang semakin mendekati 1 menunjukkan kemampuan diskriminasi yang semakin baik. Namun, AUC pada multiclass perlu dibaca bersama metrik lain karena model tetap dapat memiliki AUC cukup baik tetapi masih melakukan kesalahan pada kelas tertentu.

15 Feature Importance Decision Tree

importance_dt <- data.frame(
  Variabel = names(dt_tuning$variable.importance),
  Importance = as.numeric(dt_tuning$variable.importance)
)

importance_dt <- importance_dt %>%
  arrange(desc(Importance)) %>%
  mutate(Gain = Importance / sum(Importance)) %>%
  arrange(desc(Gain))

kable(importance_dt, digits = 4, caption = "Feature Importance Model Decision Tree")
Feature Importance Model Decision Tree
Variabel Importance Gain
BS 178.9486 0.3209
SystolicBP 112.9588 0.2026
DiastolicBP 85.5745 0.1535
Age 84.3011 0.1512
HeartRate 60.7845 0.1090
BodyTemp 34.9991 0.0628
ggplot(
  importance_dt,
  aes(x = reorder(Variabel, Gain), y = Gain)
) +
  geom_col(fill = "#4E79A7") +
  geom_text(aes(label = round(Gain, 3)), hjust = -0.15, size = 4) +
  coord_flip() +
  expand_limits(y = max(importance_dt$Gain) * 1.15) +
  labs(
    title = "Feature Importance Model Decision Tree",
    x = "Variabel",
    y = "Gain"
  ) +
  theme_bw(base_size = 14) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
    axis.title = element_text(face = "bold"),
    panel.grid.major.y = element_blank()
  )

Interpretasi: Feature importance menunjukkan variabel yang paling berkontribusi dalam pembentukan model Decision Tree. Variabel dengan nilai gain terbesar memiliki peran paling kuat dalam memisahkan kelas risiko. Dalam konteks kesehatan ibu hamil, variabel yang dominan perlu ditafsirkan secara substantif, bukan hanya secara statistik, karena dapat menunjukkan indikator fisiologis yang paling membantu dalam deteksi risiko.

16 Kesimpulan

Berdasarkan hasil analisis, Decision Tree dan Naïve Bayes dapat digunakan untuk mengklasifikasikan tingkat risiko kesehatan ibu hamil berdasarkan indikator fisiologis. Secara umum, model terbaik dipilih berdasarkan keseimbangan nilai accuracy, precision, recall, dan F1-score pada data testing. Apabila Decision Tree + Tuning menjadi model dengan performa tertinggi, maka model tersebut lebih sesuai digunakan karena selain menghasilkan evaluasi yang baik, struktur pohonnya juga lebih mudah diinterpretasikan.

Namun, hasil penelitian tetap perlu dibaca secara kritis. Pertama, tuning sebaiknya dilakukan menggunakan validasi silang pada data training agar pemilihan parameter tidak terlalu dipengaruhi oleh data testing. Kedua, hasil model hanya berlaku pada dataset yang digunakan sehingga penerapan pada data ibu hamil di Indonesia membutuhkan validasi tambahan. Ketiga, dalam konteks kesehatan, recall pada kelas risiko tinggi perlu menjadi perhatian utama karena kesalahan mendeteksi ibu hamil berisiko tinggi dapat berdampak lebih serius dibandingkan kesalahan pada kelas risiko rendah.

17 Saran

Penelitian selanjutnya dapat menggunakan validasi silang, menambahkan metrik AUC multiclass, serta membandingkan metode lain seperti Random Forest, XGBoost, atau Support Vector Machine. Selain itu, penggunaan data yang lebih kontekstual dengan kondisi ibu hamil di Indonesia juga penting agar model yang dibangun lebih relevan untuk kebutuhan deteksi dini risiko kehamilan.