library(tidyverse)
library(caret)
library(e1071)
library(pROC)

set.seed(15062026)   # reproducibility untuk split, CV, dan tuning

1 Pendahuluan

Kanker payudara merupakan salah satu jenis kanker yang paling sering terjadi pada perempuan dan menjadi penyebab utama kematian akibat kanker di banyak negara. Deteksi dini sangat penting karena dapat meningkatkan peluang keberhasilan pengobatan. Dengan berkembangnya machine learning, proses identifikasi tumor dapat dibantu menggunakan algoritma klasifikasi seperti Support Vector Machine (SVM), yang mampu membedakan tumor ganas (malignant) dan tumor jinak (benign) berdasarkan karakteristik sel hasil pemeriksaan medis.

Pertanyaan prediksi:

Dapatkah karakteristik morfologi inti sel digunakan untuk mengklasifikasikan tumor sebagai malignant (ganas) atau benign (jinak) menggunakan Support Vector Machine (SVM)?

Tujuan analisis:

  1. Membangun model klasifikasi SVM yang andal.
  2. Membandingkan kernel linear dan radial (RBF) secara objektif melalui cross-validation.
  3. Mengevaluasi performa pada data uji dengan penekanan khusus pada sensitivity kelas malignant, karena false negative (tumor ganas diprediksi jinak) jauh lebih berbahaya daripada false positive.

2 Deskripsi Data

Data yang digunakan berasal dari Breast Cancer Wisconsin (Diagnostic) (WDBC) yang tersedia pada UCI Machine Learning Repository. Setiap observasi merepresentasikan satu pasien yang menjalani pemeriksaan tumor payudara. Variabel respons adalah diagnosis dengan dua kelas, yaitu malignant (ganas) dan benign (jinak). Variabel prediktornya mencakup 30 fitur numerik yang menggambarkan karakteristik morfologi inti sel hasil pemeriksaan fine needle aspirate (FNA). Fitur tersebut berasal dari 10 karakteristik utama (radius, tekstur, perimeter, area, smoothness, compactness, concavity, concave points, symmetry, dan fractal dimension), masing-masing diringkas dalam tiga ukuran statistik: nilai rata-rata (_mean), galat baku (_se), dan nilai terburuk (_worst), sehingga total terdapat 30 variabel prediktor.

url_wdbc <- paste0(
  "https://archive.ics.uci.edu/ml/machine-learning-databases/",
  "breast-cancer-wisconsin/wdbc.data"
)

feature_names <- c(
  "radius", "texture", "perimeter", "area", "smoothness",
  "compactness", "concavity", "concave_points", "symmetry", "fractal_dimension"
)
col_names <- c(
  "id", "diagnosis",
  paste0(feature_names, "_mean"),
  paste0(feature_names, "_se"),
  paste0(feature_names, "_worst")
)

wdbc <- readr::read_csv(url_wdbc, col_names = col_names, show_col_types = FALSE) %>%
  mutate(
    # PENTING: Malignant dijadikan level PERTAMA -> menjadi kelas POSITIF default
    # di caret::confusionMatrix, sehingga sensitivity dihitung relatif terhadap
    # kelas malignant (yang paling relevan secara medis).
    diagnosis = factor(
      if_else(diagnosis == "M", "Malignant", "Benign"),
      levels = c("Malignant", "Benign")
    )
  )

