# Load pustaka
library(datasets)
library(dbscan)
## 
## Attaching package: 'dbscan'
## The following object is masked from 'package:stats':
## 
##     as.dendrogram
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.3
library(gridExtra)

# Load dataset Iris
data(iris)
X <- iris[, 1:4] # Mengambil fitur
y <- iris[, 5] # Mengambil label asli

# Standardisasi data
X_scaled <- scale(X)
# Load pustaka
library(cluster)
## Warning: package 'cluster' was built under R version 4.3.3
# Fungsi untuk menghitung silhouette score
silhouette_score <- function(dbscan_result, data) {
  clusters <- dbscan_result$cluster
  if (length(unique(clusters)) > 1 && sum(clusters == 0) < length(clusters)) {
    silhouette <- silhouette(clusters, dist(data))
    mean(silhouette[, 3])
  } else {
    return(NA)
  }
}

# Inisialisasi parameter pencarian
eps_values <- seq(0.2, 1, by = 0.1)
minPts_values <- seq(3, 10, by = 1)
results <- data.frame(eps = numeric(), minPts = numeric(), silhouette = numeric())

# Loop untuk mencari kombinasi parameter terbaik
for (eps in eps_values) {
  for (minPts in minPts_values) {
    dbscan_result <- dbscan(X_scaled, eps = eps, minPts = minPts)
    sil_score <- silhouette_score(dbscan_result, X_scaled)
    results <- rbind(results, data.frame(eps = eps, minPts = minPts, silhouette = sil_score))
  }
}

# Menampilkan hasil silhouette score
print(results)
##    eps minPts   silhouette
## 1  0.2      3  0.087058413
## 2  0.2      4  0.025145892
## 3  0.2      5           NA
## 4  0.2      6           NA
## 5  0.2      7           NA
## 6  0.2      8           NA
## 7  0.2      9           NA
## 8  0.2     10           NA
## 9  0.3      3 -0.147299869
## 10 0.3      4 -0.207346074
## 11 0.3      5 -0.194194769
## 12 0.3      6  0.175097595
## 13 0.3      7  0.175097595
## 14 0.3      8  0.156581806
## 15 0.3      9  0.098470512
## 16 0.3     10           NA
## 17 0.4      3  0.151250886
## 18 0.4      4  0.081946150
## 19 0.4      5  0.027670002
## 20 0.4      6 -0.066223814
## 21 0.4      7 -0.151644657
## 22 0.4      8  0.296706349
## 23 0.4      9  0.288235750
## 24 0.4     10  0.288235750
## 25 0.5      3  0.159710369
## 26 0.5      4  0.364574357
## 27 0.5      5  0.356516481
## 28 0.5      6  0.195866593
## 29 0.5      7  0.139148314
## 30 0.5      8  0.188217431
## 31 0.5      9  0.069320899
## 32 0.5     10  0.009426257
## 33 0.6      3  0.348775735
## 34 0.6      4  0.434179122
## 35 0.6      5  0.402761747
## 36 0.6      6  0.398923970
## 37 0.6      7  0.364780124
## 38 0.6      8  0.364780124
## 39 0.6      9  0.352111281
## 40 0.6     10  0.345153069
## 41 0.7      3  0.508066852
## 42 0.7      4  0.508066852
## 43 0.7      5  0.523400849
## 44 0.7      6  0.487722868
## 45 0.7      7  0.463133538
## 46 0.7      8  0.454889013
## 47 0.7      9  0.422944743
## 48 0.7     10  0.422944743
## 49 0.8      3  0.521696505
## 50 0.8      4  0.521696505
## 51 0.8      5  0.521696505
## 52 0.8      6  0.521696505
## 53 0.8      7  0.522574267
## 54 0.8      8  0.510808481
## 55 0.8      9  0.510808481
## 56 0.8     10  0.510808481
## 57 0.9      3  0.521696505
## 58 0.9      4  0.521696505
## 59 0.9      5  0.521696505
## 60 0.9      6  0.521696505
## 61 0.9      7  0.522457300
## 62 0.9      8  0.522574267
## 63 0.9      9  0.522574267
## 64 0.9     10  0.510808481
## 65 1.0      3  0.504645611
## 66 1.0      4  0.538288431
## 67 1.0      5  0.538288431
## 68 1.0      6  0.538288431
## 69 1.0      7  0.538288431
## 70 1.0      8  0.538288431
## 71 1.0      9  0.538288431
## 72 1.0     10  0.538288431
# Menemukan nilai terbaik
best_index <- which.max(results$silhouette)
best_eps <- results$eps[best_index]
best_minPts <- results$minPts[best_index]
best_silhouette <- results$silhouette[best_index]

