library(cluster)
library(factoextra)
library(clusterCrit)
library(dplyr)
library(ggplot2)
library(tidyr)
library(scales)
library(readxl)
library(RColorBrewer)
data_air = read_excel("C:\\Users\\mhdha\\Downloads\\air+quality\\AirQualityUCI.xlsx")
data_air
## # A tibble: 465 × 4
## `CO(GT)` `NOx(GT)` T RH
## <dbl> <dbl> <dbl> <dbl>
## 1 1.2 62 11.3 56.8
## 2 1 62 10.7 60
## 3 0.9 45 10.7 59.7
## 4 0.7 16 11.0 56.2
## 5 0.7 34 10.5 58.1
## 6 1.1 98 10.2 59.6
## 7 2 174 10.8 57.4
## 8 2.2 129 10.5 60.6
## 9 1.7 112 10.8 58.4
## 10 1.5 95 10.5 57.9
## # ℹ 455 more rows
data_air_scaled <- scale(data_air)
head(data_air_scaled)
## CO(GT) NOx(GT) T RH
## [1,] -0.8540407 -1.0312693 -0.7463001 0.5229217
## [2,] -1.0018096 -1.0312693 -0.8910016 0.7471800
## [3,] -1.0756940 -1.2375754 -0.8965670 0.7245803
## [4,] -1.2234629 -1.5895092 -0.8186508 0.4811992
## [5,] -1.2234629 -1.3710675 -0.9410905 0.6167973
## [6,] -0.9279251 -0.5943859 -0.9967450 0.7193650
Menentukan jumlah cluster terbaik (k) dapat menggunakan dua metode populer:
Elbow Method: melihat titik siku (elbow point) pada grafik within-cluster sum of squares (WSS). Silhouette Method: menilai kualitas pemisahan cluster; semakin tinggi nilai silhouette, semakin baik hasil clustering.
fviz_nbclust(data_air_scaled, kmeans, method = "wss") +
labs(title = "Elbow Method")
fviz_nbclust(data_air_scaled, kmeans, method = "silhouette") +
labs(title = "Silhouette Method")
Setelah melihat dari pola menggunakan Elbow Method dan Silhoutte,
diperoleh pengelompokan yang terbaik itu 3. Selabjutnya dilakukan proses
clustering menggunakan fungsi kmeans().
Parameter nstart = 465 digunakan untuk memastikan
stabilitas hasil dengan mencoba 465 inisialisasi acak.
set.seed(1012)
kmeans_air_result <- kmeans(data_air_scaled, centers = 3, nstart = 465)
kmeans_air_result
## K-means clustering with 3 clusters of sizes 223, 117, 125
##
## Cluster means:
## CO(GT) NOx(GT) T RH
## 1 -0.66121221 -0.63922794 -0.6335353 0.6133178
## 2 1.29113433 1.30427293 -0.0093941 0.1269247
## 3 -0.02889915 -0.08041682 1.1390199 -1.2129605
##
## Clustering vector:
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 1 1 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3
## [38] 2 2 2 2 2 2 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1
## [75] 3 3 3 3 3 3 3 3 2 2 2 1 1 1 1 1 1 1 1 2 2 2 2 3 3 3 3 3 3 2 2 2 2 2 1 1 1
## [112] 1 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 2 3 1 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3 3 3
## [149] 2 2 2 3 2 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3 3 3 2 2 2 1 1 1 1 1 1 1 1 2 2 2 2
## [186] 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 2 2 3 3 3 3 3 3 2 2 2 1 1 2 1 1
## [223] 1 1 1 1 1 1 3 3 3 3 3 3 3 2 2 2 2 1 1 1 1 1 1 1 1 2 2 3 3 3 3 3 3 3 3 2 2
## [260] 2 2 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 2 2 2 1 3
## [297] 3 3 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 3 3 3 3 2 2 1 1 1 1 1 1 1
## [334] 1 1 1 2 2 2 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 2
## [371] 2 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 2 1 3
## [408] 3 3 3 3 3 3 3 3 3 1 1 3 1 3 1 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1
## [445] 1 1 1 1 2 2 1 1 1 2 1 1 2 1 1 1 1 1 1 1 1
##
## Within cluster sum of squares by cluster:
## [1] 286.9539 282.3682 181.7110
## (between_SS / total_SS = 59.5 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
table(kmeans_air_result$cluster)
##
## 1 2 3
## 223 117 125
Terdapat 223 amatan yang termasuk ke dalam clustering 1, 117 amatan ke dalam clusterinf 2, 125 amatan ke dalam clustering 3
head(data.frame(Observasi = 1:length(kmeans_air_result$cluster),
Cluster = kmeans_air_result$cluster),10)
## Observasi Cluster
## 1 1 1
## 2 2 1
## 3 3 1
## 4 4 1
## 5 5 1
## 6 6 1
## 7 7 1
## 8 8 1
## 9 9 1
## 10 10 1
Fungsi kmeans() menghasilkan sejumlah komponen penting
untuk memahami hasil pengelompokan:
| Komponen | Penjelasan |
|---|---|
cluster |
Label cluster untuk setiap observasi |
centers |
Koordinat pusat (centroid) tiap cluster |
totss |
Total variasi data (Total Sum of Squares) |
withinss |
Variasi dalam masing-masing cluster |
tot.withinss |
Jumlah keseluruhan variasi dalam cluster |
betweenss |
Variasi antar cluster |
size |
Jumlah anggota setiap cluster |
iter |
Jumlah iterasi hingga konvergen |
ifault |
Status hasil (0 = sukses) |
names(kmeans_air_result)
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
kmeans_air_result$cluster
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 1 1 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3
## [38] 2 2 2 2 2 2 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1
## [75] 3 3 3 3 3 3 3 3 2 2 2 1 1 1 1 1 1 1 1 2 2 2 2 3 3 3 3 3 3 2 2 2 2 2 1 1 1
## [112] 1 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 2 3 1 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3 3 3
## [149] 2 2 2 3 2 1 1 1 1 1 1 2 2 2 3 3 3 3 3 3 3 3 2 2 2 1 1 1 1 1 1 1 1 2 2 2 2
## [186] 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 2 2 3 3 3 3 3 3 2 2 2 1 1 2 1 1
## [223] 1 1 1 1 1 1 3 3 3 3 3 3 3 2 2 2 2 1 1 1 1 1 1 1 1 2 2 3 3 3 3 3 3 3 3 2 2
## [260] 2 2 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 2 2 2 1 3
## [297] 3 3 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 3 3 3 3 2 2 1 1 1 1 1 1 1
## [334] 1 1 1 2 2 2 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 2
## [371] 2 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 2 1 3
## [408] 3 3 3 3 3 3 3 3 3 1 1 3 1 3 1 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1
## [445] 1 1 1 1 2 2 1 1 1 2 1 1 2 1 1 1 1 1 1 1 1
kmeans_air_result$totss
## [1] 1856
kmeans_air_result$withinss
## [1] 286.9539 282.3682 181.7110
kmeans_air_result$tot.withinss
## [1] 751.0332
kmeans_air_result$betweenss
## [1] 1104.967
kmeans_air_result$iter
## [1] 3
cluster_km_air <- kmeans_air_result$cluster
dist_matrix_air <- dist(data_air_scaled, method = "euclidean")
sil <- mean(silhouette(cluster_km_air, dist_matrix_air)[, 3])
ch <- intCriteria(traj = as.matrix(data_air_scaled),
part = cluster_km_air,
crit = "Calinski_Harabasz")$calinski_harabasz
dunn <- intCriteria(traj = as.matrix(data_air_scaled),
part = cluster_km_air,
crit = "Dunn")$dunn
data.frame(Silhouette = sil,
Calinski_Harabasz = ch,
Dunn = dunn)
## Silhouette Calinski_Harabasz Dunn
## 1 0.3937749 339.8616 0.03212287
data_air_clustered <- data.frame(data_air, cluster = factor(cluster_km_air))
cluster_air_summary <- data_air_clustered %>%
group_by(cluster) %>%
summarise(across(where(is.numeric), mean, .names = "{.col}"))
cluster_air_summary
## # A tibble: 3 × 5
## cluster CO.GT. NOx.GT. T RH
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 1 1.46 94.3 11.8 58.1
## 2 2 4.10 254. 14.6 51.1
## 3 3 2.32 140. 19.8 31.8
fviz_cluster(kmeans_air_result, data= data_air_scaled,
palette = "jco", geom = "point",
main = "Visualisasi Hasil K-Means Clustering (3 Cluster)")
heat_data_air <- cluster_air_summary %>%
pivot_longer(-cluster, names_to = "Variabel", values_to = "Rata2")
heat_data_air
## # A tibble: 12 × 3
## cluster Variabel Rata2
## <fct> <chr> <dbl>
## 1 1 CO.GT. 1.46
## 2 1 NOx.GT. 94.3
## 3 1 T 11.8
## 4 1 RH 58.1
## 5 2 CO.GT. 4.10
## 6 2 NOx.GT. 254.
## 7 2 T 14.6
## 8 2 RH 51.1
## 9 3 CO.GT. 2.32
## 10 3 NOx.GT. 140.
## 11 3 T 19.8
## 12 3 RH 31.8
Berdasarkan hasil clustering dan visualisasi yang kita peroleh, Clustering 1 (Biru) Memiliki kualitas udara yang cukup baik, dimana CO dan NOx nya realtif rendah. Selain itu memiliki suhu rendah-sedang dan kelembapan yang tinggi. CLustering ini bisa menggambarkan kondisi udara bersih dengan kelembapan yang tinggi Clustering 2 (Kuning) Memiliki kualitas udara yang buruk, dimana CO dan NOx paling tinggi dibandingkan yang lainnya. Suhu sedikit lebih hangat dengan kelembapan lebih rendah. CLustering ini menunjukkan kondisi udara tercemar karena memiliki polusi yang tinggi dengan suhu yang cukup hangat Clustering 3 (Abu-abu) Memiliki kualitas udara cukup buruk, dimana CO dan NOx relatif menengah. Memiliki suhu yang tinggi dan kelembapan yang rendah. Clustering ini menggambarkan kondisi udara sedang hingga hangat dengan kelembapan rendah dan polusi sedang
ggplot(heat_data_air, aes(x = Variabel, y = cluster, fill = Rata2)) +
geom_tile(color = "white") +
scale_fill_gradientn(colors = c("#56B1F7", "white", "#FF6B6B")) +
labs(title = "Heatmap Karakteristik Cluster",
x = "Variabel", y = "Cluster") +
theme_minimal(base_size = 12) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Berdasarkan heatmap karakteristik cluster, terlihat bahwa Cluster 2
memiliki nilai NOx(GT) tertinggi, menandakan adanya tingkat polusi udara
yang lebih tinggi dibandingkan dua cluster lainnya. Sementara itu,
Cluster 1 menunjukkan nilai rata-rata terendah pada seluruh variabel,
yang menggambarkan kondisi udara bersih dan stabil. Adapun Cluster 3
berada di posisi menengah, dengan nilai NOx(GT) sedikit lebih tinggi
daripada Cluster 1, menandakan kondisi udara sedang. Secara keseluruhan,
hasil ini konsisten dengan temuan pada tabel rata-rata dan visualisasi
K-Means sebelumnya.
ggplot(heat_data_air, aes(x = Variabel, y = Rata2, fill = cluster)) +
geom_bar(stat = "identity", position = "dodge") +
scale_fill_brewer(palette = "Set2") +
labs(title = "Heatmap Karakteristik Cluster",
x = "Variabel", y = "Rata-rata Nilai") +
theme_minimal(base_size = 12) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Grafik tersebut memperlihatkan perbandingan rata-rata nilai variabel CO(GT), NOx(GT), RH, dan T untuk masing-masing cluster hasil K-Means Clustering. Warna hijau, oranye, dan ungu mewakili Cluster 1, Cluster 2, dan Cluster 3 secara berurutan. Dari grafik terlihat bahwa variabel NOx(GT) memiliki perbedaan paling mencolok antar cluster.
Cluster 2 (warna oranye) menunjukkan rata-rata NOx(GT) yang paling tinggi, mencapai nilai di atas 250. Hal ini menunjukkan bahwa cluster ini merupakan kelompok dengan tingkat polusi tertinggi, didominasi oleh emisi nitrogen oksida.
Cluster 1 (hijau) memiliki nilai NOx(GT) sedang, sedangkan Cluster 3 (ungu) lebih rendah dari Cluster 2 namun masih lebih tinggi dibanding Cluster 1. Ini menandakan bahwa Cluster 1 memiliki kualitas udara terbaik, sedangkan Cluster 3 berada di tingkat menengah.
Untuk variabel CO(GT), perbedaan antar cluster tidak terlalu besar, namun Cluster 2 tetap menunjukkan nilai tertinggi, konsisten dengan karakteristik udara tercemar.
Sementara itu, untuk variabel RH (kelembapan), Cluster 1 memiliki nilai tertinggi, diikuti oleh Cluster 2 dan kemudian Cluster 3. Artinya, udara pada Cluster 1 cenderung lebih lembap, sedangkan Cluster 3 paling kering.
Pada variabel T (suhu), pola yang muncul adalah Cluster 3 memiliki suhu tertinggi, disusul Cluster 2 dan kemudian Cluster 1. Kondisi ini mengindikasikan bahwa Cluster 3 mewakili lingkungan yang panas dan kering, sedangkan Cluster 1 lebih sejuk dan lembap.