glimpse(wdbc)
## Rows: 569
## Columns: 32
## $ id                      <dbl> 842302, 842517, 84300903, 84348301, 84358402, …
## $ diagnosis               <fct> Malignant, Malignant, Malignant, Malignant, Ma…
## $ radius_mean             <dbl> 17.990, 20.570, 19.690, 11.420, 20.290, 12.450…
## $ texture_mean            <dbl> 10.38, 17.77, 21.25, 20.38, 14.34, 15.70, 19.9…
## $ perimeter_mean          <dbl> 122.80, 132.90, 130.00, 77.58, 135.10, 82.57, …
## $ area_mean               <dbl> 1001.0, 1326.0, 1203.0, 386.1, 1297.0, 477.1, …
## $ smoothness_mean         <dbl> 0.11840, 0.08474, 0.10960, 0.14250, 0.10030, 0…
## $ compactness_mean        <dbl> 0.27760, 0.07864, 0.15990, 0.28390, 0.13280, 0…
## $ concavity_mean          <dbl> 0.30010, 0.08690, 0.19740, 0.24140, 0.19800, 0…
## $ concave_points_mean     <dbl> 0.14710, 0.07017, 0.12790, 0.10520, 0.10430, 0…
## $ symmetry_mean           <dbl> 0.2419, 0.1812, 0.2069, 0.2597, 0.1809, 0.2087…
## $ fractal_dimension_mean  <dbl> 0.07871, 0.05667, 0.05999, 0.09744, 0.05883, 0…
## $ radius_se               <dbl> 1.0950, 0.5435, 0.7456, 0.4956, 0.7572, 0.3345…
## $ texture_se              <dbl> 0.9053, 0.7339, 0.7869, 1.1560, 0.7813, 0.8902…
## $ perimeter_se            <dbl> 8.589, 3.398, 4.585, 3.445, 5.438, 2.217, 3.18…
## $ area_se                 <dbl> 153.40, 74.08, 94.03, 27.23, 94.44, 27.19, 53.…
## $ smoothness_se           <dbl> 0.006399, 0.005225, 0.006150, 0.009110, 0.0114…
## $ compactness_se          <dbl> 0.049040, 0.013080, 0.040060, 0.074580, 0.0246…
## $ concavity_se            <dbl> 0.05373, 0.01860, 0.03832, 0.05661, 0.05688, 0…
## $ concave_points_se       <dbl> 0.015870, 0.013400, 0.020580, 0.018670, 0.0188…
## $ symmetry_se             <dbl> 0.03003, 0.01389, 0.02250, 0.05963, 0.01756, 0…
## $ fractal_dimension_se    <dbl> 0.006193, 0.003532, 0.004571, 0.009208, 0.0051…
## $ radius_worst            <dbl> 25.38, 24.99, 23.57, 14.91, 22.54, 15.47, 22.8…
## $ texture_worst           <dbl> 17.33, 23.41, 25.53, 26.50, 16.67, 23.75, 27.6…
## $ perimeter_worst         <dbl> 184.60, 158.80, 152.50, 98.87, 152.20, 103.40,…
## $ area_worst              <dbl> 2019.0, 1956.0, 1709.0, 567.7, 1575.0, 741.6, …
## $ smoothness_worst        <dbl> 0.1622, 0.1238, 0.1444, 0.2098, 0.1374, 0.1791…
## $ compactness_worst       <dbl> 0.6656, 0.1866, 0.4245, 0.8663, 0.2050, 0.5249…
## $ concavity_worst         <dbl> 0.71190, 0.24160, 0.45040, 0.68690, 0.40000, 0…
## $ concave_points_worst    <dbl> 0.26540, 0.18600, 0.24300, 0.25750, 0.16250, 0…
## $ symmetry_worst          <dbl> 0.4601, 0.2750, 0.3613, 0.6638, 0.2364, 0.3985…
## $ fractal_dimension_worst <dbl> 0.11890, 0.08902, 0.08758, 0.17300, 0.07678, 0…
cat("Dimensi data:", nrow(wdbc), "baris x", ncol(wdbc), "kolom\n")
## Dimensi data: 569 baris x 32 kolom

3 Prapemrosesan dan EDA

3.1 Pemeriksaan Data Hilang

sum(is.na(wdbc))                      # total nilai hilang
## [1] 0
n_distinct(wdbc$id) == nrow(wdbc)     # semua id unik?
## [1] TRUE

Interpretasi. Hasil menunjukkan nilai 0 pada total data hilang dan seluruh id unik, sehingga dataset dinyatakan lengkap dan tidak memerlukan proses imputasi. Dengan demikian seluruh observasi dapat langsung digunakan pada tahap analisis berikutnya.

3.2 Distribusi Kelas Diagnosis

Distribusi kelas diperiksa untuk mengetahui apakah terdapat ketidakseimbangan antara jumlah tumor ganas (malignant) dan tumor jinak (benign).

distribusi <- wdbc %>%
  count(diagnosis) %>%
  mutate(proporsi = round(n / sum(n), 3))
