|
K-Means clustering dengan R
|
Halo teman-teman, jumpa lagi dengan blog sederhana ini. Kemarin kita sejenak break dengan membahas one way anova, kali ini kita akan melanjutkan belajar bersama tentang salah satu algoritma machine learning dengan jenis unsupervised learning, yaitu algoritma klastering (hierarchy clustering dan kmeans clustering) karena beberapa bahasan sebelumnya kita telah membahas supervised learning. Perbedaan supervised learning dan unsupervised learning sendiri dapat teman-teman baca pada unggahan berikut.
Klastering (Clustering) merupakan salah satu algoritma yang banyak digunakan dalam unsupervised learning. Sebelum jauh pembahasannya, ada baiknya kita bahas kaitan antara K means clustering dan hierarchy clustering. Mengapa kita ulas kaitan kedua istilah ini? Karena dalam pengertiannya, kerapkali membingungkan. Lebih-lebih kalau sudah kita campuradukkan dengan konsep clustering yang menggunakan algoritma supervised learning.
Jadi begini, di alam clustering, kita akan mengenal 2 bentuk pengklasteran, yaitu hierarchy clustering dan non-hierarchy clustering. Hierarchy clustering itu intinya adalah mengelompokan data itu tidak secara bertahap dan di dalam prosesnya jumlah cluster tidak ditentukan terlebih dahulu. Berbeda dengan non-hierarchy clustering yang dalam prosesnya diawali dengan menentukan jumlah cluster terlebih dahulu dan biasanya digunakan untuk data-data yang jumlahnya besar. Posisi K-Means clustering itu merupakan salah satu algoritma pengklasteran non-hierarchy clustering. Sampai di sini semoga telah jelas perbedaannya.
Aspek lain yang membedakan hierarchy clustering dan non-hierarchy clustering adalah ada tidaknya proses operasi dan strukturisasi cluster. Dalam hierarchy clustering, kita akan mengenai 2 istilah, yaitu aglomeratif (agglomerative) dan divisif (divisive). Bedanya, kalau aglomaratif setiap amatan dipandang sebagai 1 cluster kemudian digabung menurut kemiripan (distance similarity) dengan amatan lain yang dipandang cluster sendiri, dan seterusnya hingga berhenti dan diperoleh ukuran cluster yang paling optimal. Sedangkan pada divisif, kita pandang seluruh amatan adalah satu cluster kemudian kita pecah (split) untuk mendapatkan cluster yang homogen (varians dalam cluster minimal dan antar cluster maksimal) hingga kita peroleh sejumlah cluster yang optimal. Sedangkan di dalam non-hierarcy clustering algoritma operasi dan strukturisasi tersebut diabaikan.
Berikutnya, mengapa clustering satu ini masuk ke dalam unsupervised learning? Jelas, sebagaimana ulasan sebelumnya, intinya jika data kita bukan data yang terlabelisasi atau telah ditentukan mana variabel dependen dan independennya, maka algoritma dalam pengelompokannya masuk dalam unsupervised learning.
Pada algoritma K-Means clustering sendiri, bagaimana prinsip dasar kerjanya? Setidak ada kurang lebih 3 prinsip dasarnya. Pertama, karena K-Means clustering ini masuk non-hierarchy clustering, maka kita tentukan dulu jumlah klasternya (K). Kedua, menentukan mana centroid atau titik rata-rata sementara sejumlah K cluster. Ketiga, melakukan perulangan (iterasi) penghitungan kemiripan (similarity) setiap amatan terhadap centroid, biasanya menggunakan jarak (bisa jarak Euclidean atau jarak lainnya), sampai tidak ada satupun amatan yang tidak memiliki kelompok (cluster).
Tujuan utama dari algoritma K-Means clustering ini adalah meminimalkan fungsi obyektif pengelompokan, yaitu dengan memaksimalkan varians antar cluster dan meminimalkan varians di dalam cluster.
Kelemahan dari algoritma K-Means clustering ini ada pada metodenya yang menggunakan rata-rata atau mean. Karena ukuran rata-rata ini merupakan ukuran yang tidak bersifat robust, maka algoritma K-Means clustering ini rentan dipengaruhi oleh adanya pencilan atau outlier.
Baik itu sekilas teori mengenai K-Means clustering. Berikutnya kita akan coba mempraktikkan pengklasteran menggunakan metode K-Means clustering dengan menggunakan R. Data yang kita angkat kali ini merupakan data yang saya peroleh menggunakan teknik web scraping memanfaatkan package rvest mengenai daftar Digital Monster (Digimon) menurut jenis, kekuatan, dan karakteristik lainnya. Data saya peroleh dari situs grindosaur dan bisa teman-teman unduh pada tautan berikut.
|
Tampilan situs grindosaur
|
Setelah datanya diunduh, kita dapat mempraktikkan algoritma K-Means clustering menggunakan beberapa code berikut:
#Import Dataset
library(readxl)
digimon <- read_excel("E:/R/Machine Learning/digimon.xlsx")
digimon
## # A tibble: 505 x 6
## Move spcost tipe power atribut inheritable
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Acceleration Boost 6 1 0 10 1
## 2 Adhesive Bubble Blow 2 2 25 20 0
## 3 Agility Charge 6 1 0 10 1
## 4 Aguichant Lèvres 40 3 0 30 0
## 5 Air Bubbles 2 3 30 40 0
## 6 Air Shot 5 3 50 50 0
## 7 Ambush Crunch 10 2 90 10 0
## 8 Amethyst Mandala 20 3 70 30 0
## 9 Animal Nail 15 2 115 60 0
## 10 Anti-Bug 4 1 0 10 1
## # ... with 495 more rows
#Menggunakan Variabel Numeriknya saja
dataku <- digimon[,c(2:6)]
dataku
## # A tibble: 505 x 5
## spcost tipe power atribut inheritable
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 6 1 0 10 1
## 2 2 2 25 20 0
## 3 6 1 0 10 1
## 4 40 3 0 30 0
## 5 2 3 30 40 0
## 6 5 3 50 50 0
## 7 10 2 90 10 0
## 8 20 3 70 30 0
## 9 15 2 115 60 0
## 10 4 1 0 10 1
## # ... with 495 more rows
#Melihat Struktur Data
str(dataku)
## tibble [505 x 5] (S3: tbl_df/tbl/data.frame)
## $ spcost : num [1:505] 6 2 6 40 2 5 10 20 15 4 ...
## $ tipe : num [1:505] 1 2 1 3 3 3 2 3 2 1 ...
## $ power : num [1:505] 0 25 0 0 30 50 90 70 115 0 ...
## $ atribut : num [1:505] 10 20 10 30 40 50 10 30 60 10 ...
## $ inheritable: num [1:505] 1 0 1 0 0 0 0 0 0 1 ...
#Mengattach Data
attach(dataku)
## The following objects are masked from dataku (pos = 23):
##
## atribut, inheritable, power, spcost, tipe
#Ringkasan Data
summary(dataku)
## spcost tipe power atribut inheritable
## Min. : 0.00 Min. :1.000 Min. : 0.00 Min. :10.00 Min. :0.0000
## 1st Qu.: 6.00 1st Qu.:2.000 1st Qu.: 20.00 1st Qu.:20.00 1st Qu.:0.0000
## Median :10.00 Median :2.000 Median : 65.00 Median :40.00 Median :0.0000
## Mean :14.97 Mean :2.212 Mean : 60.59 Mean :45.84 Mean :0.2733
## 3rd Qu.:20.00 3rd Qu.:3.000 3rd Qu.: 95.00 3rd Qu.:70.00 3rd Qu.:1.0000
## Max. :99.00 Max. :3.000 Max. :250.00 Max. :90.00 Max. :1.0000
#Ringkasan Data dengan fungsi Kable
library(kableExtra)
summary(dataku) %>% kable() %>% kable_styling()
|
spcost |
tipe |
power |
atribut |
inheritable |
|
Min. : 0.00 |
Min. :1.000 |
Min. : 0.00 |
Min. :10.00 |
Min. :0.0000 |
|
1st Qu.: 6.00 |
1st Qu.:2.000 |
1st Qu.: 20.00 |
1st Qu.:20.00 |
1st Qu.:0.0000 |
|
Median :10.00 |
Median :2.000 |
Median : 65.00 |
Median :40.00 |
Median :0.0000 |
|
Mean :14.97 |
Mean :2.212 |
Mean : 60.59 |
Mean :45.84 |
Mean :0.2733 |
|
3rd Qu.:20.00 |
3rd Qu.:3.000 |
3rd Qu.: 95.00 |
3rd Qu.:70.00 |
3rd Qu.:1.0000 |
|
Max. :99.00 |
Max. :3.000 |
Max. :250.00 |
Max. :90.00 |
Max. :1.0000 |
#Melihat Sebaran Data dengan Faset Histogram
library(tidyverse)
dataku %>%
gather(power, value, 1:5) %>%
ggplot(aes(x=value)) +
geom_histogram(fill = "steelblue", color = "black", bins = 30) +
facet_wrap(~power, scales = "free_x") +
labs(x = "Nilai", y = "Frekuensi")
|
Visualisasi 1
|
#Matrks Korelasi Antar Variabel
library(reshape2)
corrku <- cor(dataku)
melt_cor <- melt(corrku)
ggplot(data = melt_cor, aes(x = Var1, y = Var2, fill = value)) +
geom_tile(aes(fill = value), colour = "white") +
scale_fill_gradient(low = "white", high = "#ff8c00") +
geom_text(aes(Var1, Var2, label = round(value, 2)), size = 5)
|
Visualisasi 2
|
#Bila data Beda Satuan, perlu penskalaan data
datakuskal <- scale(dataku)
head(datakuskal, 10)
## spcost tipe power atribut inheritable
## [1,] -0.829012192 -1.9516720 -1.2925274 -1.2586863 1.6291575
## [2,] -1.198600502 -0.3412237 -0.7592543 -0.9075059 -0.6125987
## [3,] -0.829012192 -1.9516720 -1.2925274 -1.2586863 1.6291575
## [4,] 2.312488435 1.2692246 -1.2925274 -0.5563254 -0.6125987
## [5,] -1.198600502 1.2692246 -0.6525996 -0.2051450 -0.6125987
## [6,] -0.921409270 1.2692246 -0.2259811 0.1460354 -0.6125987
## [7,] -0.459423883 -0.3412237 0.6272560 -1.2586863 -0.6125987
## [8,] 0.464546890 1.2692246 0.2006374 -0.5563254 -0.6125987
## [9,] 0.002561503 -0.3412237 1.1605291 0.4972159 -0.6125987
## [10,] -1.013806347 -1.9516720 -1.2925274 -1.2586863 1.6291575
#Penentuan jumlah Klaster dengan pendekatan klaster gap untuk memperoleh K terbaik
library(cluster)
gapclust <- clusGap(datakuskal, FUN = kmeans, nstart = 30, K.max = 20, B = 10)
## Clustering k = 1,2,..., K.max (= 20): .. done
## Bootstrapping, b = 1,2,..., B (= 10) [one "." per sample]:
## .
## Warning: did not converge in 10 iterations
## .....
## Warning: did not converge in 10 iterations
## ...
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
## . 10
library(factoextra)
fviz_gap_stat(gapclust) + theme_minimal() + ggtitle("Visualisasi Statistik Gap Klaster") #diperlukan 2 Klaster
|
Visualisasi 3
|
#Penentuan K optimal dengan PCA
library(FactoMineR)
pcaku <-PCA(datakuskal, graph = F)
fviz_screeplot(pcaku, addlabels = T) #Untuk dapat menjelaskan ragam sekitar 80% diperlukan Klaster = 5
|
Visualisasi 5
|
#Penentuan K optimal dengan pendekatan Silhouette
fviz_nbclust(datakuskal, kmeans, method = "silhouette", k.max = 24) +
theme_minimal() + ggtitle("Plot Penentukan K Optimal Metode Shilhouette") #diperlukan 2 klaster
|
Visualisasi 6
|
#Penentuan K optimal dengan pendekatan NbClust
library(NbClust)
nbclust <- NbClust(datakuskal, distance = "euclidean", min.nc = 2, max.nc = 20,
method = "complete", index = "all")
|
Visualisasi 7
|
## *** : The Hubert index is a graphical method of determining the number of clusters.
## In the plot of Hubert index, we seek a significant knee that corresponds to a
## significant increase of the value of the measure i.e the significant peak in Hubert
## index second differences plot.
##
|
Visualisasi 8
|
## *** : The D index is a graphical method of determining the number of clusters.
## In the plot of D index, we seek a significant knee (the significant peak in Dindex
## second differences plot) that corresponds to a significant increase of the value of
## the measure.
##
## *******************************************************************
## * Among all indices:
## * 10 proposed 2 as the best number of clusters
## * 2 proposed 3 as the best number of clusters
## * 1 proposed 4 as the best number of clusters
## * 2 proposed 6 as the best number of clusters
## * 1 proposed 8 as the best number of clusters
## * 3 proposed 9 as the best number of clusters
## * 1 proposed 15 as the best number of clusters
## * 2 proposed 18 as the best number of clusters
## * 2 proposed 20 as the best number of clusters
##
## ***** Conclusion *****
##
## * According to the majority rule, the best number of clusters is 2
##
##
## *******************************************************************
fviz_nbclust(nbclust) + theme_minimal() + ggtitle("Plot Penentuan K Optimal \n Metode NbClust") #diperlukan 2 klaster
## Warning in if (class(best_nc) == "numeric") print(best_nc) else if (class(best_nc) == : the condition
## has length > 1 and only the first element will be used
## Warning in if (class(best_nc) == "matrix") .viz_NbClust(x, print.summary, : the condition has length > 1
## and only the first element will be used
## Warning in if (class(best_nc) == "numeric") print(best_nc) else if (class(best_nc) == : the condition
## has length > 1 and only the first element will be used
## Warning in if (class(best_nc) == "matrix") {: the condition has length > 1 and only the first element
## will be used
## Among all indices:
## ===================
## * 2 proposed 0 as the best number of clusters
## * 10 proposed 2 as the best number of clusters
## * 2 proposed 3 as the best number of clusters
## * 1 proposed 4 as the best number of clusters
## * 2 proposed 6 as the best number of clusters
## * 1 proposed 8 as the best number of clusters
## * 3 proposed 9 as the best number of clusters
## * 1 proposed 15 as the best number of clusters
## * 2 proposed 18 as the best number of clusters
## * 2 proposed 20 as the best number of clusters
##
## Conclusion
## =========================
## * According to the majority rule, the best number of clusters is 2 .
|
Visualisasi 9
|
#Penentuan K optimal dengan fungsi Clustree
library(clustree)
coba <- NULL
for (k in 1:16){
coba[k] <- kmeans(datakuskal, k, nstart = 30)
}
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
## Warning in coba[k] <- kmeans(datakuskal, k, nstart = 30): number of items to replace is not a multiple
## of replacement length
df <- data.frame(coba) #Menambahkan identitas kolom
colnames(df) <- seq(1:16)
colnames(df) <- paste0("k",colnames(df)) #PCA setiap amatan
dfpca <- prcomp(df, center = TRUE, scale. = FALSE)
inkoor <- dfpca$x
inkoor <- inkoor[,1:2]
df <- bind_cols(as.data.frame(df), as.data.frame(inkoor))
clustree(df, prefix = "k")
|
Visualisasi 10
|
#Penentuan K Optimal dengan menggabungkan beberapa metode
library(clValid)
bandingmetod <- clValid(datakuskal, nClust = 2:24, clMethods = c("hierarchical", "kmeans", "pam"),
validation = "internal")
## Warning in clValid(datakuskal, nClust = 2:24, clMethods = c("hierarchical", : rownames for data not
## specified, using 1:nrow(data)
#Ringkasan Beberapa Metode
summary(bandingmetod) %>%
kable() %>% kable_styling() #Terlihat K optimal adalah 2
##
## Clustering Methods:
## hierarchical kmeans pam
##
## Cluster sizes:
## 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
##
## Validation Measures:
## 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
##
## hierarchical Connectivity 4.8579 15.8940 16.8940 16.8940 16.9940 32.5389 32.5389 38.7619 40.0119 43.7357 62.5472 62.5472 62.5472 62.5472 63.8806 67.2270 68.0865 71.9556 78.5524 80.0397 87.8567 94.0504 100.4496
## Dunn 0.2482 0.1750 0.1750 0.1862 0.1862 0.0866 0.0866 0.0954 0.0954 0.0954 0.0813 0.0879 0.0879 0.0917 0.0917 0.0917 0.0917 0.0917 0.0917 0.0917 0.0917 0.0577 0.0577
## Silhouette 0.5743 0.3289 0.2953 0.2774 0.2460 0.2394 0.3051 0.2925 0.2900 0.2810 0.3036 0.3180 0.3226 0.3390 0.3372 0.3435 0.3439 0.3447 0.3418 0.3422 0.3459 0.3679 0.3747
## kmeans Connectivity 31.0258 46.9234 45.1480 55.2615 37.2889 105.3278 112.9909 102.8933 106.8726 95.4925 115.8099 120.0135 120.0135 108.1873 92.7317 112.0877 117.6790 126.4944 137.0829 133.7988 129.8329 124.6083 134.9381
## Dunn 0.0113 0.0230 0.0254 0.0345 0.0346 0.0222 0.0445 0.0223 0.0228 0.0457 0.0502 0.0243 0.0243 0.0640 0.0640 0.0321 0.0643 0.0321 0.0322 0.0330 0.0323 0.0340 0.0366
## Silhouette 0.3221 0.2846 0.3310 0.3221 0.3199 0.3219 0.3262 0.3249 0.3422 0.3534 0.3228 0.3280 0.3386 0.3544 0.3593 0.3932 0.3936 0.3845 0.3849 0.3912 0.3899 0.4118 0.4197
## pam Connectivity 2.3552 7.1548 19.3996 72.2540 80.6262 73.8270 114.4377 79.9421 87.7000 103.9385 116.2214 113.7968 114.0806 113.9278 122.1270 137.5746 142.7107 136.7690 138.3218 164.4119 181.7690 182.1857 176.5302
## Dunn 0.1856 0.1617 0.0428 0.0114 0.0139 0.0139 0.0132 0.0133 0.0141 0.0141 0.0143 0.0143 0.0143 0.0285 0.0302 0.0302 0.0302 0.0302 0.0302 0.0151 0.0151 0.0151 0.0302
## Silhouette 0.3087 0.2312 0.2857 0.2918 0.3037 0.3059 0.3169 0.3343 0.3389 0.3588 0.3504 0.3564 0.3607 0.3768 0.3695 0.3698 0.3787 0.3836 0.3916 0.3744 0.3664 0.3774 0.3756
##
## Optimal Scores:
##
## Score Method Clusters
## Connectivity 2.3552 pam 2
## Dunn 0.2482 hierarchical 2
## Silhouette 0.5743 hierarchical 2
#Menentukan Matriks Jarak
jarak <- dist(datakuskal, method = 'euclidian')
#Pengklasteran
set.seed(500)
hc <- hclust(jarak, method = 'average')
#Membuat Plot Dendogram
par(mfrow = c(1, 1))
plot(hc)
#Memotong Dendogram
abline(h = 2, col = "red")
rect.hclust(hc, k = 2, border = 2:6)
|
Visualisasi 11
|
#Membuat Klaster dengan K = 2
hc_fit <- cutree(hc, k = 2)
#Tabulasi melihat jumlah anggota masing-masing klaster
table(hc_fit) #Anggota Klaster 1 503 Digimon, dan Klaster 2 hanya 2 jenis Digimon
## hc_fit
## 1 2
## 503 2
#Mengcustome Dendogram
library(dendextend)
denobj <- as.dendrogram(hc)
digimon_den <- color_branches(denobj, h = 1)
plot(digimon_den)
|
Visualisasi 12
|
Demikian sedikit ulasan kita bagaimana mempraktikkan algoritma K-Means clustering yang merupakan salah satu jenis machine learning di era Big Data dan Data Science dengan R. Jangan lupa untuk menantikan unggahan berikutnya. Selamat memahami dan mempraktikkan!