Pada tahap ini dilakukan instalasi dan pemanggilan beberapa package di RStudio yang digunakan untuk proses clustering, visualisasi, dan evaluasi. Package seperti tidyverse, dbscan, dan cluster membantu dalam pengolahan data serta penerapan berbagai metode clustering.
#install.packages(tidyverse) #install.packages(flexclust) # k-median #install.packages(dbscan) # dbscan #install.packages(meanShiftR) # meanshift #install.packages(e1071) # fuzzy c-means #install.packages(cluster) # shilhoutte score #install.packages(fpc) # another metrics #install.packages(mclust) # ARI metrics to compare cluster with true label
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.2.0 ✔ readr 2.2.0
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.2 ✔ tibble 3.3.1
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.2
## ✔ purrr 1.2.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(flexclust)
library(dbscan)
##
## Attaching package: 'dbscan'
##
## The following object is masked from 'package:stats':
##
## as.dendrogram
library(meanShiftR)
library(e1071)
##
## Attaching package: 'e1071'
##
## The following object is masked from 'package:flexclust':
##
## bclust
##
## The following object is masked from 'package:ggplot2':
##
## element
library(cluster)
library(fpc)
##
## Attaching package: 'fpc'
##
## The following object is masked from 'package:dbscan':
##
## dbscan
library(mclust)
## Package 'mclust' version 6.1.2
## Type 'citation("mclust")' for citing this R package in publications.
##
## Attaching package: 'mclust'
##
## The following object is masked from 'package:dplyr':
##
## count
##
## The following object is masked from 'package:purrr':
##
## map
Dataset Online Shoppers Intention dibaca ke dalam R menggunakan fungsi read.csv(). Selanjutnya dilakukan pengecekan awal menggunakan head() dan str() untuk melihat struktur data dan tipe setiap variabel.
df <- read.csv("online_shoppers_intention.csv")
head(df)
## Administrative Administrative_Duration Informational Informational_Duration
## 1 0 0 0 0
## 2 0 0 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 0 0
## ProductRelated ProductRelated_Duration BounceRates ExitRates PageValues
## 1 1 0.000000 0.20000000 0.2000000 0
## 2 2 64.000000 0.00000000 0.1000000 0
## 3 1 0.000000 0.20000000 0.2000000 0
## 4 2 2.666667 0.05000000 0.1400000 0
## 5 10 627.500000 0.02000000 0.0500000 0
## 6 19 154.216667 0.01578947 0.0245614 0
## SpecialDay Month OperatingSystems Browser Region TrafficType
## 1 0 Feb 1 1 1 1
## 2 0 Feb 2 2 1 2
## 3 0 Feb 4 1 9 3
## 4 0 Feb 3 2 2 4
## 5 0 Feb 3 3 1 4
## 6 0 Feb 2 2 1 3
## VisitorType Weekend Revenue
## 1 Returning_Visitor FALSE FALSE
## 2 Returning_Visitor FALSE FALSE
## 3 Returning_Visitor FALSE FALSE
## 4 Returning_Visitor FALSE FALSE
## 5 Returning_Visitor TRUE FALSE
## 6 Returning_Visitor FALSE FALSE
str(df)
## 'data.frame': 12330 obs. of 18 variables:
## $ Administrative : int 0 0 0 0 0 0 0 1 0 0 ...
## $ Administrative_Duration: num 0 0 0 0 0 0 0 0 0 0 ...
## $ Informational : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Informational_Duration : num 0 0 0 0 0 0 0 0 0 0 ...
## $ ProductRelated : int 1 2 1 2 10 19 1 0 2 3 ...
## $ ProductRelated_Duration: num 0 64 0 2.67 627.5 ...
## $ BounceRates : num 0.2 0 0.2 0.05 0.02 ...
## $ ExitRates : num 0.2 0.1 0.2 0.14 0.05 ...
## $ PageValues : num 0 0 0 0 0 0 0 0 0 0 ...
## $ SpecialDay : num 0 0 0 0 0 0 0.4 0 0.8 0.4 ...
## $ Month : chr "Feb" "Feb" "Feb" "Feb" ...
## $ OperatingSystems : int 1 2 4 3 3 2 2 1 2 2 ...
## $ Browser : int 1 2 1 2 3 2 4 2 2 4 ...
## $ Region : int 1 1 9 2 1 1 3 1 2 1 ...
## $ TrafficType : int 1 2 3 4 4 3 3 5 3 2 ...
## $ VisitorType : chr "Returning_Visitor" "Returning_Visitor" "Returning_Visitor" "Returning_Visitor" ...
## $ Weekend : logi FALSE FALSE FALSE FALSE TRUE FALSE ...
## $ Revenue : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
Beberapa variabel kategorikal seperti Month, VisitorType, dan Weekend diubah menjadi bentuk numerik agar dapat digunakan dalam proses clustering.
df$Month <- as.numeric(as.factor(df$Month))
df$VisitorType <- as.numeric(as.factor(df$VisitorType))
df$Weekend <- as.numeric(df$Weekend)
Variabel Revenue dipisahkan sebagai label dan tidak digunakan dalam proses clustering karena metode clustering termasuk unsupervised learning.
label <- df$Revenue
df$Revenue <- NULL
Dipilih fitur-fitur numerik yang relevan untuk digunakan dalam analisis clustering.
df_num <- df[, c(
"Administrative","Administrative_Duration",
"Informational","Informational_Duration",
"ProductRelated","ProductRelated_Duration",
"BounceRates","ExitRates","PageValues","SpecialDay",
"Month","VisitorType","Weekend"
)]
Data dinormalisasi menggunakan fungsi scale() agar semua fitur memiliki skala yang sama, sehingga perhitungan jarak antar data menjadi lebih akurat.
df_scaled <- scale(df_num)
Dilakukan pengambilan sampel sebanyak 3000 data untuk mempercepat proses komputasi tanpa mengurangi representasi data secara signifikan.
set.seed(123)
index <- sample(1:nrow(df_scaled), 1000)
df_sample <- df_scaled[index, ]
label_sample <- label[index]
Deteksi outlier dilakukan menggunakan metode Mahalanobis Distance yang mempertimbangkan hubungan antar variabel (multivariat). Setiap observasi dihitung jaraknya terhadap pusat data, kemudian dibandingkan dengan nilai threshold berdasarkan distribusi chi-square. Data yang memiliki nilai Mahalanobis Distance lebih besar dari threshold dikategorikan sebagai outlier.
df_numeric <- as.data.frame(df_sample)
center <- colMeans(df_numeric)
cov_matrix <- cov(df_numeric)
mahalanobis_dist <- mahalanobis(df_numeric, center, cov_matrix)
threshold <- qchisq(0.975, df = ncol(df_numeric))
outlier_mahalanobis <- mahalanobis_dist > threshold
cat("Jumlah Outlier:", sum(outlier_mahalanobis), "\n")
## Jumlah Outlier: 98
Boxplot digunakan untuk memvisualisasikan distribusi nilai Mahalanobis Distance secara keseluruhan. Garis vertikal berwarna merah menunjukkan batas (threshold) outlier. Data yang berada di sebelah kanan garis tersebut merupakan observasi yang terindikasi sebagai outlier.
df_numeric <- as.data.frame(df_sample)
center <- colMeans(df_numeric)
cov_matrix <- cov(df_numeric)
mahalanobis_dist <- mahalanobis(df_numeric, center, cov_matrix)
threshold <- qchisq(0.975, df = ncol(df_numeric))
boxplot(mahalanobis_dist,
horizontal = TRUE,
main = "Boxplot Mahalanobis Distance",
xlab = "Mahalanobis Distance",
col = "lightgray")
abline(v = threshold, col = "red", lwd = 2)
Metode ini digunakan untuk menentukan jumlah cluster optimal dengan melihat grafik perubahan nilai WCSS. Titik “siku” pada grafik menunjukkan jumlah cluster yang baik.
wss <- sapply(1:10, function(k){
kmeans(df_sample, centers = k, nstart = 20)$tot.withinss
})
plot(1:10, wss, type="b", pch=19,
main="Elbow Method",
xlab="Jumlah Cluster", ylab="WCSS")
Silhouette score digunakan untuk mengukur kualitas cluster. Nilai yang lebih tinggi menunjukkan bahwa cluster yang terbentuk semakin baik.
avg_sil <- function(k){
km <- kmeans(df_sample, centers = k, nstart = 25)
ss <- silhouette(km$cluster, dist(df_sample))
mean(ss[,3])
}
k_values <- 2:10
sil <- sapply(k_values, avg_sil)
plot(k_values, sil, type="b", pch=19,
main="Silhouette Score")
## Clustering # K-Means Metode K-Means digunakan untuk mengelompokkan
data berdasarkan jarak ke pusat cluster (centroid).
km <- kmeans(df_sample, centers = 3)
K-Median mirip dengan K-Means, namun menggunakan median sebagai pusat cluster sehingga lebih tahan terhadap outlier.
kmed <- kcca(df_sample, k = 3, family = kccaFamily("kmedians"))
## Found more than one class "kcca" in cache; using the first, from namespace 'flexclust'
## Also defined by 'kernlab'
## Found more than one class "kcca" in cache; using the first, from namespace 'flexclust'
## Also defined by 'kernlab'
DBSCAN mengelompokkan data berdasarkan kepadatan (density) dan mampu mendeteksi data yang dianggap sebagai noise atau outlier.
db <- dbscan::dbscan(df_sample, eps = 0.5, minPts = 5)
Mean Shift mencari pusat cluster secara otomatis tanpa menentukan jumlah cluster di awal.
ms <- meanShift(df_sample)
Fuzzy C-Means memungkinkan satu data masuk ke lebih dari satu cluster dengan tingkat keanggotaan tertentu.
fcm <- cmeans(df_sample, centers = 3, m = 2)
Visualisasi dilakukan untuk melihat hasil pengelompokan dari masing-masing metode clustering. Setiap warna menunjukkan cluster yang berbeda sehingga memudahkan dalam interpretasi hasil.
par(mfrow=c(2,3))
plot(df_sample, col=km$cluster, main="K-Means")
plot(df_sample, col=clusters(kmed), main="K-Median")
plot(df_sample, col=db$cluster+1, main="DBSCAN")
plot(df_sample, col=ms$assignment, main="Mean Shift")
plot(df_sample, col=fcm$cluster, main="Fuzzy C-Means")
plot(df_sample, col=as.numeric(label_sample), main="Original Revenue")
## Evaluasi metrix
dist_matrix <- dist(df_sample)
Digunakan untuk mengukur seberapa baik suatu data cocok dengan cluster-nya dibandingkan dengan cluster lain.
sil_mean <- mean(silhouette(km$cluster, dist(df_sample))[,3])
sil_mean
## [1] 0.1286353
Dunn Index digunakan untuk mengevaluasi kualitas cluster berdasarkan jarak antar cluster dan kepadatan dalam cluster. Nilai yang lebih tinggi menunjukkan cluster yang lebih baik.
stats <- cluster.stats(dist(df_sample), km$cluster)
stats$dunn
## [1] 0.02817072
ARI digunakan untuk membandingkan hasil clustering dengan label asli (Revenue) untuk melihat seberapa sesuai hasil pengelompokan.
ari_mean <- adjustedRandIndex(km$cluster, label_sample)
ari_mean
## [1] 0.03589561
Evaluasi pada metode K-Median dilakukan menggunakan tiga metrik utama, yaitu Silhouette Score, Dunn Index, dan Adjusted Rand Index (ARI).
cluster_kmed <- clusters(kmed)
Silhouette Score digunakan untuk mengukur seberapa baik pemisahan antar cluster
sil_kmed <- mean(silhouette(cluster_kmed, dist_matrix)[,3])
sil_kmed
## [1] 0.1529381
Dunn Index untuk melihat rasio antara jarak antar cluster dan kepadatan dalam cluster
dunn_kmed <- cluster.stats(dist_matrix, cluster_kmed)$dunn
dunn_kmed
## [1] 0.01524909
ARI untuk membandingkan hasil clustering dengan label asli.
ari_kmed <- adjustedRandIndex(cluster_kmed, label_sample)
ari_kmed
## [1] 0.01805934
Pada metode DBSCAN, data yang dianggap sebagai noise (cluster = 0) tidak disertakan dalam evaluasi. Hal ini dilakukan agar penilaian kualitas cluster lebih akurat dan tidak dipengaruhi oleh data yang tidak termasuk dalam cluster manapun.
db_cluster <- db$cluster
non_noise <- db_cluster != 0
df_db <- df_sample[non_noise, ]
db_cluster_clean <- db_cluster[non_noise]
label_db <- label_sample[non_noise]
dist_db <- dist(df_db)
if(length(unique(db_cluster_clean)) > 1){
sil_db <- mean(silhouette(db_cluster_clean, dist_db)[,3])
dunn_db <- cluster.stats(dist_db, db_cluster_clean)$dunn
ari_db <- adjustedRandIndex(db_cluster_clean, label_db)
} else {
sil_db <- NA
dunn_db <- NA
ari_db <- NA
}
sil_db
## [1] 0.4306407
dunn_db
## [1] 0.2032923
ari_db
## [1] -0.00457333
Evaluasi Mean Shift dilakukan dengan menggunakan metrik yang sama, yaitu Silhouette Score, Dunn Index, dan ARI. Metode ini secara otomatis menentukan jumlah cluster sehingga evaluasi bertujuan untuk melihat seberapa baik hasil pengelompokan yang terbentuk tanpa parameter jumlah cluster di awal.
cluster_ms <- ms$assignment
sil_ms <- mean(silhouette(cluster_ms, dist_matrix)[,3])
sil_ms
## [1] 0.01551995
dunn_ms <- cluster.stats(dist_matrix, cluster_ms)$dunn
dunn_ms
## [1] 0.02289094
ari_ms <- adjustedRandIndex(cluster_ms, label_sample)
ari_ms
## [1] 0.06641142
Pada Fuzzy C-Means, setiap data memiliki derajat keanggotaan pada setiap cluster. tetapi, untuk keperluan evaluasi, digunakan label cluster dengan nilai keanggotaan tertinggi.
cluster_fcm <- fcm$cluster
sil_fcm <- mean(silhouette(cluster_fcm, dist_matrix)[,3])
sil_fcm
## [1] 0.173657
dunn_fcm <- cluster.stats(dist_matrix, cluster_fcm)$dunn
## Warning in cluster.stats(dist_matrix, cluster_fcm): clustering renumbered
## because maximum != number of clusters
dunn_fcm
## [1] 0.01886552
ari_fcm <- adjustedRandIndex(cluster_fcm, label_sample)
ari_fcm
## [1] 0.06968427
Berdasarkan hasil perbandingan lima metode clustering yaitu K-Means, K-Median, DBSCAN, Mean Shift, dan Fuzzy C-Means, didapatkan hasil bahwa setiap metode memiliki performa yang berbeda-beda tergantung pada karakteristik data.
Metode berbasis centroid seperti K-Means dan K-Median cenderung menghasilkan cluster yang stabil, namun sensitif terhadap outlier. DBSCAN mampu mendeteksi noise dengan baik, tetapi hasilnya sangat bergantung pada parameter yang digunakan. Mean Shift memiliki keunggulan dalam menentukan jumlah cluster secara otomatis, sedangkan Fuzzy C-Means memberikan fleksibilitas dengan memungkinkan satu data berada pada beberapa cluster.
Berdasarkan metrik evaluasi yang digunakan, metode dengan nilai Silhouette Score dan Dunn Index yang lebih tinggi serta ARI yang mendekati 1 menunjukkan performa clustering yang lebih baik. Oleh karena itu, metode terbaik dipilih berdasarkan hasil evaluasi tersebut dengan mempertimbangkan keseimbangan antara pemisahan cluster dan kesesuaian dengan label asli.