distribusi
ggplot(distribusi, aes(diagnosis, n, fill = diagnosis)) +
  geom_col(width = 0.6) +
  geom_text(aes(label = paste0(n, " (", scales::percent(proporsi), ")")),
            vjust = -0.3, size = 3.5) +
  scale_fill_manual(values = c("Malignant" = "#c0392b", "Benign" = "#2980b9")) +
  labs(title = "Distribusi Kelas Diagnosis", x = NULL, y = "Jumlah pasien") +
  theme_minimal() + theme(legend.position = "none")

Interpretasi. Proporsi pasien benign lebih banyak dibandingkan malignant (sekitar 63% berbanding 37%). Ketidakseimbangan ini tergolong ringan sehingga tidak memerlukan teknik penyeimbangan data khusus. Namun demikian, akurasi saja menjadi metrik yang menyesatkan, sehingga evaluasi model juga mempertimbangkan sensitivity, specificity, dan AUC.

3.3 Eksplorasi Variabel Prediktor

Untuk memahami karakteristik data, dilakukan visualisasi beberapa fitur yang diketahui berhubungan kuat dengan diagnosis kanker payudara.

fitur_terpilih <- c("radius_mean", "perimeter_mean", "area_mean",
                    "concavity_mean", "concave_points_mean", "texture_mean")

wdbc %>%
  select(diagnosis, all_of(fitur_terpilih)) %>%
  pivot_longer(-diagnosis, names_to = "fitur", values_to = "nilai") %>%
  ggplot(aes(diagnosis, nilai, fill = diagnosis)) +
  geom_boxplot(alpha = 0.8, outlier.size = 0.7) +
  facet_wrap(~ fitur, scales = "free_y") +
  scale_fill_manual(values = c("Malignant" = "#c0392b", "Benign" = "#2980b9")) +
  labs(title = "Distribusi Fitur Inti Sel berdasarkan Diagnosis",
       x = NULL, y = "Nilai") +
  theme_minimal() + theme(legend.position = "none")

Interpretasi. Pasien malignant cenderung memiliki nilai radius, perimeter, area, concavity, dan concave_points yang lebih tinggi dibandingkan pasien benign. Perbedaan distribusi yang cukup jelas mengindikasikan bahwa fitur-fitur tersebut memiliki kemampuan diskriminasi yang baik untuk membedakan kedua kelas.

3.4 Analisis Korelasi Antar Prediktor

wdbc %>%
  select(ends_with("_mean")) %>%
  cor() %>%
  as.data.frame() %>%
  rownames_to_column("var1") %>%
  pivot_longer(-var1, names_to = "var2", values_to = "korelasi") %>%
  ggplot(aes(var1, var2, fill = korelasi)) +
  geom_tile() +
  scale_fill_gradient2(low = "#2980b9", mid = "white", high = "#c0392b",
                       midpoint = 0, limits = c(-1, 1)) +
  labs(title = "Korelasi antar Fitur (_mean)", x = NULL, y = NULL) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Interpretasi. Terdapat korelasi sangat kuat antara radius_mean,perimeter_mean, dan area_mean. Hal ini wajar karena ketiganya secara geometris saling berkaitan. Walaupun terdapat multikolinieritas, SVM relatif tidak sesensitif model regresi klasik terhadap kondisi tersebut.

3.5 Pembagian Data Latih-Uji (Stratified)

Dataset dibagi menjadi data latih 80% dan data uji 20% secara stratified sampling agar proporsi kelas tetap terjaga.

# createDataPartition mengambil sampel stratified terhadap diagnosis
idx_train <- createDataPartition(wdbc$diagnosis, p = 0.80, list = FALSE)

# Buang kolom id (pengenal, bukan prediktor) sebelum pemodelan
data_model <- wdbc %>% select(-id)

train_dat <- data_model[idx_train, ]
test_dat  <- data_model[-idx_train, ]

cat("Data latih:", nrow(train_dat), "baris\n")
## Data latih: 456 baris
cat("Data uji  :", nrow(test_dat),  "baris\n")
## Data uji  : 113 baris
# Verifikasi proporsi kelas terjaga
bind_rows(
  Latih = count(train_dat, diagnosis) %>% mutate(p = round(n/sum(n), 3)),
  Uji   = count(test_dat,  diagnosis) %>% mutate(p = round(n/sum(n), 3)),
  .id = "set"
)