cat("Best eps:", best_eps, "\n")
## Best eps: 1
cat("Best minPts:", best_minPts, "\n")
## Best minPts: 4
cat("Best silhouette score:", best_silhouette, "\n")
## Best silhouette score: 0.5382884
# Visualisasi silhouette scores
ggplot(results, aes(x = eps, y = minPts, fill = silhouette)) + 
  geom_tile() + 
  scale_fill_gradient(low = "blue", high = "red") + 
  labs(title = "Silhouette Scores for DBSCAN Parameters", x = "eps", y = "minPts") + 
  theme_minimal()

# Menggunakan parameter terbaik untuk clustering
best_dbscan_result <- dbscan(X_scaled, eps = 1, minPts = 4)

# Menambahkan hasil cluster ke data frame
iris_clustered <- cbind(iris, cluster = best_dbscan_result$cluster)

# Menemukan jumlah cluster (tidak termasuk noise, cluster = 0)
num_clusters <- length(unique(best_dbscan_result$cluster)) - (if (0 %in% best_dbscan_result$cluster) 1 else 0)

# Menampilkan jumlah cluster
cat("Number of clusters (excluding noise):", num_clusters, "\n")
## Number of clusters (excluding noise): 2

Interpretasi :

Diperoleh hasil clustering dengan DBSCAN menggunakan parameter eps = 1 dan minPts = 4 menunjukkan dua cluster utama dalam dataset Iris. Cluster pertama terdiri dari 49 titik, sedangkan cluster kedua terdiri dari 98 titik, dengan 3 titik lainnya dianggap sebagai noise. Dalam konteks dataset Iris yang memiliki tiga kelas (setosa, versicolor, dan virginica), dua cluster ini mungkin menunjukkan bahwa dua kelas tersebut lebih dekat satu sama lain dalam ruang fitur yang digunakan. Jumlah noise yang sedikit menunjukkan bahwa sebagian besar data berhasil dikelompokkan dengan baik. Distribusi titik yang signifikan dalam kedua cluster ini mencerminkan struktur alami data.

# Menerapkan DBSCAN dengan parameter terbaik
final_dbscan <- dbscan(X_scaled, eps = 1, minPts = 4)

# Menambah label hasil clustering ke dataset Iris
iris$Cluster <- as.factor(final_dbscan$cluster)

# Visualisasi hasil clustering pada Sepal
plot1 <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Cluster)) + 
  geom_point(size = 1.5) + 
  ggtitle("Clustering DBSCAN pada Iris Data (Sepal)") +
  theme(plot.title = element_text(size = 10))

# Visualisasi hasil clustering pada Petal
plot2 <- ggplot(iris, aes(Petal.Length, Petal.Width, color = Cluster)) + 
  geom_point(size = 1.5) + 
  ggtitle("Clustering DBSCAN pada Iris Data (Petal)") +
  theme(plot.title = element_text(size = 10))

# Visualisasi hasil clustering pada Sepal.Length dan Petal.Length
plot3 <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Cluster)) + 
  geom_point(size = 1.5) + 
  ggtitle("Clustering DBSCAN pada Iris Data (Sepal.Length vs Petal.Length)") +
  theme(plot.title = element_text(size = 8))

# Visualisasi hasil clustering pada Sepal.Width dan Petal.Width
plot4 <- ggplot(iris, aes(Sepal.Width, Petal.Width, color = Cluster)) + 
  geom_point(size = 1.5) + 
  ggtitle("Clustering DBSCAN pada Iris Data (Sepal.Width vs Petal.Width)") +
  theme(plot.title = element_text(size = 8))

# Menampilkan visualisasi secara berdampingan
grid.arrange(plot1, plot2, plot3, plot4, ncol = 2)

# Visualisasi menggunakan semua fitur
pairs(X_scaled, col = final_dbscan$cluster + 1,
      main = "DBSCAN Clustering with eps = 1 and minPts = 4")

Interpretasi :

Hasil visualisasi menunjukkan bahwa algoritma DBSCAN berhasil memisahkan ketiga kelas Iris dengan baik. Algoritma ini menghasilkan cluster yang berbeda berdasarkan atribut panjang sepal, panjang kelopak, lebar sepal, dan lebar kelopak. Jumlah cluster dalam setiap cluster meningkat seiring dengan meningkatnya jumlah cluster maksimum yang telah didapatkan. Pada plot visualisasi pairwise scatter plots, titik berwarna hijau dan merah mewakili dua cluster yang berbeda yang ditemukan oleh DBSCAN. Titik berwarna hitam adalah noise atau titik yang tidak termasuk dalam cluster manapun. Cluster hijau cenderung memiliki nilai Petal.Length dan Petal.Width yang lebih tinggi, sedangkan cluster merah cenderung memiliki nilai yang lebih rendah untuk fitur-fitur tersebut. Sebaliknya, Sepal.Width lebih bervariasi dalam kedua cluster, namun tetap ada pola pengelompokan yang terlihat. Secara keseluruhan, visualisasi ini menunjukkan bahwa DBSCAN dapat mengidentifikasi dua cluster utama dalam dataset ini, dengan beberapa titik yang tidak termasuk dalam cluster manapun (noise).