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
Memilih 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), 3000)
df_sample <- df_scaled[index, ]
label_sample <- label[index]
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 # Silhoutte Digunakan untuk mengukur seberapa baik
suatu data cocok dengan cluster-nya dibandingkan dengan cluster
lain.
mean(silhouette(km$cluster, dist(df_sample))[,3])
## [1] 0.3084682
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.01656521
ARI digunakan untuk membandingkan hasil clustering dengan label asli (Revenue) untuk melihat seberapa sesuai hasil pengelompokan.
adjustedRandIndex(km$cluster, label_sample)
## [1] 0.03169522