Interpretasi. Proporsi kelas pada data latih dan data uji relatif sama, menunjukkan stratified sampling berhasil menjaga distribusi kelas sehingga pelatihan dan evaluasi model menjadi lebih representatif.

3.6 Standardisasi Variabel (ilustrasi)

Karena SVM berbasis jarak, seluruh variabel numerik perlu berada pada skala yang sama. Chunk berikut hanya mengilustrasikan efek standardisasi menggunakan rata-rata dan simpangan baku data latih. Pada pemodelan sesungguhnya, standardisasi ditangani otomatis oleh argumen scale = TRUE di dalam svm(), sehingga skala yang diturunkan dari data latih diterapkan konsisten ke data uji tanpa kebocoran.

preproc <- preProcess(train_dat[, -1], method = c("center", "scale"))

x_train <- predict(preproc, train_dat[, -1])
x_test  <- predict(preproc, test_dat[, -1])

head(x_train)

Interpretasi. Setelah standardisasi, seluruh variabel memiliki rata-rata mendekati nol dan simpangan baku mendekati satu, sehingga fitur dengan rentang nilai besar tidak mendominasi pembentukan hyperplane pada SVM.

4 Metode

Analisis menggunakan algoritma Support Vector Machine (SVM) untuk mengklasifikasikan tumor ke dalam kategori malignant dan benign. Seluruh variabel prediktor dinormalisasi melalui standardisasi berbasis rata-rata dan simpangan baku data latih; pada e1071::svm() hal ini dilakukan lewat argumen scale = TRUE, sehingga skala dari data latih otomatis diterapkan pada data uji saat prediksi. Pendekatan ini memastikan tidak terjadi data leakage.

Penalaan hiperparameter dilakukan dengan tune.svm() menggunakan 5-fold cross-validation hanya pada data latih. Dua kernel dibandingkan: linear (tuning cost) dan radial/RBF (tuning cost dan gamma). Parameter gamma mengontrol fleksibilitas batas keputusan pada kernel RBF.

Model terbaik dipilih berdasarkan cross-validation error terkecil, lalu dilatih ulang pada seluruh data latih dan dievaluasi pada data uji yang tidak pernah digunakan selama pelatihan maupun penalaan. Kinerja diukur dengan accuracy, sensitivity, specificity, AUC, dan confusion matrix. Sensitivity menjadi perhatian utama karena berkaitan langsung dengan kemampuan mendeteksi kasus malignant dan meminimalkan false negative.

# Kontrol CV 5-fold untuk semua proses tuning
ctrl_cv <- tune.control(sampling = "cross", cross = 5)

5 Hasil Analisis

5.1 Tuning dan Validasi SVM Linear

Model SVM kernel linear dituning pada beberapa kandidat nilai cost (C) melalui 5-fold CV. Nilai cost mengontrol toleransi model terhadap kesalahan klasifikasi.

tune_lin <- tune.svm(
  diagnosis ~ ., data = train_dat,
  kernel = "linear",
  cost = 2^(-3:5),
  scale = TRUE,
  tunecontrol = ctrl_cv
)
summary(tune_lin)$performances %>% arrange(error) %>% head(5)
cat("Cost terbaik (linear):", tune_lin$best.parameters$cost,
    "| Error CV:", round(tune_lin$best.performance, 4), "\n")
## Cost terbaik (linear): 0.125 | Error CV: 0.0242

Interpretasi. Semakin kecil cross-validation error, semakin baik kemampuan generalisasi model. Nilai cost dengan error terkecil dipilih sebagai parameter optimal untuk kernel linear.

5.2 Tuning dan Validasi SVM Radial (RBF)

Pada kernel RBF, dua parameter dituning: cost (C) dan gamma.

tune_rbf <- tune.svm(
  diagnosis ~ ., data = train_dat,
  kernel = "radial",
  cost  = 2^(-1:5),
  gamma = 2^(-8:-1),
  scale = TRUE,
  tunecontrol = ctrl_cv
)
cat("Cost terbaik (RBF):", tune_rbf$best.parameters$cost,
    "| Gamma terbaik:", tune_rbf$best.parameters$gamma,
    "| Error CV:", round(tune_rbf$best.performance, 4), "\n")
## Cost terbaik (RBF): 4 | Gamma terbaik: 0.015625 | Error CV: 0.0219
plot(tune_rbf)   # heatmap performa CV terhadap kombinasi cost x gamma

