1 Setup

Dataset yang digunakan dalam pemodelan machine learning unsupervised ini diambil dari Wine Data Set https://archive.ics.uci.edu/ml/datasets/wine dengan menghilangkan informasi tentang tipe wine.

Data ini adalah hasil dari analisis kimia dari wine yang tumbuh di suatu daerah yang di Italia, tapi berasal dari 3 kelompok tumbuhan yang berbeda, analisis ditentukan dari 13 konstituen yang ditemukan di masing-masing dari tiga jenis anggur.

Attributnya adalah :

  • Alcohol
  • Malic acid
  • Ash
  • Alcalinity of ash
  • Magnesium
  • Total phenols
  • Flavanoids
  • Nonflavanoid phenols
  • Proanthocyanins
  • Color intensity
  • Hue
  • OD280/OD315 of diluted wines
  • Proline

Set up chunk di awal untuk mengatur format chunk pada markdown

options(scipen = 9999)
rm(list=ls())

Setup library yang akan digunakan

library(tidyverse)
library(lubridate)
library(cluster)
library(factoextra)
library(GGally)
library(scales)
library(cowplot)
library(FactoMineR)
library(factoextra)
library(plotly)
library(gridExtra)

2 Data Preprocess and Exploratory Data Analisis

2.1 Input data

wine <- read.csv("wine-clustering.csv")
head(wine)

2.2 Data Preprocessing

Karena kolom type merupakan jenis dari wine dan berupa kategorikal, maka diubah type datanya

wine <- wine %>% 
  mutate(type = as.factor(type))

2.3 Exploratory Data Analysis

glimpse(wine)
## Rows: 178
## Columns: 14
## $ type                 <fct> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1~
## $ Alcohol              <dbl> 14.23, 13.20, 13.16, 14.37, 13.24, 14.20, 14.39, ~
## $ Malic_Acid           <dbl> 1.71, 1.78, 2.36, 1.95, 2.59, 1.76, 1.87, 2.15, 1~
## $ Ash                  <dbl> 2.43, 2.14, 2.67, 2.50, 2.87, 2.45, 2.45, 2.61, 2~
## $ Ash_Alcanity         <dbl> 15.6, 11.2, 18.6, 16.8, 21.0, 15.2, 14.6, 17.6, 1~
## $ Magnesium            <int> 127, 100, 101, 113, 118, 112, 96, 121, 97, 98, 10~
## $ Total_Phenols        <dbl> 2.80, 2.65, 2.80, 3.85, 2.80, 3.27, 2.50, 2.60, 2~
## $ Flavanoids           <dbl> 3.06, 2.76, 3.24, 3.49, 2.69, 3.39, 2.52, 2.51, 2~
## $ Nonflavanoid_Phenols <dbl> 0.28, 0.26, 0.30, 0.24, 0.39, 0.34, 0.30, 0.31, 0~
## $ Proanthocyanins      <dbl> 2.29, 1.28, 2.81, 2.18, 1.82, 1.97, 1.98, 1.25, 1~
## $ Color_Intensity      <dbl> 5.64, 4.38, 5.68, 7.80, 4.32, 6.75, 5.25, 5.05, 5~
## $ Hue                  <dbl> 1.04, 1.05, 1.03, 0.86, 1.04, 1.05, 1.02, 1.06, 1~
## $ OD280                <dbl> 3.92, 3.40, 3.17, 3.45, 2.93, 2.85, 3.58, 3.58, 2~
## $ Proline              <int> 1065, 1050, 1185, 1480, 735, 1450, 1290, 1295, 10~
anyNA(wine)
## [1] FALSE

Dari hasil diatas didapat bahwa data memiliki 178 baris data dan 14 kolom, dan data tidak memiliki missing value

2.3.1 Possibility for Clustering

Kita akan coba visualisasikan data berdasarkan kadar alkohol dan jumlah magnesium.

ggplot(wine, aes(Alcohol, Magnesium, color = type, size=Color_Intensity)) + 
    geom_point(alpha = 0.5) + theme_minimal()

Pada plot diatas terlihat bahwa tiap type saling berkelompok berdasarkan type nya jika di plot berdasarkan kadar alkoholnya dimana type 1 lebih tinggi kadar alkoholnya dengan tingkatan 2<3<1.
Lalu kita cek beberapa atribut lain diantara type type wine.

p1 <- ggplot(wine, aes(type, Alcohol, fill = type)) + geom_boxplot(show.legend = F) + 
    theme_minimal() + labs(title = "Alcohol")

