Unsupervised Learning: K-Means Clustering dengan R

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")
plot of chunk unnamed-chunk-31
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)
plot of chunk unnamed-chunk-32
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
plot of chunk unnamed-chunk-34
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
plot of chunk unnamed-chunk-35
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
plot of chunk unnamed-chunk-36
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")
plot of chunk unnamed-chunk-37
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. 
## 
plot of chunk unnamed-chunk-37
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 .
plot of chunk unnamed-chunk-37
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")
plot of chunk unnamed-chunk-38
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)
plot of chunk unnamed-chunk-41
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)
plot of chunk unnamed-chunk-43
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!

Add Comments


EmoticonEmoticon