Load Library

library(cluster)
library(mclust)
## Package 'mclust' version 6.1.2
## Type 'citation("mclust")' for citing this R package in publications.
library(ggplot2)

Input Data

# Input data
(data <- data.frame(
  X1 = c(11,6,9,3,4,15,9,13,4,13),
  X2 = c(5,3,7,7,12,8,12,9,11,7),
  X3 = c(7,11,11,7,7,4,12,11,14,3),
  X4 = c(6,5,8,12,12,8,6,14,6,12)
))
##    X1 X2 X3 X4
## 1  11  5  7  6
## 2   6  3 11  5
## 3   9  7 11  8
## 4   3  7  7 12
## 5   4 12  7 12
## 6  15  8  4  8
## 7   9 12 12  6
## 8  13  9 11 14
## 9   4 11 14  6
## 10 13  7  3 12

Data Scaling

# Data Scaling
(data_sc <- as.data.frame(scale(data)))
##             X1          X2         X3         X4
## 1   0.53538263 -1.04699461 -0.4692942 -0.8838069
## 2  -0.62849265 -1.72247501  0.6349275 -1.1885678
## 3   0.06983252 -0.37151422  0.6349275 -0.2742849
## 4  -1.32681782 -0.37151422 -0.4692942  0.9447590
## 5  -1.09404276  1.31718677 -0.4692942  0.9447590
## 6   1.46648285 -0.03377402 -1.2974606 -0.2742849
## 7   0.06983252  1.31718677  0.9109829 -0.8838069
## 8   1.00093274  0.30396618  0.6349275  1.5542810
## 9  -1.09404276  0.97944657  1.4630938 -0.8838069
## 10  1.00093274 -0.37151422 -1.5735160  0.9447590

DBSCAN

Non-Scaling

# DBSCAN
# Non-Scaling
library(dbscan)
## Warning: package 'dbscan' was built under R version 4.4.3
## 
## Attaching package: 'dbscan'
## The following object is masked from 'package:stats':
## 
##     as.dendrogram
kNNdistplot(data, k = 3)

(dbclust <- dbscan(data, eps = 5, minPts = 2))
## DBSCAN clustering for 10 objects.
## Parameters: eps = 5, minPts = 2
## Using euclidean distances and borderpoints = TRUE
## The clustering contains 1 cluster(s) and 8 noise points.
## 
## 0 1 
## 8 2 
## 
## Available fields: cluster, eps, minPts, metric, borderPoints
dbclust$cluster
##  [1] 0 0 0 0 0 1 0 0 0 1
result_db <- data.frame(data)
result_db$cluster <- dbclust$cluster
result_db$cluster <- as.factor(result_db$cluster)
result_db
##    X1 X2 X3 X4 cluster
## 1  11  5  7  6       0
## 2   6  3 11  5       0
## 3   9  7 11  8       0
## 4   3  7  7 12       0
## 5   4 12  7 12       0
## 6  15  8  4  8       1
## 7   9 12 12  6       0
## 8  13  9 11 14       0
## 9   4 11 14  6       0
## 10 13  7  3 12       1
# visualisasi 
ggplot(result_db,
       aes(x = X1,
           y = X2,
           color = cluster)) +
  geom_point(size = 4) +
  ggtitle("DBSCAN Clustering") +
  theme_minimal()

  • terbentuk 1 cluster

  • terdapat 8 data noise/outlier (0)

Pada data tanpa scaling, variabel masih memiliki skala asli sehingga jarak Euclidean dipengaruhi oleh variabel dengan nilai lebih besar. Akibatnya, sebagian besar data memiliki jarak yang cukup jauh satu sama lain sehingga DBSCAN sulit membentuk kelompok padat.

Hasil menunjukkan bahwa hanya observasi ke-6 dan ke-10 yang cukup dekat untuk membentuk satu cluster, sedangkan delapan observasi lainnya dikategorikan sebagai noise/outlier.

Scaling

# Scaling
kNNdistplot(data_sc, k = 3)