Interpretasi. Grafik tuning memvisualisasikan perubahan performa pada berbagai kombinasi cost dan gamma. Kombinasi dengan error terkecil dipilih sebagai kandidat terbaik untuk kernel RBF.

5.3 Perbandingan Kernel (Berbasis CV)

perbandingan <- tibble(
  Kernel        = c("Linear", "Radial (RBF)"),
  `Error CV`    = c(tune_lin$best.performance, tune_rbf$best.performance),
  `Akurasi CV`  = 1 - c(tune_lin$best.performance, tune_rbf$best.performance)
) %>% mutate(across(where(is.numeric), ~ round(., 4)))
perbandingan
# Pilih kernel pemenang berdasarkan error CV terendah
if (tune_rbf$best.performance <= tune_lin$best.performance) {
  nama_model <- "SVM Radial (RBF)"
  model_final <- svm(
    diagnosis ~ ., data = train_dat, kernel = "radial",
    cost = tune_rbf$best.parameters$cost,
    gamma = tune_rbf$best.parameters$gamma,
    scale = TRUE, probability = TRUE
  )
} else {
  nama_model <- "SVM Linear"
  model_final <- svm(
    diagnosis ~ ., data = train_dat, kernel = "linear",
    cost = tune_lin$best.parameters$cost,
    scale = TRUE, probability = TRUE
  )
}
cat("Model final terpilih:", nama_model, "\n")
## Model final terpilih: SVM Radial (RBF)

Interpretasi. Kernel dengan cross-validation error terendah dipilih sebagai model final. Jika RBF unggul, hubungan antarvariabel cenderung nonlinier; sebaliknya, bila performa setara, kernel linear dapat dipilih karena lebih sederhana dan mudah diinterpretasi.

5.4 Evaluasi Model pada Data Uji

# Prediksi kelas
pred_class <- predict(model_final, newdata = test_dat)

# Prediksi probabilitas (untuk ROC/AUC)
pred_prob_obj  <- predict(model_final, newdata = test_dat, probability = TRUE)
prob_matrix    <- attr(pred_prob_obj, "probabilities")
prob_malignant <- prob_matrix[, "Malignant"]

5.4.1 Confusion Matrix

cm <- confusionMatrix(pred_class, test_dat$diagnosis, positive = "Malignant")
cm
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  Malignant Benign
##   Malignant        42      2
##   Benign            0     69
##                                           
##                Accuracy : 0.9823          
##                  95% CI : (0.9375, 0.9978)
##     No Information Rate : 0.6283          
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.9625          
##                                           
##  Mcnemar's Test P-Value : 0.4795          
##                                           
##             Sensitivity : 1.0000          
##             Specificity : 0.9718          
##          Pos Pred Value : 0.9545          
##          Neg Pred Value : 1.0000          
##              Prevalence : 0.3717          
##          Detection Rate : 0.3717          
##    Detection Prevalence : 0.3894          
##       Balanced Accuracy : 0.9859          
##                                           
##        'Positive' Class : Malignant       
## 
as.data.frame(cm$table) %>%
  ggplot(aes(Reference, Prediction, fill = Freq)) +
  geom_tile() +
  geom_text(aes(label = Freq), size = 6) +
  scale_fill_gradient(low = "#ecf0f1", high = "#c0392b") +
  labs(title = "Confusion Matrix (Data Uji)") +
  theme_minimal()

Interpretasi. Elemen diagonal menunjukkan klasifikasi yang benar, sedangkan elemen di luar diagonal menunjukkan kesalahan. Perhatian utama diberikan pada false negative (tumor ganas diprediksi jinak) karena berpotensi menimbulkan konsekuensi klinis serius.

5.4.2 Kurva ROC dan Nilai AUC

# Kelas positif = Malignant; prediktor = P(Malignant), sehingga direction "<"
roc_obj <- roc(
  response  = test_dat$diagnosis,
  predictor = prob_malignant,
  levels    = c("Benign", "Malignant"),   # (kontrol, kasus)
  direction = "<"
)
auc_val <- as.numeric(auc(roc_obj))
auc_ci  <- ci.auc(roc_obj)   # selang kepercayaan 95% untuk AUC (DeLong)
cat("AUC =", round(auc_val, 4),
    "| 95% CI:", round(auc_ci[1], 4), "-", round(auc_ci[3], 4), "\n")