p2 <- ggplot(wine, aes(type, Magnesium, fill = type)) + geom_boxplot(show.legend = F) + 
    theme_minimal() + labs(title = "Magnesium")

p3 <- ggplot(wine, aes(type, Ash, fill = type)) + geom_boxplot(show.legend = F) + 
    theme_minimal() + labs(title = "Ash")

p4 <- ggplot(wine, aes(type, Total_Phenols, fill = type)) + geom_boxplot() + 
    theme_minimal() + theme(legend.position = "bottom") + labs(title = "Total Phenols")

plot_grid(p1, p2, p3, p4)

Pada plot diatas terlihat wine type 1 memiliki kandungan lebih banyak di tiap attributnya dibanding type lain. Dari exploratory diatas, dapat disimpulkan kita bisa melakukan clustering terhadap data wine berdasarkan atribut-atributnya. Untuk mendapatkan pola-pola tersembunyi dari data, kita lakukan clustering dengan k-means.

2.3.2 Possibility for Principle Component Analysis (PCA)

Kita akan cek apakah ada high correlation antara variabel numerik. Korelasi yang kuat dapat menandakan bahwa kita bisa mengurangi dimensi data menggunakan PCA.

ggcorr(wine)
## Warning in ggcorr(wine): data in column(s) 'type' are not numeric and were
## ignored

Terdapat korelasi yang kuat antara Total_Phenols dengan Flavanoids, Flavanoids dengan OD280, dll. Menandakan bahwa dimensi masih bisa dikurangi lagi menggunakan PCA.

3 Clustering

Sebelum melakukan clustering, lakukan scale untuk menyamakan skala data

z_wine <- scale(wine %>% select(-type))

3.1 Optimal Number of Clustering

3.1.1 Elbow Method

Untuk menentukan berapa K yang diperlukan dalam pemodelan, kita akan gunakan elbow method dimana kita memilih cluster area di area siku.

fviz_nbclust(z_wine, kmeans, method = "wss") + labs(subtitle = "Elbow method")

Dari hasil elbow method, ditentukan K = 3, karena dari 3 ke 4 tidak terjadi penurunan yang signifikan.

3.1.2 Gap Statistic

Selain elbow method, kita juga bisa menggunakan Gap Statistic untuk menentukan K yang tepat. Metode ini membandingkan total dalam variasi intra-cluster untuk nilai k yang berbeda dengan nilai yang diharapkan di bawah distribusi nol dari data. K cluster yang optimal akan menjadi nilai yang memaksimalkan Gap Statistic

fviz_nbclust(z_wine, kmeans, "gap_stat") + labs(subtitle = "Gap Statistic method")

Dari hasil Gap Statistic ditentukan K optimal adalah 3.

3.1.3 Silhouette Method

Silhouette Method mengukur koefisien siluet, dengan menghitung rata-rata jarak intra-cluster dan rata-rata jarak cluster terdekat untuk setiap observasi, jumlah k didapatkan dengan memilih nilai siluet tertinggi.

fviz_nbclust(z_wine, kmeans, "silhouette") + labs(subtitle = "Silhouette method")

Dari hasil Silhouette Method ditentukan K=3

Dari hasil diatas, 3 dari 3 metode menentukan K Optimal adalah 3, maka kita tentukan K = 3. Maka selanjutnya kita lakukan clustering.

3.2 K-Means Clustering

# k-means clustering
set.seed(13)
model_wine <- kmeans(z_wine, 3)

# result analysis
model_wine
## K-means clustering with 3 clusters of sizes 62, 51, 65
## 
## Cluster means:
##      Alcohol Malic_Acid        Ash Ash_Alcanity   Magnesium Total_Phenols
## 1  0.8328826 -0.3029551  0.3636801   -0.6084749  0.57596208    0.88274724
## 2  0.1644436  0.8690954  0.1863726    0.5228924 -0.07526047   -0.97657548
## 3 -0.9234669 -0.3929331 -0.4931257    0.1701220 -0.49032869   -0.07576891
##    Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity        Hue
## 1  0.97506900          -0.56050853      0.57865427       0.1705823  0.4726504
## 2 -1.21182921           0.72402116     -0.77751312       0.9388902 -1.1615122
## 3  0.02075402          -0.03343924      0.05810161      -0.8993770  0.4605046
##        OD280    Proline
## 1  0.7770551  1.1220202
## 2 -1.2887761 -0.4059428
## 3  0.2700025 -0.7517257
## 
## Clustering vector:
##   [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 2 3 3 3 3 3 3 3 3 3 3 3 1
##  [75] 3 3 3 3 3 3 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [112] 3 3 3 3 3 3 3 2 3 3 1 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [149] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## 
## Within cluster sum of squares by cluster:
## [1] 385.6983 326.3537 558.6971
##  (between_SS / total_SS =  44.8 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Kita akan coba bandingkan data awal dengan data hasil clustering

