Dosen Pengampu: Ike Fitriyaningsih, M.Si
## age gender chest_pain_type blood_pressure cholesterol max_heart_rate
## 1 24 1 4 250 139 212
## 2 29 0 4 132 187 147
## 3 46 0 3 271 185 193
## 4 73 NA 2 102 200 125
## 5 49 1 3 91 163 192
## 6 63 1 3 18 154 107
## 7 48 0 3 143 275 165
## 8 37 1 4 263 201 201
## 9 20 0 3 113 127 139
## 10 77 1 1 138 217 201
## exercise_angina plasma_glucose skin_thickness insulin bmi
## 1 0 108 33 109 37.99930
## 2 0 202 42 NA 25.58835
## 3 0 149 43 102 37.89203
## 4 0 105 77 165 18.66024
## 5 0 162 31 170 12.76798
## 6 0 103 67 102 22.37385
## 7 0 248 NA 136 27.90071
## 8 0 186 21 180 35.66340
## 9 1 123 NA 120 26.52915
## 10 0 199 100 132 18.39360
## diabetes_pedigree hypertension heart_disease residence_type smoking_status
## 1 0.4802775 1 1 Urban Smoker
## 2 0.2839864 1 1 Urban Unknown
## 3 2.4723086 1 0 Rural Non-Smoker
## 4 1.4720523 0 1 Rural Smoker
## 5 0.5376265 1 1 Rural Smoker
## 6 1.0624109 0 0 Rural Non-Smoker
## 7 1.0737608 1 1 Rural Non-Smoker
## 8 0.1512359 0 0 Urban Smoker
## 9 1.9102780 1 0 Urban Non-Smoker
## 10 1.8253058 1 0 Rural Non-Smoker
data %>%
summarise(across(everything(), ~sum(is.na(.)))) %>%
pivot_longer(everything(), names_to = "Kolom", values_to = "Jumlah_NA") %>%
mutate(Persen_NA = round((Jumlah_NA / nrow(data)) * 100, 2))## # A tibble: 16 × 3
## Kolom Jumlah_NA Persen_NA
## <chr> <int> <dbl>
## 1 age 0 0
## 2 gender 472 7.87
## 3 chest_pain_type 0 0
## 4 blood_pressure 0 0
## 5 cholesterol 0 0
## 6 max_heart_rate 0 0
## 7 exercise_angina 0 0
## 8 plasma_glucose 609 10.2
## 9 skin_thickness 614 10.2
## 10 insulin 568 9.47
## 11 bmi 0 0
## 12 diabetes_pedigree 0 0
## 13 hypertension 0 0
## 14 heart_disease 0 0
## 15 residence_type 0 0
## 16 smoking_status 0 0
# Cek nilai kosong " " atau spasi pada kolom karakter
sapply(data, function(x) {
if (is.character(x) || is.factor(x)) sum(trimws(x) == "") else 0
})## age gender chest_pain_type blood_pressure
## 0 0 0 0
## cholesterol max_heart_rate exercise_angina plasma_glucose
## 0 0 0 0
## skin_thickness insulin bmi diabetes_pedigree
## 0 0 0 0
## hypertension heart_disease residence_type smoking_status
## 0 0 455 0
Dari hasil cek nilai kosong pada setiap kolom dataset, ditemukan kolom gender, plasma_glucose, skin_thickness, dan insulin memiliki nilai kosong (NA). Selain itu, terdapat 455 baris nilai dengan kolom kosong (” “) pada kolom residence_type, yang berarti baris-baris tersebut tidak memiliki informasi tentang jenis tempat tinggal pasien.
ohe_encode <- function(df, column) {
dummies <- dummyVars(as.formula(paste("~", column)), data = df)
ohe <- predict(dummies, newdata = df)
colnames(ohe) <- gsub("\\.", "_", colnames(ohe))
ohe_df <- as.data.frame(ohe)
df <- cbind(df, ohe_df)
df <- df[, !(names(df) %in% column)]
return(df)
}
data <- ohe_encode(data, "residence_type")
data <- ohe_encode(data, "gender")
data <- ohe_encode(data, "smoking_status")data %>%
summarise(across(everything(), ~sum(is.na(.)))) %>%
pivot_longer(everything(), names_to = "Kolom", values_to = "Jumlah_NA") %>%
mutate(Persen_NA = round((Jumlah_NA / nrow(data)) * 100, 2))## # A tibble: 18 × 3
## Kolom Jumlah_NA Persen_NA
## <chr> <int> <dbl>
## 1 age 0 0
## 2 chest_pain_type 0 0
## 3 blood_pressure 0 0
## 4 cholesterol 0 0
## 5 max_heart_rate 0 0
## 6 exercise_angina 0 0
## 7 plasma_glucose 0 0
## 8 skin_thickness 0 0
## 9 insulin 0 0
## 10 bmi 0 0
## 11 diabetes_pedigree 0 0
## 12 hypertension 0 0
## 13 heart_disease 0 0
## 14 residence_typeRural 0 0
## 15 residence_typeUrban 0 0
## 16 smoking_statusNon-Smoker 0 0
## 17 smoking_statusSmoker 0 0
## 18 smoking_statusUnknown 0 0
# Elbow Method
fviz_nbclust(data_scaled, kmeans, method = "wss") +
labs(title = "Elbow Method", x = "Jumlah Cluster", y = "WSS")# Silhouette Method
fviz_nbclust(data_scaled, kmeans, method = "silhouette") +
labs(title = "Silhouette Method")set.seed(123)
kmeans_result <- kmeans(data_scaled, centers = 3, nstart = 25)
fviz_cluster(list(data = data_scaled, cluster = kmeans_result$cluster),
main = "K-Means Clustering")
Hasil clustering K-Means tanpa PCA menunjukkan bahwa pemilihan tiga
klaster didukung oleh metode Silhouette dan Elbow yang konsisten, dengan
nilai silhouette tertinggi sekitar 0,12. Visualisasi scatter plot
memperlihatkan ketiga klaster terpisah dengan jelas.
silhouette_kmeans <- silhouette(kmeans_result$cluster, dist(data_scaled))
silhouette_score_kmeans <- mean(silhouette_kmeans[, 3]) # Nilai rata-rata Silhouette
wss_kmeans <- kmeans_result$tot.withinss # WSS (Within-Cluster Sum of Squares)
cat("Silhouette Score K-Meanstanpa PCA:", silhouette_score_kmeans, "\n")## Silhouette Score K-Meanstanpa PCA: 0.1246539
## WSS (Within-Cluster Sum of Squares) K-Means tanpa PCA: 89968.95
Nilai Silhouette Score K-Means sebesar 0,12 menunjukkan bahwa pemisahan klaster pada dataset ini masih tergolong rendah hingga sedang. Namun, skor ini masih cukup untuk menunjukkan adanya pola pengelompokan. Nilai WSS sebesar 89.968,95 mengindikasikan tingkat kepadatan klaster, di mana semakin kecil nilai WSS semakin rapat data dalam klaster terhadap centroidnya.
## PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10
## 0.10366 0.20654 0.27089 0.33078 0.38998 0.44797 0.50503 0.56139 0.61739 0.67246
## PC11 PC12 PC13 PC14 PC15 PC16 PC17 PC18
## 0.72705 0.78132 0.83493 0.88817 0.94046 0.99219 1.00000 1.00000
# Hitung variansi kumulatif
cum_var <- summary(pca_res)$importance[3, ]
n_components <- which(cum_var >= 0.8)[1]
pca_data <- as.data.frame(pca_res$x[, 1:3])Hasil visualisasi scree plot menunjukkan bahwa komponen utama pertama (PC1) hingga komponen kedua (PC2) menyumbang proporsi variansi yang cukup besar dibandingkan komponen-komponen berikutnya. Grafik memperlihatkan pola “elbow” yang menandakan penurunan signifikan dalam kontribusi variansi setelah beberapa komponen awal.
Namun demikian, dalam konteks klasterisasi, tujuan utama bukan hanya mempertahankan sebanyak mungkin variansi data, melainkan merepresentasikan struktur spasial data secara optimal agar klaster yang terbentuk lebih kompak dan terpisah dengan jelas. Perlu dipahami bahwa variansi yang tinggi belum tentu relevan dalam proses klasterisasi apabila informasi yang dikandung tidak berkontribusi terhadap pemisahan jarak antar titik data.
Oleh karena itu, pemilihan jumlah komponen utama tidak semata-mata didasarkan pada nilai variansi kumulatif, melainkan juga mempertimbangkan kualitas hasil klasterisasi—misalnya melalui nilai Silhouette Score. Berdasarkan pertimbangan tersebut, tiga komponen utama pertama dipilih untuk digunakan dalam proses klasterisasi.
set.seed(123)
kmeans_pca <- kmeans(pca_data, centers = 3, nstart = 25)
fviz_cluster(list(data = pca_data, cluster = kmeans_pca$cluster),
main = "K-Means Clustering dengan PCA")silhouette_kmeans_pca <- silhouette(kmeans_pca$cluster, dist(pca_data))
silhouette_score_kmeans_pca <- mean(silhouette_kmeans_pca[, 3])
wss_kmeans_pca <- kmeans_pca$tot.withinss
cat("Silhouette Score (Dengan PCA):", silhouette_score_kmeans_pca, "\n")## Silhouette Score (Dengan PCA): 0.5484953
## WSS (Dengan PCA): 11596.8
Setelah data direduksi dimensinya menggunakan PCA menjadi 3 komponen utama, selanjutnya dilakukan klasterisasi menggunakan K-Means.
Hasil visualisasi klaster menunjukkan adanya tiga klaster utama yang terbentuk, yaitu:
Cluster 1 warna merah
Cluster 2 warna hijau
Cluster 3 warna biru
Dengan silhouette score 0.548 dan WSS 11596.8, pengelompokan klaster lebih terlihat terpisah meski antar klaster masih nampak tumpang tindih.
wss_df <- data.frame(
Metode = c("Tanpa PCA", "Dengan PCA"),
WSS = c(wss_kmeans, wss_kmeans_pca)
)
ggplot(wss_df, aes(x = Metode, y = WSS, fill = Metode)) +
geom_bar(stat = "identity", width = 0.4) +
ggtitle("Perbandingan WSS") +
theme_minimal()silhouette_df <- data.frame(
Metode = c("Tanpa PCA", "Dengan PCA"),
Silhouette = c(silhouette_score_kmeans, silhouette_score_kmeans_pca)
)
ggplot(silhouette_df, aes(x = Metode, y = Silhouette, fill = Metode)) +
geom_bar(stat = "identity", width = 0.4) +
ggtitle("Perbandingan Silhouette Score") +
theme_minimal()## cluster size ave.sil.width
## 1 1 476 0.22
## 2 2 2786 0.11
## 3 3 2738 0.12
Hasil clustering menggunakan K-Means tanpa PCA menghasilkan tiga klaster
dengan ukuran yang kurang seimbang. Klaster 1 terdiri dari 476 data
dengan rata-rata nilai silhouette tertinggi sebesar 0,22, sedangkan
klaster 2 dan klaster 3 masing-masing beranggotakan 2.786 dan 2.738
data, dengan rata-rata silhouette yang lebih rendah, yaitu 0,11 dan
0,12.
Plot silhouette menunjukkan bahwa sebagian besar data memiliki nilai positif, namun relatif rendah, yang mengindikasikan bahwa pemisahan antar klaster masih bersifat moderat. Beberapa data berada di dekat batas antar klaster, sehingga meningkatkan potensi tumpang tindih. Klaster 1 menunjukkan kualitas pemisahan terbaik di antara ketiganya, sedangkan klaster 2 dan 3 menunjukkan pemisahan yang kurang tajam.
Secara keseluruhan, segmentasi menggunakan K-Means tanpa PCA memberikan hasil yang cukup baik, namun masih terdapat ruang untuk perbaikan terutama dalam meningkatkan pemisahan antar klaster.
## cluster size ave.sil.width
## 1 1 2738 0.54
## 2 2 2786 0.54
## 3 3 476 0.65
Hasil clustering K-Means dengan PCA menunjukkan tiga klaster dengan
ukuran yang relatif seimbang, yaitu klaster 1 sebanyak 2.738 data,
klaster 2 sebanyak 2.786 data, dan klaster 3 berisi 476 data. Rata-rata
nilai silhouette pada ketiga klaster tergolong tinggi, yaitu
masing-masing sebesar 0,54 untuk klaster 1 dan 2, serta 0,65 untuk
klaster 3, yang merupakan nilai tertinggi.
Plot silhouette memperlihatkan bahwa mayoritas data memiliki nilai positif dan cukup tinggi, menandakan pemisahan klaster yang baik dan kohesi internal yang kuat. Klaster 3, meskipun berukuran paling kecil, menunjukkan kualitas pemisahan terbaik. Sementara itu, klaster 1 dan 2 yang berukuran lebih besar juga menunjukkan stabilitas klaster yang baik dengan nilai silhouette yang konsisten.
Secara keseluruhan, penerapan PCA sebelum K-Means berhasil meningkatkan kualitas segmentasi, menghasilkan klaster yang lebih kompak, terpisah dengan jelas, dan berukuran seimbang dibandingkan dengan K-Means tanpa PCA.