## AUC = 0.9987 | 95% CI: 0.9961 - 1
ggroc(roc_obj, colour = "#c0392b", size = 1) +
  geom_abline(slope = 1, intercept = 1, linetype = "dashed", colour = "grey60") +
  labs(title = paste0("Kurva ROC - ", nama_model),
       subtitle = paste0("AUC = ", round(auc_val, 4), " | Kelas positif: Malignant"),
       x = "Specificity", y = "Sensitivity") +
  theme_minimal()

Interpretasi. Nilai AUC mendekati 1 menandakan kemampuan diskriminasi yang sangat baik (umumnya AUC > 0,90 dianggap sangat baik). Kurva ROC yang berada jauh di atas garis diagonal menunjukkan performa klasifikasi yang baik.

5.4.3 Ringkasan Metrik Evaluasi

tibble(
  Metrik = c("Accuracy", "Sensitivity (Recall Malignant)",
             "Specificity", "Precision (PPV)", "F1", "AUC"),
  Nilai  = round(c(
    cm$overall["Accuracy"],
    cm$byClass["Sensitivity"],
    cm$byClass["Specificity"],
    cm$byClass["Pos Pred Value"],
    cm$byClass["F1"],
    auc_val
  ), 4)
)

Interpretasi metrik.

  1. Accuracy — proporsi prediksi benar terhadap seluruh observasi.
  2. Sensitivity — kemampuan mendeteksi kasus tumor ganas (malignant).
  3. Specificity — kemampuan mengenali kasus tumor jinak (benign).
  4. Precision (PPV) — proporsi prediksi positif yang benar-benar positif.
  5. F1-score — rata-rata harmonik precision dan sensitivity.
  6. AUC — kemampuan membedakan kedua kelas secara keseluruhan.

Pada diagnosis kanker payudara, sensitivity menjadi indikator paling penting karena berkaitan langsung dengan kemampuan mendeteksi pasien yang benar-benar mengalami tumor ganas.

6 Interpretasi dan Diskusi

6.1 Interpretasi Hasil Model

Model terbaik yang terpilih adalah SVM Radial (RBF) dengan nilai AUC sebesar 0.9987 dan akurasi sebesar 98.23% pada data uji. Nilai akurasi tersebut memiliki selang kepercayaan 95% sebesar 93.75% hingga 99.78%, sedangkan nilai Kappa sebesar 0.962 menunjukkan tingkat kesesuaian yang kuat antara prediksi model dan kondisi aktual. AUC yang mendekati satu mengindikasikan kemampuan yang sangat baik dalam membedakan tumor ganas dan jinak pada berbagai nilai ambang klasifikasi.

Meskipun demikian, hasil perlu diinterpretasikan secara hati-hati karena pengujian dilakukan pada data uji yang relatif terbatas, yaitu 113 observasi. Performa tinggi pada data uji belum tentu sepenuhnya mencerminkan kinerja model pada populasi yang lebih luas.

6.2 Analisis Kesalahan Klasifikasi

Berdasarkan confusion matrix, terdapat 0 kasus false negative (tumor ganas diprediksi jinak) dan 2 kasus false positive (tumor jinak diprediksi ganas). Dalam konteks diagnosis kanker payudara, false negative adalah kesalahan yang paling perlu diperhatikan karena dapat menyebabkan keterlambatan diagnosis dan penanganan pasien.

Nilai sensitivity sebesar 100.00% menunjukkan sebagian besar (pada split ini, seluruh) kasus tumor ganas berhasil dideteksi dengan benar. Perlu dicatat, dengan basis hanya 42 kasus malignant, sensitivity yang sangat tinggi tetap memiliki ketidakpastian, sehingga belum dapat diklaim sebagai jaminan tanpa false negative pada populasi yang lebih luas. Nilai specificity sebesar 97.18% menunjukkan kemampuan mengidentifikasi tumor jinak. Bila tujuan utama adalah meminimalkan kasus malignant yang terlewat, ambang klasifikasi dapat diturunkan untuk menaikkan sensitivity, dengan konsekuensi specificity menurun.

6.3 Perbandingan Kernel Linear dan RBF