wine$type
##   [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
##  [75] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [112] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [149] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## Levels: 1 2 3
model_wine$cluster
##   [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 2 3 3 3 3 3 3 3 3 3 3 3 1
##  [75] 3 3 3 3 3 3 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [112] 3 3 3 3 3 3 3 2 3 3 1 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [149] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
(6/178)*100 # percentage of miss-class from the data
## [1] 3.370787

Terdapat 6 atau 3.37% data yang di clusterkan di kelas yang tidak seharusnya.

# additional information
model_wine$tot.withinss # total within sum of squares
## [1] 1270.749
model_wine$betweenss # between sum of squares
## [1] 1030.251
model_wine$totss # total sum of squares
## [1] 2301
model_wine$iter # number of iteration needed to obtain optimum clustering
## [1] 4

Kita akan coba masukkan data cluster ke data awal dan coba lakukan cluster profiling

# melakukan profiling dengan summarise data

wine_profile <- wine %>%
  mutate(type = as.factor(model_wine$cluster)) %>% 
  group_by(type) %>% 
  summarise_all(.funs = "mean")

wine_profile

Profiling :
- Cluster 1 : Memiliki kadar alcohol rendah dan warna tidak terlalu pekat
- Cluster 2 : Memiliki kadar alkohol, magnesium, Flavanoids, Ash, Proanthocyanins, dan OD280 paling tinggi, Ash Alcanity rendah
- Cluster 3 : Memiliki Malic Acid, Ash, Ash Alcanity, Nonflavanoid tinggi, berwarna paling pekat, dan Flavanoids yang rendah

Dan apabila di visualisasikan clusternya, dengan fungsi fviz_cluster akan menjadi

fviz_cluster(object = model_wine,
             data = wine %>% select(-type))

4 Principal Component Analysis

wine_pca <- PCA(wine %>% select(-type) ,
                  graph = F)
fviz_eig(wine_pca, ncp = 13, addlabels = T, main = "Variance explained by each dimensions")

Pada proses PCA, kita dapat mempertahankan beberapa komponen utama yang informatif dari dataset untuk melakukan pengurangan dimensi. Dengan melakukan PCA, kita dapat mengurangi dimensi sekaligus menyimpan informasi sebanyak mungkin.

Kali ini, kita akan menyimpan setidaknya 90% informasi dari data. Dari ringkasan PCA (wine_pca$eig), kita pilih PC1-PC8 dari total 13 PC. Dengan melakukan ini, kita dapat mengurangi ~30% dimensi dari data asli kita sambil mempertahankan 92% informasi dari data.

Kita ekstrak data dari PC1-8 lalu dimasukkan ke data frame baru. Yang mana data frame ini dapat digunakan untuk analisis menggunakan supervised learning atau tujuan lain.

wine_x <- PCA(wine[,2:14], graph = F, ncp = 8)$ind$coord
wine_x <- cbind(wine_x, type = wine$type) %>% as.data.frame()
head(wine_x)

Lalu kita coba visualisasi kan data pca dengan hasil cluster

wine_xc <- cbind(wine_x, cluster = model_wine$cluster)

plot_ly(wine_xc, x = ~Dim.1, y = ~Dim.2, z = ~Dim.3, color = ~cluster, colors = c("black", 
    "red", "green", "blue")) %>% add_markers() %>% layout(scene = list(xaxis = list(title = "Dim.1"), 
    yaxis = list(title = "Dim.2"), zaxis = list(title = "Dim.3")))

5 Conclusion

Dari hasil unsupervised learning diatas, dapat disimpulkan bahwa :
- K-means clustering bisa dilakukan dengan dataset wine ini. Dataset dipecah menjadi 3 Cluster dan hanya 3,4% data yang salah prediksi.
- Pengurangan dimensi dapat dilakukan dengan dataset ini. Dari 13 PC yang ada, bisa diambil 7 PC saja dengan tetap mempertahan 92% informasi.
- Cluster 2 memiliki profiling kandungan yang cenderung lebih tinggi dibanding yang lain.