Heart Failure Clinical Records Dataset

Bab I: Metodologi & Praproses Data

A. Deskripsi Dataset

Dataset yang digunakan dalam penelitian ini adalah Heart Failure Clinical Records Dataset yang diperoleh dari UCI Machine Learning Repository (https://archive.ics.uci.edu/dataset/519/heart+failure+clinical+records). Dataset ini berisi data klinis pasien gagal jantung yang digunakan untuk menganalisis kondisi kesehatan pasien berdasarkan berbagai faktor medis dan hasil pemeriksaan laboratorium.

Dataset terdiri dari 299 observasi dan 13 variabel, tanpa terdapat missing value pada seluruh data. Variabel yang tersedia meliputi age, anaemia, creatinine_phosphokinase, diabetes, ejection_fraction, high_blood_pressure, platelets, serum_creatinine, serum_sodium, sex, smoking, time, dan DEATH_EVENT.

Pada penelitian ini digunakan 12 variabel sebagai fitur clustering, yaitu seluruh variabel selain DEATH_EVENT. Variabel DEATH_EVENT tidak digunakan dalam proses clustering karena merupakan variabel target yang menunjukkan status kematian pasien selama masa observasi. Sebelum proses clustering dilakukan, data terlebih dahulu distandardisasi menggunakan metode Z-score untuk mengurangi pengaruh perbedaan skala antarvariabel.

B. Impor dan Eksplorasi Data

# Load package
library(factoextra)
library(cluster)
library(dplyr)
library(gridExtra)
library(clusterCrit)
library(fpc)
library(kmed)
library(corrplot)
# Import data
df <- read.csv("C:/Users/Asus/Downloads/heart_failure_clinical_records_dataset.csv")

# Eksplorasi data
head(df)
##   age anaemia creatinine_phosphokinase diabetes ejection_fraction
## 1  75       0                      582        0                20
## 2  55       0                     7861        0                38
## 3  65       0                      146        0                20
## 4  50       1                      111        0                20
## 5  65       1                      160        1                20
## 6  90       1                       47        0                40
##   high_blood_pressure platelets serum_creatinine serum_sodium sex smoking time
## 1                   1    265000              1.9          130   1       0    4
## 2                   0    263358              1.1          136   1       0    6
## 3                   0    162000              1.3          129   1       1    7
## 4                   0    210000              1.9          137   1       0    7
## 5                   0    327000              2.7          116   0       0    8
## 6                   1    204000              2.1          132   1       1    8
##   DEATH_EVENT
## 1           1
## 2           1
## 3           1
## 4           1
## 5           1
## 6           1
dim(df)
## [1] 299  13
str(df)
## 'data.frame':    299 obs. of  13 variables:
##  $ age                     : num  75 55 65 50 65 90 75 60 65 80 ...
##  $ anaemia                 : int  0 0 0 1 1 1 1 1 0 1 ...
##  $ creatinine_phosphokinase: int  582 7861 146 111 160 47 246 315 157 123 ...
##  $ diabetes                : int  0 0 0 0 1 0 0 1 0 0 ...
##  $ ejection_fraction       : int  20 38 20 20 20 40 15 60 65 35 ...
##  $ high_blood_pressure     : int  1 0 0 0 0 1 0 0 0 1 ...
##  $ platelets               : num  265000 263358 162000 210000 327000 ...
##  $ serum_creatinine        : num  1.9 1.1 1.3 1.9 2.7 2.1 1.2 1.1 1.5 9.4 ...
##  $ serum_sodium            : int  130 136 129 137 116 132 137 131 138 133 ...
##  $ sex                     : int  1 1 1 1 0 1 1 1 0 1 ...
##  $ smoking                 : int  0 0 1 0 0 1 0 1 0 1 ...
##  $ time                    : int  4 6 7 7 8 8 10 10 10 10 ...
##  $ DEATH_EVENT             : int  1 1 1 1 1 1 1 1 1 1 ...
colSums(is.na(df))
##                      age                  anaemia creatinine_phosphokinase 
##                        0                        0                        0 
##                 diabetes        ejection_fraction      high_blood_pressure 
##                        0                        0                        0 
##                platelets         serum_creatinine             serum_sodium 
##                        0                        0                        0 
##                      sex                  smoking                     time 
##                        0                        0                        0 
##              DEATH_EVENT 
##                        0

Pembahasan:

Berdasarkan hasil eksplorasi data, dataset Heart Failure Clinical Records terdiri atas 299 observasi dan 13 variabel. Variabel yang tersedia meliputi data demografi pasien, riwayat penyakit, hasil pemeriksaan laboratorium, serta status kematian pasien. Hasil pemeriksaan struktur data menunjukkan bahwa sebagian besar variabel bertipe numerik dan integer sehingga dapat langsung digunakan dalam proses clustering tanpa memerlukan transformasi tipe data tambahan.

Pemeriksaan terhadap beberapa observasi pertama menggunakan fungsi head() menunjukkan bahwa data telah terbaca dengan baik ke dalam perangkat lunak R. Selanjutnya, hasil pengecekan missing value menggunakan fungsi colSums(is.na()) menunjukkan bahwa seluruh variabel memiliki nilai 0, yang berarti tidak terdapat data yang hilang pada dataset. Dengan demikian, dataset dapat langsung digunakan pada tahap praproses dan analisis clustering tanpa memerlukan penanganan missing value terlebih dahulu.

C. Proccesing Data

# Memisahkan fitur dan label
data <- df[,1:12]
label <- df$DEATH_EVENT
label_int <- as.integer(as.factor(label))

# Scaling data
data_scaled <- scale(data)

Pembahasan:

Setelah proses eksplorasi data, dilakukan pemisahan antara variabel fitur dan variabel label. Sebanyak 12 variabel digunakan sebagai fitur dalam proses clustering, sedangkan variabel DEATH_EVENT dipisahkan sebagai label pembanding pada tahap evaluasi eksternal. Karena clustering merupakan metode unsupervised learning, informasi label tidak digunakan dalam pembentukan cluster, tetapi hanya dimanfaatkan untuk melihat kesesuaian hasil cluster dengan kondisi sebenarnya.

Selanjutnya dilakukan proses standardisasi (scaling) menggunakan metode Z-score. Tahap ini bertujuan untuk menyamakan skala antarvariabel karena setiap variabel memiliki rentang nilai yang berbeda. Sebagai contoh, variabel platelets memiliki nilai hingga ratusan ribu, sedangkan variabel seperti serum_creatinine hanya bernilai satuan. Tanpa proses scaling, variabel dengan rentang nilai yang besar akan mendominasi perhitungan jarak dalam proses clustering. Oleh karena itu, standardisasi dilakukan agar seluruh variabel memiliki kontribusi yang lebih seimbang dalam pembentukan cluster.

Bab II: Analisis dan Pembahasan Hasil

A. Penentuan Jumlah Cluster Optimal

# Menentukan jumlah cluster optimal 
plot_elbow <- fviz_nbclust( data_scaled, kmeans, method = "wss")

plot_sil <- fviz_nbclust( data_scaled, kmeans, method = "silhouette")

grid.arrange(plot_elbow, plot_sil, ncol = 2)

# Tentukan K sesuai hasil plot
k_optimal <- 2

Pembahasan:

Berdasarkan hasil visualisasi terbaru yang telah dikunci menggunakan fungsi set.seed(), diperoleh rekomendasi jumlah cluster yang sangat konsisten dan konvergen antara kedua metode di angka k = 2. Pada grafik Elbow Method (kiri), penurunan nilai Total Within Sum of Squares (WSS) yang paling tajam terjadi pada peralihan dari cluster 1 ke cluster 2, di mana setelah titik k = 2 kurva mulai melandai secara konstan membentuk siku (elbow).

Selaras dengan hal tersebut, grafik Silhouette Method (kanan) secara tegas mencetak nilai average silhouette width tertinggi pada titik puncak k = 2. Mengingat kedua metode ini memberikan keputusan yang seragam, maka jumlah k = 2 ditetapkan sebagai jumlah cluster paling optimal dalam penelitian ini karena mampu merepresentasikan struktur kelompok alami dataset secara maksimal dan stabil.

B. Analisis Metode K-Means Clustering

1. K-Means

# a. K-Means
kmeans_result <- kmeans( data_scaled, centers = k_optimal, nstart = 25)
kmeans_result
## K-means clustering with 2 clusters of sizes 107, 192
## 
## Cluster means:
##           age     anaemia creatinine_phosphokinase   diabetes ejection_fraction
## 1 -0.09629548  0.12878057              -0.11383868  0.2320537         0.2322096
## 2  0.05366467 -0.07176834               0.06344135 -0.1293216        -0.1294085
##   high_blood_pressure  platelets serum_creatinine serum_sodium        sex
## 1          0.16467263  0.1813572      -0.01820463   0.04253077 -1.3179040
## 2         -0.09177068 -0.1010689       0.01014529  -0.02370204  0.7344569
##      smoking        time
## 1 -0.6065961  0.02132365
## 2  0.3380510 -0.01188349
## 
## Clustering vector:
##   [1] 2 2 2 2 1 2 2 2 1 2 2 2 2 2 1 2 2 2 1 1 1 1 2 2 1 2 1 2 2 2 2 2 1 1 2 2 2
##  [38] 1 2 1 2 1 2 2 1 2 2 2 2 1 2 1 1 1 1 2 2 2 2 2 2 1 2 2 1 2 1 2 1 2 2 2 2 2
##  [75] 2 2 1 2 2 1 1 2 1 2 1 2 2 1 2 2 2 2 1 2 1 2 2 1 1 1 2 2 2 2 1 1 2 2 2 2 2
## [112] 2 2 1 2 1 1 1 1 1 2 1 1 1 2 1 1 1 2 2 2 2 1 2 2 2 1 2 1 2 2 1 1 1 2 2 2 2
## [149] 2 2 1 2 2 2 1 2 1 2 2 2 2 2 2 1 2 1 2 2 1 1 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2
## [186] 2 1 1 1 1 2 1 2 2 2 2 1 1 1 2 2 1 2 2 2 1 1 2 1 1 2 2 2 1 2 2 1 1 2 1 2 2
## [223] 2 2 2 1 2 2 1 1 1 2 2 2 2 2 2 2 1 2 1 2 2 1 2 2 2 2 2 1 1 1 2 1 2 2 1 2 2
## [260] 2 2 1 2 1 2 2 2 2 1 2 2 1 1 2 2 1 1 2 1 1 2 2 2 2 2 2 2 1 1 1 1 2 2 2 2 1
## [297] 1 2 2
## 
## Within cluster sum of squares by cluster:
## [1] 1090.896 2099.518
##  (between_SS / total_SS =  10.8 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
table(kmeans_result$cluster)
## 
##   1   2 
## 107 192

Pembahasan:

Berdasarkan hasil analisis menggunakan metode K-Means Clustering, diperoleh jumlah cluster optimal sebanyak 2 cluster. Cluster 1 terdiri dari 107 data, sedangkan cluster 2 terdiri dari 192 data sehingga cluster 2 memiliki jumlah anggota lebih banyak. Hasil cluster means menunjukkan adanya perbedaan karakteristik pada beberapa variabel kesehatan antar cluster.

Cluster 1 cenderung memiliki nilai lebih tinggi pada variabel seperti anaemia, diabetes, dan high blood pressure, sedangkan cluster 2 memiliki nilai lebih tinggi pada variabel seperti smoking dan serum creatinine. Nilai (between_SS / total_SS) sebesar 10,8% menunjukkan bahwa pemisahan antar cluster masih tergolong rendah sehingga perbedaan karakteristik antar cluster belum terlalu signifikan. Secara keseluruhan, metode K-Means mampu mengelompokkan data pasien berdasarkan kemiripan karakteristik variabel kesehatan yang digunakan

2. Visualisasi Plot Elips K-Means

# b. Visualisasi K-Means
fviz_cluster( kmeans_result, data = data_scaled, ellipse.type = "convex", 
              geom = "point", palette = "jco",ggtheme = theme_bw(), 
              main = "K-Means Clustering"
)

Pembahasan:

Berdasarkan visualisasi hasil K-Means Clustering, data berhasil dikelompokkan menjadi 2 cluster yang ditunjukkan dengan warna biru untuk cluster 1 dan warna kuning untuk cluster 2. Penyebaran data pada grafik menunjukkan bahwa sebagian besar anggota cluster 1 berada pada sisi kanan grafik, sedangkan cluster 2 lebih banyak berada pada sisi kiri grafik. Meskipun demikian, terdapat beberapa titik data yang saling berdekatan pada area tengah sehingga menunjukkan adanya kemiripan karakteristik antar sebagian data pada kedua cluster.

Visualisasi juga menunjukkan bahwa cluster 2 memiliki penyebaran data yang lebih luas dibandingkan cluster 1. Hal ini menandakan bahwa variasi karakteristik data pada cluster 2 lebih beragam. Selain itu, kedua cluster masih memiliki sedikit area tumpang tindih (overlapping) sehingga pemisahan antar cluster belum sepenuhnya jelas. Secara keseluruhan, metode K-Means mampu membagi data berdasarkan kemiripan karakteristik variabel yang digunakan pada proses clustering.

3. Profil Karakteristik Cluster K-Means

# c. Profil Cluster K-Means
profil_km <- aggregate( data, by = list
                        (Cluster = kmeans_result$cluster), mean
)

profil_km
##   Cluster      age   anaemia creatinine_phosphokinase  diabetes
## 1       1 59.68848 0.4953271                 471.3832 0.5327103
## 2       2 61.47222 0.3958333                 643.3958 0.3541667
##   ejection_fraction high_blood_pressure platelets serum_creatinine serum_sodium
## 1          40.83178           0.4299065  281095.5         1.375047     136.8131
## 2          36.55208           0.3072917  253473.1         1.404375     136.5208
##          sex    smoking     time
## 1 0.01869159 0.03738318 131.9159
## 2 1.00000000 0.47916667 129.3385

Pembahasan:

Berdasarkan hasil profil cluster, terdapat perbedaan karakteristik antara cluster 1 dan cluster 2. Cluster 1 memiliki rata-rata usia sebesar 59,69 tahun dengan proporsi penderita anaemia sebesar 49,53% dan diabetes sebesar 53,27%. Selain itu, cluster 1 memiliki rata-rata ejection fraction lebih tinggi yaitu 40,83 dibandingkan cluster 2. Nilai rata-rata platelets pada cluster 1 juga lebih besar, yaitu 281095,5.

Sementara itu, cluster 2 memiliki rata-rata usia sedikit lebih tinggi yaitu 61,47 tahun. Cluster ini memiliki rata-rata creatinine phosphokinase lebih besar sebesar 643,40 serta rata-rata serum creatinine sebesar 1,40. Pada variabel sex dan smoking, cluster 2 memiliki nilai lebih tinggi dibandingkan cluster 1, yang menunjukkan bahwa cluster 2 lebih banyak didominasi oleh pasien laki-laki dan perokok. Selain itu, nilai ejection fraction pada cluster 2 lebih rendah dibandingkan cluster 1 sehingga menunjukkan kondisi fungsi jantung yang relatif lebih rendah.

Secara keseluruhan, hasil profil cluster menunjukkan bahwa metode K-Means mampu mengelompokkan pasien berdasarkan kemiripan karakteristik kesehatan sehingga setiap cluster memiliki ciri yang berbeda.

C. Analisis Metode Hierarchical Clustering

1. Pemodelan dan Analisis Dendrogram

dist_matrix <- dist(data_scaled)

hc <- hclust(dist_matrix, method = "ward.D2")

# Plot dendrogram 
if (inherits(hc, "hclust")) {
  plot(
    hc,
    labels = FALSE, 
    hang = -1,
    main = "Dendrogram Hierarchical Clustering",
    xlab = "",
    sub = ""
  )
  
  rect.hclust(hc, k = k_optimal, border = "red")
} else {
  stop("Objek hc bukan merupakan hasil hclust!")
}

# Potong pohon
hc_cluster <- cutree(hc, k = k_optimal)
table(hc_cluster)
## hc_cluster
##   1   2 
## 168 131

Pembahasan:

Analisis dilanjutkan dengan mengamati struktur pengelompokan secara hierarki melalui visualisasi Dendrogram menggunakan metode Ward’s Distance (k = 2).

Berdasarkan plot di atas, pembagian data digambarkan secara tegas oleh garis pembatas merah yang membelah objek menjadi dua kelompok besar, di mana proses pemotongan pohon (cutting tree) menghasilkan distribusi anggota yang cukup seimbang, yaitu sebanyak 168 pasien masuk ke dalam klaster 1 dan 131 pasien masuk ke dalam klaster 2. Pola percabangan pada klaster 1 cenderung lebih stabil pada tingkat height yang rendah, sedangkan klaster 2 baru menyatu pada nilai height yang lebih tinggi (mendekati skala 20) yang mengindikasikan bahwa variasi karakteristik medis pasien di dalam klaster 2 cenderung lebih heterogen.

Pembagian jumlah anggota yang proporsional ini membuktikan bahwa metode Hierarchical berhasil mengelompokkan data secara objektif tanpa menciptakan fenomena singleton cluster, sehingga kedua kelompok ini valid untuk dianalisis lebih lanjut karakteristik klinisnya.

2. Visualisasi Plot Elips Hierarchical

# Plot Hierarchical
fviz_cluster(
  list(
    data = data_scaled,
    cluster = hc_cluster
  ),
  ellipse.type = "convex",
  geom = "point",
  palette = "jco",
  ggtheme = theme_bw(),
  main = "Hierarchical Clustering"
)

Pembahasan:

Visualisasi hasil Hierarchical Clustering dilakukan menggunakan plot dua dimensi berbasis Principal Component Analysis (PCA), di mana Dim1 (13,9%) dan Dim2 (13,2%) bertindak sebagai komponen utama yang mereduksi keseluruhan dimensi fitur klinis. Berdasarkan grafik di atas, terlihat pembentukan dua wilayah klaster (convex hull) yang cukup terstruktur, di mana klaster 1 digambarkan oleh area berwarna biru (simbol lingkaran) dan klaster 2 oleh area berwarna kuning (simbol segitiga).

Meskipun kedua klaster mampu menunjukkan pusat massa (centroid) yang terpisah secara spasial, terdapat area irisan (overlapping) yang cukup tebal di bagian tengah grafik. Fenomena tumpang tindih ini mencerminkan karakteristik alami dari data medis pasien gagal jantung, di mana batas kondisi klinis antar-pasien secara riil bersifat kontinu dan memiliki kemiripan nilai pada beberapa indikator laboratorium tertentu, sehingga tidak terpisah secara ekstrem (well-separated).

3. Profil Karakteristik Cluster Hierarchical

profil_hc <- aggregate(data,by = list(Cluster = hc_cluster), mean
)

profil_hc
##   Cluster      age   anaemia creatinine_phosphokinase  diabetes
## 1       1 61.75397 0.4464286                 618.1964 0.3154762
## 2       2 59.65395 0.4122137                 535.2137 0.5496183
##   ejection_fraction high_blood_pressure platelets serum_creatinine serum_sodium
## 1          37.23810           0.3630952  246224.7         1.511905     136.6786
## 2          39.16794           0.3358779  285330.5         1.242519     136.5573
##         sex    smoking     time
## 1 0.9702381 0.54761905 127.8452
## 2 0.2366412 0.03053435 133.3588

Pembahasan:

Berdasarkan tabel rata-rata profil klinis di atas, metode Hierarchical Clustering berhasil mengidentifikasi dua kelompok pasien dengan karakteristik medis yang sangat kontras dan bermakna secara klinis. Klaster 1 dapat diidentifikasi sebagai kelompok pasien laki-laki perokok dengan risiko komplikasi ginjal, di mana anggotanya didominasi oleh pria (97%) dan perokok (54,7%), serta memiliki rata-rata kadar kreatinin serum yang lebih tinggi (1,51 mg/dL) yang mengindikasikan adanya penurunan fungsi ginjal. Sebaliknya, Klaster 2 merupakan kelompok pasien wanita dengan prevalensi diabetes yang tinggi, yang dicirikan oleh dominasi pasien perempuan (76,3%) dan hampir seluruhnya bukan perokok (97%), namun memiliki riwayat penyakit diabetes yang sangat tinggi mencapai 54,9% dibandingkan klaster 1 yang hanya 31,5%.

Meskipun kedua klaster memiliki kemiripan pada indikator usia (sekitar 60 tahun) dan kadar natrium darah, pemisahan yang kontras pada faktor gender, kebiasaan merokok, dan diabetes ini membuktikan bahwa algoritma mampu menangkap pola pengelompokan yang relevan dengan faktor risiko klinis pada pasien gagal jantung.

D. Validasi Eksternal Hasil Clustering

tab_km <- table(
  Actual = label,
  Cluster = kmeans_result$cluster
)

tab_hc <- table(
  Actual = label,
  Cluster = hc_cluster
)

tab_km
##       Cluster
## Actual   1   2
##      0  73 130
##      1  34  62
tab_hc
##       Cluster
## Actual   1   2
##      0 110  93
##      1  58  38

Pembahasan:

Berdasarkan hasil tabulasi silang (cross-tabulation) di atas, kita dapat mengevaluasi sejauh mana pengelompokan unsupervised ini mampu mengenali status fatalitas pasien (DEATH_EVENT). Pada metode K-Means, algoritma cenderung memetakan pasien yang bertahan hidup (0) ke dalam Cluster 2 sebanyak 130 observasi, dan pasien yang meninggal (1) ke dalam Cluster 1 sebanyak 34 observasi, dengan tingkat akurasi korespondensi sebesar 54,8%. Sementara itu, metode Hierarchical (Ward’s) menghasilkan pengelompokan yang lebih bias secara klinis, di mana Cluster 1 mendominasi dengan menampung sebagian besar pasien hidup (110 orang) sekaligus pasien meninggal (58 orang), sehingga akurasi korespondensinya hanya mencapai 49,4%.

Secara keseluruhan, rendahnya nilai kecocokan pada kedua metode ini menunjukkan bahwa fitur-fitur klinis laboratorium yang digunakan dalam clustering memiliki variasi yang sangat cair, sehingga kondisi fatalitas pasien di dunia nyata tidak bisa hanya diprediksi berdasarkan kemiripan pola fisik dan laboratorium medisnya saja.

E. Evaluasi Kualitas Cluster (Internal & Eksternal)

1. Analisis Silhouette Coefficient

# 1. Menghitung objek silhouette berdasarkan jarak objek dan hasil cluster
sil_km <- silhouette(kmeans_result$cluster, dist_matrix)

sil_hc <- silhouette(hc_cluster,dist_matrix) 

# 2. Mengambil nilai rata-rata (mean) silhouette width dari kolom ke-3
mean_sil_km <- mean(sil_km[, 3])
mean_sil_hc <- mean(sil_hc[, 3])

# 3. Menampilkan nilai rata-rata silhouette di konsol
mean_sil_km
## [1] 0.1178513
mean_sil_hc
## [1] 0.0881889
# 4. Membuat visualisasi grafik silhouette dengan tema hitam-putih (theme_bw)
p1 <- fviz_silhouette(sil_km, ggtheme = theme_bw())
##   cluster size ave.sil.width
## 1       1  107          0.14
## 2       2  192          0.10
p2 <- fviz_silhouette(sil_hc, ggtheme = theme_bw())
##   cluster size ave.sil.width
## 1       1  168          0.06
## 2       2  131          0.12
# 5. Menggabungkan kedua plot secara berdampingan (2 kolom)
grid.arrange(p1, p2, ncol = 2)

Pembahasan:

Evaluasi validitas internal kelompok dilakukan menggunakan analisis Silhouette Coefficient untuk mengukur seberapa baik suatu objek ditempatkan di dalam clusternya serta seberapa tegas pemisahan antar-kelompok. Berdasarkan visualisasi grafik gabungan di atas, metode K-Means (kiri) menghasilkan nilai mean silhouette width sebesar 0,1179, dengan kekuatan lokal sebesar 0,14 pada klaster 1 (n = 107 ) dan 0,10 pada klaster 2 (n = 192).

Di sisi lain, metode Hierarchical (kanan) mencatat nilai rata-rata yang lebih rendah yaitu sebesar 0,0882, di mana klaster 1 (n = 168) hanya mencapai nilai 0,06 dan klaster 2 (n = 131) sebesar 0,12. Secara visual, mayoritas balok es pada kedua plot berada di atas garis nol (bernilai positif), yang menandakan bahwa sebagian besar pasien sudah berada di kelompok yang tepat. Namun, ketebalan balok yang tidak merata dan nilai rata-rata yang berada di bawah 0,25 mengindikasikan bahwa dataset klinis ini secara alami memiliki struktur kelompok yang lemah (weak structure) dengan tingkat tumpang tindih (overlapping) yang tinggi di area perbatasan. Meskipun demikian, secara geometris visual, metode K-Means terbukti memberikan hasil pengelompokan yang sedikit lebih solid dan seimbang dibandingkan metode Hierarchical.

2. Analisis Purity dan Rand Index

# 1. Menghitung Nilai Purity (Kemurnian Cluster terhadap Label Aktual)
purity_km <- sum(apply(tab_km, 2, max)) / sum(tab_km)
purity_hc <- sum(apply(tab_hc, 2, max)) / sum(tab_hc)

# 2. Menghitung Nilai Rand Index (Kesesuaian Pasangan Objek)
# Fungsi extCriteria di clusterCrit menggunakan huruf kecil untuk argumen "Rand"
rand_km <- extCriteria(
  as.integer(kmeans_result$cluster),
  label_int,
  "Rand"
)$rand

rand_hc <- extCriteria(
  as.integer(hc_cluster),
  label_int,
  "Rand"
)$rand

# 3. Menampilkan Hasil Cetak di Konsol
cat("Purity K-Means     :", purity_km, "\n")
## Purity K-Means     : 0.6789298
cat("Purity Hierarchical:", purity_hc, "\n")
## Purity Hierarchical: 0.6789298
cat("Rand Index K-Means :", rand_km, "\n")
## Rand Index K-Means : 0.5030414
cat("Rand Index Hierarch:", rand_hc, "\n")
## Rand Index Hierarch: 0.4983726

Pembahasan:

Analisis dilanjutkan dengan melakukan evaluasi eksternal menggunakan indikator Purity (Kemurnian) untuk mengukur kemampuan algoritma unsupervised dalam mengenali label kondisi aktual pasien (DEATH_EVENT). Berdasarkan hasil perhitungan, kedua metode menghasilkan nilai Purity yang identik yaitu sebesar 0,6789 (67,89%). Nilai yang kembar ini menunjukkan bahwa baik K-Means maupun Hierarchical Clustering memiliki kapasitas kemurnian yang benar-benar setara dalam menangkap dominasi kelas aktual di setiap clusternya, di mana kedua metode tersebut mampu mengelompokkan secara tepat sebanyak 203 dari total 299 observasi pasien gagal jantung berdasarkan fitur-fitur klinis yang tersedia.

Meskipun nilai kemurnian clusternya setara, pengujian menggunakan Rand Index (RI) berhasil menunjukkan adanya sedikit perbedaan performa dalam hal konsistensi pasangan objek. Pada parameter ini, metode K-Means mencatat nilai RI yang sedikit lebih unggul sebesar 0,5030 dibandingkan metode Hierarchical yang hanya mencapai 0,4984. Nilai Rand Index yang berada di kisaran 0,5 ini mengindikasikan bahwa performa kedua algoritma dalam merepresentasikan status fatalitas pasien berada pada tingkat yang moderat (sedang). Secara keseluruhan, hasil pengujian eksternal ini menegaskan bahwa metode K-Means memberikan kestabilan dan akurasi pasangan objek yang sedikit lebih optimal dibandingkan metode Hierarchical dalam memetakan kondisi klinis riil pasien.

F. Evaluasi Kestabilan Cluster (Bootstrap & Consensus Heatmap)

# 1. ANALISIS NILAI STABILITAS
# Bootstrap nilai untuk K-Means
boot_km <- clusterboot(
  data_scaled,
  B = 50,
  clustermethod = kmeansCBI,
  krange = k_optimal,
  seed = 123
)
## boot 1 
## boot 2 
## boot 3 
## boot 4 
## boot 5 
## boot 6 
## boot 7 
## boot 8 
## boot 9 
## boot 10 
## boot 11 
## boot 12 
## boot 13 
## boot 14 
## boot 15 
## boot 16 
## boot 17 
## boot 18 
## boot 19 
## boot 20 
## boot 21 
## boot 22 
## boot 23 
## boot 24 
## boot 25 
## boot 26 
## boot 27 
## boot 28 
## boot 29 
## boot 30 
## boot 31 
## boot 32 
## boot 33 
## boot 34 
## boot 35 
## boot 36 
## boot 37 
## boot 38 
## boot 39 
## boot 40 
## boot 41 
## boot 42 
## boot 43 
## boot 44 
## boot 45 
## boot 46 
## boot 47 
## boot 48 
## boot 49 
## boot 50
# Bootstrap nilai untuk Hierarchical Ward's
boot_hc <- clusterboot(
  dist(data_scaled),
  B = 50,
  clustermethod = disthclustCBI,
  method = "ward.D2",
  k = k_optimal
)
## boot 1 
## boot 2 
## boot 3 
## boot 4 
## boot 5 
## boot 6 
## boot 7 
## boot 8 
## boot 9 
## boot 10 
## boot 11 
## boot 12 
## boot 13 
## boot 14 
## boot 15 
## boot 16 
## boot 17 
## boot 18 
## boot 19 
## boot 20 
## boot 21 
## boot 22 
## boot 23 
## boot 24 
## boot 25 
## boot 26 
## boot 27 
## boot 28 
## boot 29 
## boot 30 
## boot 31 
## boot 32 
## boot 33 
## boot 34 
## boot 35 
## boot 36 
## boot 37 
## boot 38 
## boot 39 
## boot 40 
## boot 41 
## boot 42 
## boot 43 
## boot 44 
## boot 45 
## boot 46 
## boot 47 
## boot 48 
## boot 49 
## boot 50
# Menampilkan nilai rata-rata stabilitas (bootmean) tiap cluster
boot_km$bootmean
## [1] 0.6198355 0.7181558
boot_hc$bootmean
## [1] 0.6602457 0.6296907
# 2. VISUALISASI CONSENSUS HEATMAP

dist_pasien <- dist(as.matrix(data_scaled))

# Heatmap K-Means
skm_pasien_func <- function(x, nclust){ skm(x, nclust)$cluster }
boot_km_map <- clustboot(dist_pasien, nclust = 2, nboot = 50, algorithm = skm_pasien_func)
consensus_km <- consensusmatrix(boot_km_map, nclust = 2)
clustheatmap(consensus_km, "Consensus Heatmap - K-Means")
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the kmed package.
##   Please report the issue to the authors.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

# Heatmap Hierarchical Ward
wardfunc <- function(x, nclust){
  res <- hclust(as.dist(x), method = "ward.D2")
  return(cutree(res, nclust))
}
wardbootstrap <- clustboot(dist_pasien, nclust = 2, nboot = 50, algorithm = wardfunc)
consensusward <- consensusmatrix(wardbootstrap, nclust = 2, wardfunc)
clustheatmap(consensusward, "Heart Failure Data evaluated by Ward Linkage")

Pembahasan:

Analisis kestabilan kelompok dilakukan menggunakan dua pendekatan komplementer, yaitu pengujian nilai kuantitatif Bootstrap Resampling melalui fungsi clusterboot() (dengan replikasi \(B = 50\)) serta konfirmasi visual melalui grafik Consensus Heatmap dengan fungsi clustheatmap().Berdasarkan hasil pengujian kuantitatif, metode K-Means memperoleh nilai bootstrap mean (bootmean) sebesar 0.6198 untuk klaster 1 dan sebesar 0.7182 untuk klaster 2. Sementara itu, metode Hierarchical Clustering (Ward’s) mencatat nilai stabilitas sebesar 0.6602 pada klaster 1 dan 0.6297 pada klaster 2.

Berdasarkan kriteria interpretasi oleh Hennig, nilai yang berada pada rentang 0.60 hingga 0.85 mengindikasikan bahwa kedua algoritma berhasil membentuk struktur kelompok pada kategori cukup stabil (stable). Karakteristik klinis pasien di dalamnya terbukti bersifat valid dan bukan sekadar pola semu yang terbentuk secara kebetulan.

Temuan angka kuantitatif tersebut diperkuat secara visual melalui pola gradien warna pada grafik Consensus Heatmap yang dihasilkan:

  1. Pada Consensus Heatmap K-Means: Pembentukan blok kontur persegi berwarna kuning-putih terang di sepanjang garis diagonal utama terlihat sangat solid, tegas, dan terpisah secara simetris dengan batas sekat warna yang tajam. Pola visual yang kaku ini merefleksikan tingginya ketahanan spasial klaster 2 K-Means (0.7182), membuktikan bahwa algoritma ini sangat konsisten mempertahankan posisinya dari efek gangguan acak (noise).

  2. Pada Consensus Heatmap Hierarchical Clustering: Meskipun susunan datanya telah diurutkan mengikuti struktur pohon (wardfunc) sehingga membentuk pola anak tangga diagonal yang rapi, batas konturnya cenderung tampak lebih baur dengan degradasi warna yang menyebar di area perbatasan. Pola visual ini menyelaraskan alasan mengapa nilai stabilitas Hierarchical berada di angka yang lebih rendah (0.6602 dan 0.6297), menandakan adanya tingkat ambiguitas posisi spasial (overlapping) yang lebih tinggi antar-pasien saat sampel diresampling.

Secara keseluruhan, integrasi evaluasi teoritis Hennig dan bukti visual heatmap memberikan kesimpulan yang mutlak bahwa metode K-Means Clustering memberikan hasil pengelompokan yang jauh lebih stabil, kokoh (robust), dan reliabel untuk dataset klinis pasien gagal jantung ini.

G. Ringkasan Perbandingan Performa Algoritma

# TABEL PERBANDINGAN
hasil <- data.frame(
  Metode = c("K-Means", "Hierarchical"),
  Silhouette = c(round(mean_sil_km, 4), round(mean_sil_hc, 4)),
  Purity = c(round(purity_km, 4), round(purity_hc, 4)),
  Rand_Index = c(round(rand_km, 4), round(rand_hc, 4))
)

print(hasil)
##         Metode Silhouette Purity Rand_Index
## 1      K-Means     0.1179 0.6789     0.5030
## 2 Hierarchical     0.0882 0.6789     0.4984
# KESIMPULAN
if(mean_sil_km > mean_sil_hc){
  print("Kesimpulan Sistem: Metode terbaik berdasarkan validitas internal adalah K-Means")
} else {
  print("Kesimpulan Sistem: Metode terbaik berdasarkan validitas internal adalah Hierarchical Clustering")
}
## [1] "Kesimpulan Sistem: Metode terbaik berdasarkan validitas internal adalah K-Means"

Pembahasan:

Berdasarkan output tabel perbandingan otomatis di atas, sistem secara tegas menetapkan bahwa K-Means merupakan metode terbaik untuk dataset klinis ini karena unggul pada mayoritas parameter evaluasi:

  1. Silhouette Coefficient (Validitas Internal): K-Means unggul dengan nilai 0.1179 dibandingkan Hierarchical (0.0882). Hal ini membuktikan bahwa secara geometris, K-Means mampu membentuk batas kelompok yang lebih solid dan meminimalkan kesalahan penempatan objek secara lebih optimal.

  2. Purity (Validitas Eksternal): Kedua metode menghasilkan nilai yang identik secara presisi, yaitu 0.6789 (67.89%). Artinya, kedua algoritma memiliki kemampuan yang benar-benar setara dalam menangkap dominasi kelas fatalitas aktual (DEATH_EVENT) pada tiap klaster.

  3. Rand Index (Konsistensi Pasangan): K-Means kembali unggul tipis dengan skor 0.5030 dibanding Hierarchical (0.4984), yang menandakan K-Means sedikit lebih konsisten dalam memetakan kecocokan pasangan objek pasien.

Melalui integrasi logika percabangan if-else, sistem mengonfirmasi bahwa metode K-Means Clustering memberikan hasil pengelompokan yang jauh lebih reliabel, konsisten, dan optimal untuk data klinis pasien gagal jantung ini.

Bab III: Kesimpulan

Berdasarkan seluruh rangkaian analisis komparatif pengelompokan menggunakan metode K-Means Clustering dan Hierarchical Clustering (Ward’s Linkage) pada dataset pasien gagal jantung, dapat ditarik kesimpulan utama sebagai berikut:

  1. Jumlah kelompok alami paling optimal untuk memetakan karakteristik klinis pasien dalam dataset ini adalah sebanyak k = 2 kelompok, didukung secara konsisten oleh pengujian Elbow dan Silhouette Method.

  2. Kedua metode berhasil mengidentifikasi segmentasi medis yang kontras, mencakup kelompok pasien dengan risiko komplikasi penyakit dalam serta kelompok pasien pria perokok dengan gangguan fungsi ginjal.

  3. Evaluasi internal geometris menunjukkan K-Means lebih unggul dengan nilai silhouette width 0.1179 dibandingkan Hierarchical (0.0882).

  4. Validasi eksternal menghasilkan nilai Purity yang identik (67.89%), namun K-Means memiliki konsistensi pasangan objek yang sedikit lebih baik melalui nilai Rand Index 0.5030.

  5. Uji ketahanan Bootstrap dan Consensus Heatmap mengonfirmasi bahwa K-Means memiliki struktur kelompok yang lebih kokoh (robust) dengan nilai bootstrap mean tertinggi 0.7182 (kategori stable).

Secara keseluruhan, metode K-Means Clustering direkomendasikan sebagai algoritma yang lebih unggul, konsisten, dan reliabel dalam mengelompokkan data klinis pasien gagal jantung pada penelitian ini.