Hasil cross-validation menunjukkan kernel RBF menghasilkan error sebesar 0.0219, sedangkan kernel linear sebesar 0.0242. Perbedaan performa kedua kernel relatif kecil, yaitu setara dengan sekitar 1 observasi dari total 456 data latih — selisih yang berada dalam derau resampling dan tidak bermakna secara praktis.

Temuan ini menunjukkan kedua kernel memiliki kemampuan klasifikasi yang sebanding pada dataset WDBC. Meskipun model akhir dipilih berdasarkan error validasi silang terendah, kernel linear tetap menjadi alternatif yang layak karena lebih sederhana, lebih cepat, dan lebih mudah diinterpretasi. Hasil ini sejalan dengan EDA yang menunjukkan kedua kelas telah cukup terpisah pada ruang fitur.

6.4 Kekuatan Model

Pertama, seluruh proses dilakukan secara reproducible melalui penggunaan random seed tetap. Kedua, standardisasi dilakukan hanya berdasarkan data latih sehingga terhindar dari data leakage. Ketiga, pemilihan hiperparameter memakai 5-fold cross-validation pada data latih untuk mengurangi risiko overfitting. Keempat, evaluasi menggunakan data uji yang tidak terlibat dalam pelatihan maupun tuning.

6.5 Keterbatasan Penelitian

Dataset hanya terdiri dari 569 pasien dari satu sumber, sehingga kemampuan generalisasi terhadap populasi atau sistem pemeriksaan berbeda masih perlu diuji. Beberapa prediktor berkorelasi tinggi sehingga interpretasi kontribusi tiap fitur menjadi lebih sulit. Evaluasi juga hanya memakai satu pembagian data latih-uji; pendekatan seperti nested cross-validation dapat memberi estimasi performa yang lebih stabil. Selain itu, SVM relatif sulit diinterpretasi dibandingkan metode seperti pohon keputusan, sehingga analisis tambahan seperti permutation importance dapat dipertimbangkan untuk konteks klinis.

7 Kesimpulan

tibble(
  Model       = nama_model,
  Accuracy    = round(acc, 4),
  Sensitivity = round(sens, 4),
  Specificity = round(spec, 4),
  AUC         = round(auc_val, 4)
)

Karakteristik morfologi inti sel terbukti dapat digunakan untuk mengklasifikasikan tumor payudara ke dalam kategori malignant dan benign menggunakan SVM. Model terbaik yang diperoleh adalah SVM Radial (RBF) dengan performa sangat baik pada data uji: akurasi 98.23%, AUC 0.9987, sensitivity 100.00%, dan specificity 97.18%.

Perbandingan kernel linear dan RBF menunjukkan performa yang relatif serupa. Meskipun RBF memberikan error validasi silang sedikit lebih rendah dan terpilih sebagai model final, selisihnya tidak bermakna, sehingga kernel linear yang lebih sederhana tetap layak dipertimbangkan.

Hasil yang sangat tinggi ini perlu diinterpretasikan secara hati-hati. WDBC merupakan dataset benchmark yang relatif mudah dipisahkan, sehingga akurasi tinggi tidak serta-merta menjamin performa serupa pada data klinis yang lebih beragam. Untuk penelitian selanjutnya, disarankan validasi pada dataset eksternal atau nested cross-validation guna memperoleh estimasi yang lebih robust. Dalam konteks klinis, perhatian utama sebaiknya diberikan pada sensitivity agar risiko false negative dapat diminimalkan, dan model perlu diuji pada populasi lebih luas sebelum digunakan sebagai alat pendukung keputusan medis.

8 Referensi

  • Wolberg, W. H., Street, W. N., & Mangasarian, O. L. (1995). Breast Cancer Wisconsin (Diagnostic) Data Set. UCI Machine Learning Repository. https://archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+(Diagnostic)
  • Meyer, D. et al. (2023). e1071: Misc Functions of the Department of Statistics, TU Wien. R package.
  • Kuhn, M. (2008). Building Predictive Models in R Using the caret Package. Journal of Statistical Software, 28(5).
  • Robin, X. et al. (2011). pROC: an open-source package for R and S+ to analyze and compare ROC curves. BMC Bioinformatics, 12, 77.
  • Cortes, C., & Vapnik, V. (1995). Support-vector networks. Machine Learning, 20(3), 273–297.