(db_clustsc <- dbscan(data_sc, eps = 1.5, minPts = 2))
## DBSCAN clustering for 10 objects.
## Parameters: eps = 1.5, minPts = 2
## Using euclidean distances and borderpoints = TRUE
## The clustering contains 2 cluster(s) and 6 noise points.
## 
## 0 1 2 
## 6 2 2 
## 
## Available fields: cluster, eps, minPts, metric, borderPoints
db_clustsc$cluster
##  [1] 0 0 0 0 0 1 2 0 2 1
result_dbsc <- data.frame(data_sc)
result_dbsc$cluster <- db_clustsc$cluster
result_dbsc$cluster <- as.factor(result_dbsc$cluster)
result_dbsc
##             X1          X2         X3         X4 cluster
## 1   0.53538263 -1.04699461 -0.4692942 -0.8838069       0
## 2  -0.62849265 -1.72247501  0.6349275 -1.1885678       0
## 3   0.06983252 -0.37151422  0.6349275 -0.2742849       0
## 4  -1.32681782 -0.37151422 -0.4692942  0.9447590       0
## 5  -1.09404276  1.31718677 -0.4692942  0.9447590       0
## 6   1.46648285 -0.03377402 -1.2974606 -0.2742849       1
## 7   0.06983252  1.31718677  0.9109829 -0.8838069       2
## 8   1.00093274  0.30396618  0.6349275  1.5542810       0
## 9  -1.09404276  0.97944657  1.4630938 -0.8838069       2
## 10  1.00093274 -0.37151422 -1.5735160  0.9447590       1
# visualisasi 
ggplot(result_dbsc,
       aes(x = X1,
           y = X2,
           color = cluster)) +
  geom_point(size = 4) +
  ggtitle("DBSCAN Clustering (Scaling)") +
  theme_minimal()

  • terbentuk 2 cluster (1&2)

  • terdapat 6 noise (0)

Setelah dilakukan scaling, seluruh variabel memiliki skala yang sama sehingga perhitungan jarak menjadi lebih seimbang. Hal ini menyebabkan DBSCAN mampu mendeteksi lebih banyak pola kepadatan dibandingkan data non-scaling.

  • cluster pertama : observasi 6 dan 10

  • cluster kedua : observasi 7 dan 9.

Sementara itu, enam observasi lainnya masih dianggap noise karena tidak memenuhi syarat kepadatan minimum.

MODEL BASE (Gaussian Mixture Model)

Non-Scaling

# Non-Scaling
(gmm_model <- Mclust(data, G = 3))
## 'Mclust' model object: (VEI,3) 
## 
## Available components: 
##  [1] "call"           "data"           "modelName"      "n"             
##  [5] "d"              "G"              "BIC"            "loglik"        
##  [9] "df"             "bic"            "icl"            "hypvol"        
## [13] "parameters"     "z"              "classification" "uncertainty"
summary(gmm_model)
## ---------------------------------------------------- 
## Gaussian finite mixture model fitted by EM algorithm 
## ---------------------------------------------------- 
## 
## Mclust VEI (diagonal, equal shape) model with 3 components: 
## 
##  log-likelihood  n df       BIC       ICL
##       -92.53632 10 20 -231.1243 -231.3989
## 
## Clustering table:
## 1 2 3 
## 3 5 2
gmm_model$classification
##  [1] 1 1 1 2 2 2 3 2 3 2
# visualisasi
gmm_viz <- predict(gmm_model)$classification
ggplot(data = data, aes(x = X1, y = X2)) +
  geom_point(aes(col = as.factor(gmm_viz))) +
  theme_bw() + 
  labs(col = "cluster")

Model terbaik yang dipilih oleh Mclust tanpa scaling adalah model VEI dimana bentuk covariance diagonal dan shape antar cluster sama.

  • Cluster 1 → 3 observasi
  • Cluster 2 → 5 observasi
  • Cluster 3 → 2 observasi

Grafik menunjukkan bahwa data terbagi menjadi 3 kelompok berdasarkan kemiripan karakteristik antar observasi. Karena data belum distandardisasi, variabel dengan skala lebih besar memiliki pengaruh lebih dominan terhadap pembentukan cluster.

Akibatnya, pemisahan cluster lebih dipengaruhi oleh variabel tertentu yang memiliki rentang nilai lebih besar.

Scaling

# Scaling
(gmm_modelsc <- Mclust(data_sc, G = 3))
## 'Mclust' model object: (VII,3) 
## 
## Available components: 
##  [1] "call"           "data"           "modelName"      "n"             
##  [5] "d"              "G"              "BIC"            "loglik"        
##  [9] "df"             "bic"            "icl"            "hypvol"        
## [13] "parameters"     "z"              "classification" "uncertainty"
summary(gmm_modelsc)
## ---------------------------------------------------- 
## Gaussian finite mixture model fitted by EM algorithm 
## ---------------------------------------------------- 
## 
## Mclust VII (spherical, varying volume) model with 3 components: 
## 
##  log-likelihood  n df       BIC       ICL
##        -45.5799 10 17 -130.3037 -130.8176
## 
## Clustering table:
## 1 2 3 
## 3 5 2
gmm_modelsc$classification
##  [1] 1 1 1 2 2 2 3 2 3 2
# Visualisasi
gmm_vizsc <- predict(gmm_modelsc)$classification
ggplot(data = data_sc, aes(x = X1, y = X2)) +
  geom_point(aes(col = as.factor(gmm_vizsc))) +
  theme_bw() + 
  labs(col = "cluster")

