Library

library(cluster)
library(factoextra)
library(clusterCrit)
library(dplyr)
library(ggplot2)
library(tidyr)
library(scales)
library(readxl)
library(RColorBrewer)

Membaca Data

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

Metode Non Hierarki

K-Means Clustering

Menentukan Jumlah Clustering yang Optimal

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")

Penerapan Algoritma K-Means

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"

Hasil Clustering

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

Komponen Hasil K-Means

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

Evaluasi Clustering

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

Karakteristik Clustering

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

Visualisasi Clustering

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.