Install & Load Package

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

Load Data

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 ...

Preprocessing

encoding

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)

Hapus target (Revenue)

Variabel Revenue dipisahkan sebagai label dan tidak digunakan dalam proses clustering karena metode clustering termasuk unsupervised learning.

label <- df$Revenue
df$Revenue <- NULL

Ambil fitur numerik

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

Scaling

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)

Sampling

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]

Mengecek OUtlier

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)

Menentukan Jumlah Cluster

Elbow Method

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

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

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

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

Mean Shift mencari pusat cluster secara otomatis tanpa menentukan jumlah cluster di awal.

ms <- meanShift(df_sample)

Fuzzy C-Means

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

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)

K_Means

Silhoutte

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

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

Adjusted Rand Index (ARI)

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

K-Median

Evaluasi pada metode K-Median dilakukan menggunakan tiga metrik utama, yaitu Silhouette Score, Dunn Index, dan Adjusted Rand Index (ARI).

cluster_kmed <- clusters(kmed)

Silhoutte

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

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

Adjusted Rand Index (ARI)

ARI untuk membandingkan hasil clustering dengan label asli.

ari_kmed <- adjustedRandIndex(cluster_kmed, label_sample)
ari_kmed
## [1] 0.01805934

DBSCAN

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

Mean Shift

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

Silhoutte

sil_ms <- mean(silhouette(cluster_ms, dist_matrix)[,3])
sil_ms
## [1] 0.01551995

Dunn Index

dunn_ms <- cluster.stats(dist_matrix, cluster_ms)$dunn
dunn_ms
## [1] 0.02289094

Adjusted Rand Index (ARI)

ari_ms <- adjustedRandIndex(cluster_ms, label_sample)
ari_ms
## [1] 0.06641142

Fuzzy C-Means

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

Silhoutte

sil_fcm <- mean(silhouette(cluster_fcm, dist_matrix)[,3])
sil_fcm
## [1] 0.173657

Dunn Index

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

Adjusted Rand Index (ARI)

ari_fcm <- adjustedRandIndex(cluster_fcm, label_sample)
ari_fcm
## [1] 0.06968427

Kesimpulan

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.