Model terbaik berubah menjadi VII

Nilai BIC scaling lebih baik dibanding non-scaling karena nilainya lebih besar (lebih mendekati nol).

Hasil model based clustering pada data non-scaling dan scaling menunjukkan komposisi anggota cluster yang sama. Hal ini berarti proses scaling tidak mengubah struktur pengelompokan data. Kesamaan hasil ini menunjukkan bahwa pola data relatif stabil dan hubungan antar observasi tetap konsisten meskipun dilakukan standardisasi.

SPECTRAL

Metode spectral clustering dilakukan melalui tahapan:

  1. Membentuk similarity matrix,
  2. Melakukan eigen decomposition,
  3. Mengambil k eigenvector utama,
  4. Melakukan K-Means pada eigenvector tersebut.

Non-Scaling

# Spectral 
set.seed(123)
# Non-Scaling
# Similarity Matrix
similarity_matrix <- exp(-dist(data)^2)

# Spectral Decomposition
eigen_result <- eigen(similarity_matrix)

k <- 3

k_eigenvectors <- eigen_result$vectors[,1:k]
(km_keigenvec <- kmeans(k_eigenvectors, centers = k))
## K-means clustering with 3 clusters of sizes 2, 2, 6
## 
## Cluster means:
##            [,1]          [,2]          [,3]
## 1 -3.988606e-08 -2.520552e-21 -7.037361e-01
## 2 -7.071068e-01  1.355843e-16  3.951340e-08
## 3 -1.118308e-14 -2.357023e-01 -1.853613e-02
## 
## Clustering vector:
##  [1] 1 3 1 3 3 2 3 3 3 2
## 
## Within cluster sum of squares by cluster:
## [1] 2.115304e-05 3.091525e-15 6.740949e-01
##  (between_SS / total_SS =  71.5 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
# Visualisasi
ggplot(data = data, aes(x = X1, y = X2)) +
  geom_point(aes(col = as.factor(km_keigenvec$cluster))) +
  theme_bw() +
  labs(col = "Cluster")

  • Cluster 1 → 2 observasi
  • Cluster 2 → 2 observasi
  • Cluster 3 → 6 observasi

Nilai 71.5% menunjukkan bahwa cluster yang terbentuk cukup baik dalam memisahkan data.

Pada data non-scaling, spectral clustering menghasilkan satu cluster besar dan dua cluster kecil. Hal ini menunjukkan bahwa sebagian besar observasi memiliki kemiripan yang cukup tinggi sehingga tergabung dalam satu kelompok utama.

Karena data belum distandardisasi, pembentukan similarity matrix masih dipengaruhi oleh perbedaan skala antar variabel.

Scaling

# Scaling
# Similarity Matrix
similarity_matrixsc <- exp(-dist(data_sc)^2)

# Spectral Decomposition
eigen_resultsc <- eigen(similarity_matrixsc)

k <- 3

k_eigenvectorsc <- eigen_resultsc$vectors[,1:k]
(km_keigenvecsc <- kmeans(k_eigenvectorsc, centers = k))
## K-means clustering with 3 clusters of sizes 5, 2, 3
## 
## Cluster means:
##         [,1]       [,2]        [,3]
## 1 -0.2239956  0.1606721  0.06362491
## 2 -0.2805540 -0.5363057  0.35444753
## 3 -0.2958270 -0.1408755 -0.46054236
## 
## Clustering vector:
##  [1] 3 3 3 1 1 2 1 1 1 2
## 
## Within cluster sum of squares by cluster:
## [1] 0.596682971 0.006082274 0.054735006
##  (between_SS / total_SS =  71.2 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
# Visualisasi
ggplot(data = data_sc, aes(x = X1, y = X2)) +
  geom_point(aes(col = as.factor(km_keigenvecsc$cluster))) +
  theme_bw() +
  labs(col = "Cluster")

  • Cluster 1 → 5 observasi
  • Cluster 2 → 2 observasi
  • Cluster 3 → 3 observasi

Nilai 71.2% hampir sama dengan non-scaling, sehingga kualitas pemisahan cluster relatif setara.

Hasil scaling menghasilkan distribusi cluster yang lebih seimbang dibandingkan non-scaling. Pada non-scaling, sebagian besar observasi terkumpul dalam satu cluster besar, sedangkan scaling mampu membagi data menjadi kelompok yang lebih proporsional.

Hal ini terjadi karena scaling membuat seluruh variabel memiliki kontribusi yang sama dalam perhitungan jarak dan similarity matrix.

** X1 dan X2 digunakan pada visualisasi karena grafik scatterplot hanya dapat menampilkan dua variabel. Namun, proses clustering tetap menggunakan seluruh variabel pada data. **