Clustering Saham Indonesia
David

20 minute read

Introduction

Saham merupakan satuan nilai atau pembukuan dalam berbagai instrumen finansial yang mengacu pada bagian kepemilikan sebuah perusahaan. Perusahaan yang dapat menjual sahamnya ke publik merupakan saham yang sudah listing di bursa atau sudah melakukan Initial Public Offering (IPO)1. Terdapat sekitar 680 saham per Maret 2020 yang sudah listing di bursa efek Indonesia dan jumlahnya terus bertambah seiring berjalannya waktu. Setiap saham yang melantai dibursa memiliki karakteristik yang berbeda beda baik dari sisi fundamental perusahaan maupun pergerakan harga sahamnya dibursa (teknikal), oleh sebab itu perlu dilakukan pengelompokkan emiten berdasarkan karakteristik dari saham itu sendiri.

Clustering merupakan salah satu teknik dari unsupervised machine learning yang bertujuan mengelompokkan data berdasarkan kemiripan karakteristik antar data. Terdapat banyak pendekatan untuk melakukan clustering seperti partitional methods, density methods, hierarchical methods dll2. Setiap metode clustering memiliki kelebihan masing masing seperti metode partitional yang jumlah cluster dapat ditentukan oleh user, dan setiap cluster dapat di cari karakteristiksnya karena memiliki pusat cluster.

Artikel ini akan membahas clustering pada saham di Indonesia menggunakan beberapa algoritma yang berasal dari metode partitional. Setelah melakukan clustering setiap cluster akan dicari karakteristiknya (profiling)

Setup

Library yang digunakan pada artikel ini terbagi menjadi 3 kategori yaitu wrangling, visualisasi, dan clustering.

# wrangling and EDA
library(tidyverse)
library(tidyquant)
library(lubridate)

# Visualization
library(ggthemes)
library(scales)

#clustering
library(factoextra)
library(FactoMineR)
library(dbscan) # DBSCAN
library(cluster) #K-Medoid

Work Flow

Secara garis besar proses clustering ini memiliki 5 tahapan yaitu :
- Data Collaction : Pengumpulan data dari berbagai sumber.
- Feature Engineering : Mengekstrak feature/ informasi dari data yang ada.
- Anomaly Detection : Mencari data yang bersifat anomali dan menghapusnya sehingga tidak mengganggu cluster yang akan dibentuk.
- Clustering : Mengelompokkan data menjadi beberapa kelompok berdasarkan karakteristik data.
- Cluster Profiling : Mencari karakteristik dari setiap cluster yang sudah terbentuk.

Data Collection

Terdapat 2 sumber data yang digunakan pada analisis ini yaitu data profil perusahaan dan data pergerakan harga saham setiap harinya. Data profil perusahaan didapat dengan cara scraping dari website resmi Bursa Efek Indonesia (IDX). Hasil scraping data kemudian di simpan dalam file daftar_saham.csv. Emiten yang akan dilakukan clustering adalah emiten yang sudah melantai di bursa sebelum tahun 2017, hal ini bertujuan untuk menghindari IPO affect3.

profile <- read_csv("data_input/daftar_saham.csv") %>% 
  mutate(ListingDate = as.Date(ListingDate)) %>% 
  filter(year(ListingDate) < 2017)
head(profile)
#> # A tibble: 6 x 6
#>   Code  Name                           ListingDate    Shares ListingBoard sector
#>   <chr> <chr>                          <date>          <dbl> <chr>        <chr> 
#> 1 ABBA  Mahaka Media Tbk.              2002-04-03     2.76e9 PENGEMBANGAN TRADE 
#> 2 AIMS  Akbar Indo Makmur Stimec Tbk   2001-07-20     2.20e8 PENGEMBANGAN TRADE 
#> 3 AKKU  Anugerah Kagum Karya Utama Tbk 2004-11-01     6.45e9 PENGEMBANGAN TRADE 
#> 4 APII  Arita Prima Indonesia Tbk.     2013-10-29     1.08e9 PENGEMBANGAN TRADE 
#> 5 ARTA  Arthavest Tbk                  2002-11-05     4.47e8 PENGEMBANGAN TRADE 
#> 6 BAYU  Bayu Buana Tbk                 1989-10-30     3.53e8 Pengembangan TRADE

Terdapat 6 kolom (variabel) dari data profil perusahaan yaitu :
- Code : Kode emiten perusahaan di bursa.
- Name : Nama perusahaan.
- ListingDate : Tanggal perusahaan pertama kali melantai dibursa (IPO).
- Share : banyaknya lembar sahan suatu perusahaan.
- ListingBoard : Papan pencatatan saham (Pengembangan dan Utama).
- Sector : Kategori perusahaan berdasarkan sektornya4.

Data pergerakan harga saham didapat dari yahoo finance yang bisa langsung diakes menggunakan function tq_get() dari packages tidyquant. Kode emiten saham Indonesia pada yahoo finance diakhiri oleh .JK sebagai tanda bahwa emiten tersebut berasal dari Indonesia.

emiten_code <- profile %>% 
  mutate(Code = paste0(Code,".JK")) %>% 
  pull(Code)

emiten_code[1:5]
#> [1] "ABBA.JK" "AIMS.JK" "AKKU.JK" "APII.JK" "ARTA.JK"

Setelah kode emiten disesuaikan tahap selanjutnya mengambil data pergerakan harga saham setiap harinya mulai dari awal tahun 2017 hingga akhir tahun 2019 menggunakan function tq_get(). Terdapat beberapa parameter yang harus di isi pada function tq_get() yaitu :

  • x : Kode emiten
  • from : tanggal dimulai harga saham diambil
  • to : tanggal berakhir harga saham diambil

Data yang diambil langsung dilakukan penghapusan .JK agar code emiten yang didapat sesuai dengan code pada data profile

stocks <- tq_get(emiten_code, from = "2017-01-01", to = "2019-12-31") %>% 
  mutate(symbol = str_remove_all(symbol, ".JK"))
head(stocks)
#> # A tibble: 6 x 8
#>   symbol date        open  high   low close volume adjusted
#>   <chr>  <date>     <dbl> <dbl> <dbl> <dbl>  <dbl>    <dbl>
#> 1 ABBA   2017-01-02    50    50    50    50      0       50
#> 2 ABBA   2017-01-03    50    50    50    50   1000       50
#> 3 ABBA   2017-01-04    50    50    50    50  95400       50
#> 4 ABBA   2017-01-05    50    51    50    50 115900       50
#> 5 ABBA   2017-01-06    50    51    50    51  25000       51
#> 6 ABBA   2017-01-09    51    51    50    50   6600       50

Pada data stocks terdapat 8 variabel yaitu :
- symbol : Kode Emiten perusahaan di bursa
- date : Tanggal dari harga saham
- open : Harga pembukaan
- high : Harga tertinggi
- low : Harga terendah
- close : Harga penutupan
- volume : banyaknya lembar saham yang diperdagangkan
- adjusted : harga penutupan yang sudah disesuikan dengan aksi korporasi lainnya5.

Terdapat beberapa kode saham yang tidak dapat diambil data pergerakan harganya, hal ini disebabkan tidak adanya kode emiten pada yahoo finance. berikut adalah kode emiten tersebut

yahoo_symbols <- stocks %>% 
  pull(symbol) %>% 
  unique()

profile %>% 
  filter(!Code %in% yahoo_symbols) %>% 
  pull(Code)
#> [1] "SUGI" "TRIL" "GOLL" "KBRI" "BTEL" "CMPP" "HDTX" "LCGP" "SCBD"

Feature Engineering

Feature engineering merupakan suatu proses yang menggunakan expert domain knowledge untuk mengekstrak informasi yang ada pada data dengan tujuan meng-improve hasil dari machine learning. Terdapat 3 feature yang akan diekstrak dari data yang ada yaitu volatilitas (Volatility), liquiditas (Liquidity) serta kapasitas (size) dari suatu saham6.

Volatilitas (Volatility)

Volatilitas merupakan indikator tingkat perubahan harga saham setiap harinya. Volatilitas suatu saham bisa dilihat dari persentase perubahan harga saham setiap harinya7. Suatu saham naik dan turun dengan persentase yang besar maka, saham tersebut bisa dikatakan memiliki volatilitas yang tinggi begitu juga sebaliknya. Nilai yang bisa digunakan untuk mengukur tingkat volatilitas suatu saham yaitu standar deviasi dari persentase perubahan harga. Perhitungan standar deviasi dilakukan pada persentase perubahan harga disetiap tahunnya. Semakin besar nilai standar deviasi maka perubahan harga saham dapat berubah dengan cepat setiap harinya.

stocks %>% 
  na.omit() %>% # remove missing value
  mutate(change = (close- lag(close))/lag(close)) %>% # calculate the price change ratio
  group_by(symbol, year(date)) %>% 
  summarise(sdclose = StdDev(change)) %>% 
  ungroup() %>% 
  head(6)
#> # A tibble: 6 x 3
#>   symbol `year(date)` sdclose[,1]
#>   <chr>         <dbl>       <dbl>
#> 1 AALI           2017    14.0    
#> 2 AALI           2018     0.0214 
#> 3 AALI           2019     0.0183 
#> 4 ABBA           2017     0.00756
#> 5 ABBA           2018     0.0699 
#> 6 ABBA           2019     0.0567

Likuiditas (Liquidity)

Likuiditas merupakan indikator seberapa mudah saham tersebut untuk dijual dan dibeli tanpa mempengaruhi harga aset. Likuiditas suatu saham dapat dilihat dari volume saham itu. Semakin besar volume dari suatu saham yang diperdagangkan setiap harinya maka semakin liquid saham tersebut. Median dari volume saham digunakan sebagai indikator likuiditas suatu saham. Pemilihan median sebagai indikator karena sifatnya yang robust terhadap outlier (tidak seperti mean) sehingga hasil yang didapat tidak terdapat bias.

Jumlah saham setiap perusahaan berbeda beda seperti FREN dengan jumlah share 217 milliar sedangkan LPGI hanya 150 juta oleh sebab itu bila nilai pada volume langsung digunakan akan terjadi bias pada informasi yang didapat. Untuk menghindari terjadinya bias volume suatu saham akan dibagi terlebih dahulu dengan jumlah lembar saham (total share) setiap emiten. Total share didapat dari data profile sehingga perlu dilakukan penggabungan 2 data frame (join) terlebih dahulu.

liq_stocks <- stocks %>% 
  na.omit() %>% 
  left_join(profile, by = c("symbol" = "Code")) %>% 
  mutate(volume = volume / Shares) %>% 
  group_by(symbol, year(date)) %>% 
  summarise(med_vol = median(volume)) %>% 
  ungroup() %>% 
  arrange(desc(med_vol))
head(liq_stocks)
#> # A tibble: 6 x 3
#>   symbol `year(date)` med_vol
#>   <chr>         <dbl>   <dbl>
#> 1 POOL           2019 0.0323 
#> 2 TRAM           2019 0.0207 
#> 3 MAMI           2019 0.0173 
#> 4 POOL           2018 0.0145 
#> 5 RIMO           2018 0.0123 
#> 6 LEAD           2018 0.00942

Setelah dilakukan penyesuaian pada volume, range dari nilai volume sekarang dari 1 hingga 0. saham dengan tingkat likuiditas terbesar dan terendah berdasarkan median volume dapat dilihat pada plot histogram dibawah.Plot dengan warna merah merupakan saham paling likuid, sedangkan plot yang berwarna biru merupakan saham tidak liquid.

Size

Size merupakan ukuran seberapa besar sebuah perusahaan di pasar saham. Nilai size bisa diwakili oleh market capitalization (market cap), market cap merupakan perkalian antar total share dengan harga saham tersebut. Semakin besar market cap maka semakin sulit untuk harga saham dipermainkan oleh segelintir orang. Harga yang digunakan untuk menghitung market cap adalah harga penutupan di akhir tahun 2019.

Market capitalization terbesar di Indonesia adalah BBCA dengan nilai lebih dari 800 T pertanggal 30 Desember 2019. Market cap besar didominasi dari sektor finance khususnya perbankan (BBCA, BBRI, BMRI,BBNI).

Create Data frame

Setelah mengetahui feature apa saja yang akan digunakan dalam proses clustering, tahap selanjutnya adalah menggabungkan semua feature tersebut kedalam satu dataframe.

stocks_agg <- stocks %>% 
  na.omit() %>% 
  mutate(change = (close- lag(close))/lag(close)) %>% 
  group_by(symbol, year(date)) %>% 
  summarise(sdclose = StdDev(change), # volatility
            medvol = round(median(volume)) # liquidity
            ) %>% 
  ungroup() %>% 
  left_join(select(profile, Code, Shares) , by = c("symbol"="Code")) %>% 
  mutate(medvol = medvol/Shares*100) %>% 
  select(-Shares) %>% 
  rename(year = 2)
head(stocks_agg)
#> # A tibble: 6 x 4
#>   symbol  year sdclose[,1]    medvol
#>   <chr>  <dbl>       <dbl>     <dbl>
#> 1 AALI    2017    14.0     0.0430   
#> 2 AALI    2018     0.0214  0.0445   
#> 3 AALI    2019     0.0183  0.0308   
#> 4 ABBA    2017     0.00756 0.0000817
#> 5 ABBA    2018     0.0699  0.0225   
#> 6 ABBA    2019     0.0567  0.601

Hasil aggregasi data diatas mendapatkan 4 variabel yaitu symbol, year, sdclose, medvol. sdclose merupakan standar deviasi dari close price, dan medvol merupakan median dari volume saham yang sudah dibagi dengan total share dari masing masing emiten. Data diatas masih belum dapat digunakan dalam proses clustering dikarenakan setiap emiten blm diwakili oleh satu baris sehingga perlu dilakukan transformasi data menjadi wide format dataframe serta menambahakan data market cap.

data_final <-  stocks_agg %>% 
  rename(year = 2) %>% 
  pivot_wider(names_from = year, values_from = c(3:4)) %>% 
  left_join(market_cap) %>% 
  select(symbol, market_cap, everything()) %>% 
  replace(is.na(.),0) %>% 
  column_to_rownames(var = "symbol")
head(data_final) 
#>          market_cap sdclose_2017 sdclose_2018 sdclose_2019   medvol_2017
#> AALI 28052332453475 13.971410210   0.02135307   0.01829919 0.04303813692
#> ABBA   292043250000  0.007557864   0.06987505   0.05673176 0.00008166599
#> ABDA  4330126593000  2.514334020   0.01968832   0.03312356 0.00000000000
#> ABMM  4212342450000  1.384784132   0.04841329   0.04950203 0.00000000000
#> ACES 25639250000000  0.036338664   0.02335375   0.02038276 0.04927463557
#> ACST   679000000000  0.377768825   0.01953749   0.02650320 0.01928571429
#>      medvol_2018    medvol_2019
#> AALI  0.04450071 0.030833563535
#> ABBA  0.02254344 0.600731364276
#> ABDA  0.00000000 0.000000000000
#> ABMM  0.00000000 0.000001816092
#> ACES  0.03953353 0.069497667638
#> ACST  0.10961429 0.030935714286

Data untuk proses clustering sudah siap, data_final terdiri dari 510 baris yang setiap barisnya mewakili 1 emiten. Variabel yang digunakan dalam proses clustering terdapat 7 variabel yaitu market_cap, standar deviasi, dan median dari tahun 2017 hingga 2019.

Outlier Detection

Outlier/anomaly detection merupakan teknik mencari data yang bersifat berbeda eksteam dari data lainnya. Pendeteksian outlier perlu dilakukan mengingat algoritma yang digunakan dalam proses clustering adalah K-Means dan K-Medoid. Algoritma tersebut akan memaksa data yang bersifat outlier untuk masuk kedalam salah satu cluster yang terbentuk, apabila hal itu terjadi maka karakteristik cluster akan berubah signifikan. Ada banyak cara untuk melakukan anomaly detection salah satunya adalah menggunakan algoritma DBSCAN8 yang merupakan salah satu algoritma clustering berdasarkan kerapatan antar data (density method).

Berbeda dengan algoritma K-Means yang harus menentukan jumlah cluster diawal, metode BDSCAN memerlukan minimum points (minPts) dan epsilon (eps) untuk proses pembuatan clusternya. Pencarian nilai Eps dan MinPts yang optimal bisa dilakukan dengan metode knee plot. Pembuatan knee plot dapat menggunakan fungsi kNNdistplot dari packages dbscan. Ide utama dari fungsi ini adalah menghitung jarak rata2 untuk setiap data ke k tetangga terdekatnya (nearest neighbors). Nilai dari K ditentukan oleh user yang nantinya akan digunakan sebagai minPts pada proses clustering. Rata rata jarak yang sudah didapat divisualisasikan dalam plot secara ascending untuk mendapatkan “knee” yang menunjukkan nilai optimal dari eps berdasarkan K yang ditentukan.

kNNdistplot(scale(data_final), k = 8)
abline(h = 2.5, col = "red")

Berdasarkan plot diatas dengan menggunakan K = 8 didapat jarak yang optimal yaitu sekitar 2.5. Nilai 2.5 didapat dari posisi “knee” yang terbentuk pada plot. Hasil pencarian nilai eps yang optimal diatas dapat digunakan dalam proses clustering yang mana nilai eps adalah 2.5 dengan minPts 8. Tahap selanjutnya adalah pembuatan cluster menggunakan function dbscan dengan parameter yang sudah didapat.

# DBSCAN clustering
dbscan_clust <- dbscan(scale(data_final), eps = 2.5, minPts = 8)
dbscan_clust
#> DBSCAN clustering for 510 objects.
#> Parameters: eps = 2.5, minPts = 8
#> The clustering contains 1 cluster(s) and 10 noise points.
#> 
#>   0   1 
#>  10 500 
#> 
#> Available fields: cluster, eps, minPts

Dari hasil anomaly detection menggunakan metode DBSCAN didapat 10 data noise atau outlier. Label outlier yang sudah didapat (cluster 0) digabungkan dengan data_final dengan tujuan untuk mengetahui saham apa yang dikategorikan outlier.

# cluster yang outlier
data_anomaly <- data_final %>% 
  rownames_to_column(var = "symbol") %>% 
  mutate(db_clust = as.factor(dbscan_clust$cluster)) 

data_anomaly %>% 
  filter(db_clust==0) %>% 
  pull(symbol)
#>  [1] "ATIC" "BCIC" "IIKP" "LEAD" "MAMI" "MYRX" "OCAP" "POOL" "RIMO" "TRAM"

Emiten yang diindikasikan sebagai outlier adalah ATIC, BCIC, IIKP, LEAD, MAMI, MYRX, OCAP, POOL, RIMO, TRAM. Untuk melihat seberapa ekstream outlier tersebut secara visual dapat digunakan visualisasi biplot. Biplot merupakan teknik visualisasi dari hasil Principal Component Analysis (PCA)9. PCA merupakan teknik mereduksi dimensi dengan mempertahankan informasi sebanyak mungkin. Fungsi yang digunakan dalam pembuatan PC adalah PCA(), dan untuk untuk membuat biplot menggunakan plot.PCA() dari package FactoMineR.

 data_anomaly %>% 
  column_to_rownames("symbol") %>% 
  PCA(graph = F, quali.sup = 8) %>% 
  plot.PCA(choix = "ind", 
           select = "contrib10",
           habillage = 8,
           col.hab = c("red", "black"))

Terdapat 2 warna pada biplot diatas yaitu merah dan hitam, emiten dengan warna merah merupakan emiten yang diindikasikan outlier. Emiten yang berwarna merah menyebar cukup jauh dari sebaran data yang lain (warna hitam). Emiten yang diindikasikan sebagai outlier tidak akan digunakan dalam proses clustering agar cluster yang terbentuk representatif.

Data yang akan digunakan dalam proses clustering juga harus dilakukan scaling, hal ini dikarenakan metode K-Means berdasarkan perhitungan jarak antar data (euclidian distance) yang mana range antar data harus sama. proses scaling yang dilakukan menggunakan metode z-score, proses scaling hanya merubah skala dari data tanpa merubah distribusi data awal.

data_final_scale <- data_anomaly %>% 
  filter(db_clust != 0) %>% 
  column_to_rownames(var = "symbol") %>% 
  select(-db_clust) %>% 
  scale()
tail(data_final_scale)
#>       market_cap sdclose_2017 sdclose_2018 sdclose_2019 medvol_2017 medvol_2018
#> WSBP -0.09594534   -0.2898713   -0.2501830  -0.78107074   2.6534829   1.7603059
#> WSKT  0.11921277   -0.3109128   -0.1543827  -0.45493589   0.7487485   2.1476185
#> WTON -0.16844413   -0.2528324   -0.2395274  -0.22551437   0.6106544   0.8025378
#> YPAS -0.23142357   -0.2782496    0.6560785   2.75998113  -0.4504959  -0.4460910
#> YULE -0.22876145   -0.2692605    0.1358728   2.69399375  -0.4456131  -0.4460910
#> ZBRA -0.23659827   -0.2888215   -0.5748003   0.07454265  -0.4504959  -0.4460910
#>      medvol_2019
#> WSBP   1.0455536
#> WSKT   1.5479780
#> WTON   1.2339881
#> YPAS  -0.4106457
#> YULE  -0.4105052
#> ZBRA  -0.4108071

Clustering

K-Means

K-Means10 merupakan algoritma clustering yang masuk kedalam kategori partitioning clustering yang berarti jumlah cluster ditentukan oleh user. Algoritma K-Means menghasilkan pusat cluster yang disebut centroid. Centroid dari setiap cluster bukanlah sebuah data melainkan sebuah titik yang merepresentasikan rata-rata (mean) nilai dari setiap variabel di setiap cluster. Penentuan nilai K yang optimum dapat menggunakan teknik elbow method. Elbow method mengoptimalkan jarak antar data ke centroid atau sering disebut within sum of square (wss). Nilai K yang optimum adalah ketika jumlah cluster ditambah namun penurunan wss tidak lagi drastis.

kmeansTunning <- function(data, maxK) {
  withinall <- NULL
  total_k <- NULL
  for (i in 2:maxK) {
    set.seed(122)
    temp <- kmeans(data,i)$tot.withinss
    withinall <- append(withinall, temp)
    total_k <- append(total_k,i)
  }
  plot(x = total_k, y = withinall, type = "o", xlab = "Number of Cluster", ylab = "Total wss")
  abline(h = 1080, col  = "firebrick3", lty = 2)
}
kmeansTunning(data_final_scale, maxK = 10)

Berdasarkan elbow plot diatas dapat dilihat ketika jumlah cluster ditambah dari 7 ke 8 penurunan nilai total withinss sudah tidak pesat lagi, sehingga jumlah cluster yang diambil adalah 7.

set.seed(122)
clust <- kmeans(data_final_scale,7)
fviz_cluster(clust, data_final_scale, ggtheme = theme_minimal()) 

Dari hasil visualisasi diatas dapat dilihat luas area dan jumlah anggota cluster berbeda. Hasil cluster dapat dilihat pada data dibawah, pada cluster 4 merupakan cluster dengan anggota terkecil yaitu 2 data, sedangkan cluster 2 merupakan cluster terpadat dengan jumlah anggota sebesar 269 data dengan nilai total wss sebesar 272.

kmeans_total <- clust$cluster %>% 
  table() %>% 
  as.numeric()

data.frame(cluster = c(1:7), 
           member = kmeans_total, 
           wss = clust$withinss) %>% 
  arrange(wss)
#>   cluster member        wss
#> 1       4      2   1.705163
#> 2       6     13  66.114389
#> 3       7      7  79.602120
#> 4       5    134 147.661506
#> 5       3     12 227.541188
#> 6       2    269 272.378141
#> 7       1     63 284.296567

Salah satu nilai yang bisa digunakan untuk mengetahui seberapa baik cluster yang dihasilkan oleh algoritma K-Means adalah perbandingan antara nilai between_SS dengan total_SS. hasil pembagian antara between_SS dengan total_SS mengindikasikan seberapa berkumpul data di setiap centroidnya. Hasil yang didapat dari perbandingan kedua nilai tersebut adalah 69.1 % yang mana apabila semakin mendekati 100% semakin baik.

clust$betweenss / clust$totss *100
#> [1] 69.10109

K-Medoid

Sama seperti K-Means, K-Medoid11 merupakan algoritma clustering yang masuk kedalam kategori partitioning clustering. Berbeda dengan K-Means, pusat cluster dari K-Medoid adalah salah satu data yang ada didalam cluster sehingga pusat cluster disebut medoid. Umumnya untuk menentukan nilai K yang optimum pada K-medoid adalah menggunakan silhouette yang mana teknik ini mencari nilai dissimilarities terendah untuk setiap cluster, namun pada artikel ini akan digunakan WSS agar hasil clustering dapat dibandingkan dengan K-means cluster12. untuk mencari nilai WSS yang optimum maka akan digunakan teknik elbow plot.

# Elbow method
fviz_nbclust(data_final_scale, pam, method = "wss") +
    geom_vline(xintercept = 8, linetype = 2)+
  geom_hline(yintercept = 1100)+
  labs(subtitle = "Elbow method")

berdasarkan elbow plot didapat jumlah cluster yang optimum adalah 8 dengan total wss 1100. Fungsi yang digunakan untuk membuat K-medoid clustering adalah pam() dari packages cluster. data yang digunakan adalah data yang sama ketika proses pembuatan cluster dengan k-means, dan jumlah cluster yang digunakan adalah 8.

# K-medoid clustering
kmedoid <- pam(x = data_final_scale, k = 8)

# Cluster info
kmedoid$clusinfo %>% 
  as.data.frame() %>% 
  mutate(cluster = 1:8,
         avg_sil = kmedoid$clus.avg.widths, 
         medoid = rownames(kmedoid$medoids)) %>% 
  select(cluster, everything())
#>   cluster size max_diss   av_diss  diameter separation medoid
#> 1       1   15 5.428291 1.9387329  7.729919 0.81101729   SILO
#> 2       2   48 9.127867 2.9570740 12.677216 0.61688893   WIKA
#> 3       3  137 4.996278 0.6228818  5.735555 0.07694591   KKGI
#> 4       4   68 3.035536 1.2728382  4.395163 0.29571561   SCMA
#> 5       5  166 2.129887 0.6498969  2.765000 0.09038836   LTLS
#> 6       6   57 4.952556 0.6942794  5.593736 0.07694591   ETWA
#> 7       7    7 8.340566 2.5120613 10.406839 1.31886987   BMRI
#> 8       8    2 1.846707 0.9233535  1.846707 9.28244066   MAPI

Hasil clustering menggunakan K-Medoid menghasilkan beberapa informasi untuk setiap clusternya. Terdapat 7 variabel yang menunjukkan informasi seperti berikut :

  • cluster : Id cluster.
  • size : Banyaknya data dalam cluster.
  • max_diss : Jarak terbesar antar data dalam cluster ke medoid-nya.
  • av_diss : Rata rata jarak antar data ke medoid.
  • diameter : Jarak terbesar antar 2 data dalam 1 cluster.
  • separation : Jarak terkecil antar data dalam cluster ke data pada cluster lain.
  • medoid : Data yang menjadi pusat cluster.

Dari data diatas bisa disimpulkan bahwa cluster 8 merupakan cluster dengan nilai separation terbesar yang menunjukkan cluster ini jauh dari cluster yang lain. Cluster lainnya yaitu cluster 2 memiliki diameter terbesar yang menjadikan cluster ini sebagai cluster terluas, sedangkan cluster 5 dengan jumlah anggota 166 dan diameter 2.765 membuat cluster ini menjadi cluster terpadat.Karakteristik tersebut dapat dilihat dalam bentuk visualisasi seperti dibawah.

fviz_cluster(kmedoid, data_final_scale, ggtheme = theme_minimal())

Cluster Profiling

Comparing K-Means and K-Medoid

Hasil clustering antara K-Medoid dan K-Means bila dilihat secara jumlah cluster dan wss tidak tidak terlalu jauh berbeda. Algoritma K-Means menghasilkan cluster sebanyak 7 dengan total wss sebesar 1080, sedangkan algoritma K-Medoid menghasilkan 8 cluster dengan total wss sebesar 1100. Bila hasil hasil kedua clustering tersebut dibandingkan secara langsung maka menghasilkan visualisi seperti dibawah.

Hasil visualisasi diatas menunjukkan bahwa cluster 7 pada K-Means (sumbu x) memiliki anggota yang sama dengan cluster 7 pada K-medoid (sumbu y). Sedangkan cluster 2 pada K-Means terpecah ke dalam cluster 1, 3, 4, dan 5 pada K-Medoid hal ini disebabkan karena jarak antar cluster yang sangat berdekatan seperti plot dibawah.

ggpubr::ggarrange(
  fviz_cluster(clust, data_final_scale, main = "K-Means Clustering", ggtheme = theme_minimal()),
  fviz_cluster(kmedoid, data_final_scale, main = "K-Medoid Clustering",  ggtheme = theme_minimal()), 
  ncol = 1  
  )

Berdasarkan nilai wss dan jumlah K, K-Means lebih efektif dibandingkan K-Medoid oleh sebab itu cluster pada hasil K-means yang akan digunakan pada proses profiling cluster.

Characteristics of Cluster

Setiap cluster yang dihasilkan pada proses clustering memiliki karakteristik yang berbeda beda. Karakter atau ciri dari setiap cluster ini didapat dari kondisi data yang ada dalam cluster tersebut. Untuk mengetahui ciri dari setiap cluster dapat dilakukan dengan analisis statistik deskriptif di setiap clusternya.

General

Hasil clustering menghasilkan 7 cluster dengan karakteristik berbeda beda. Cluster 2 merupakan cluster dengan jumlah data terbanyak yaitu sebesar 269 sedangkan cluster 4 hanya berisi 2 data saja. Selain itu rata rata market capitalization terbesar dipegang oleh cluster 7 dengan nilai 420.9 triliun. Dilihat dari tingkat volatilitas pergerakakan harga, seluruh cluster pada 2017 memiliki volatilitas yang lebih tinggi dari tahun lainnya kecuali cluster 4. Cluster 3 merupakan cluster dengan tingkat liquiditas yang tinggi, selama 3 tahun rata rata likuiditas diatas 0.3 atau 30% dari total seluruh saham yang ada.

Jumlah Anggota

Cluster 1

Likuiditas tinggi dan stabil

Cluster 1 merupakan salah satu cluster dengan tingkat liquiditas yang tinggi. Tingginya nilai likuiditas diimbangi dengan konsistensinya selama 3 tahun, hal ini dapat ditunjukkan lewat boxplot dibawah. Berdasarkan plot dibawah garis tengah pada boxplot, serta ukuran box relatif lebih stabil bila dibandingkan dengan cluster lain. Cluster 4 yang terlihat lebih stabil daripada cluster 1 itu terjadi karena pada cluster tersebut hanya berisi 2 data saja.

Cluster 2

Anggota cluster terbanyak

Cluster 2 merupakan cluster dengan jumlah anggota terbanyak yaitu sebesar 269 data atau sekitar 53% dari total keseluruhan data. Cluster ini terbilang sulit untuk dilakukan profiling secara langsung karena tidak adanya karakterisitik yang dominan. Bila dilihat kembali pada plot yang membandingkan hasil cluster K-Means dan K-Medoid, cluster 2 terbagi menjadi 3 bagian bila dilakukan clustering menggunkan K-Medoid, oleh sebab itu cluster ini akan dibagi lagi menjadi 3 sub-cluster menggunakan metode K-medoid. Hasil sub-cluster dapat dilihat pada visualisasi dibawah

Berdasarkan hasil clustering menggunakan K-Medoid didapat 3 cluster seperti dibawah. sub-cluster 2 (warna hijau) merupakan cluster paling aktif, hal ini ditunjukkan dengan searahnya sebaran data tersebut dengan variabel medvol yang menunjukkan likuiditas. sub-cluster 1 memiliki arah yang berlawanan dengan variabel sdclose yang menunjukkan nilai volatilitas, sedangkan sub-cluster 3 berlawanan dengan sdclose_2017, serta market_cap.

anggota yang termasuk kedalam sub-cluster dapat dilihat melalui visualisasi dibawah ini.

Cluster 3

paling liquid setiap tahun

Cluster 3 merupakan cluster dengan anggota 12 emiten. anggota dari cluster ini adalah BCIP, BUMI, CINT, ELSA, ENRG, ERAA, KREN, SIMA, SSIA, SSMS, TARA, WEHA. Cluster ini merupakan cluster dengan tingkat likuiditas tertinggi setiap tahunnya bila dibandingkan dengan clsuter lain.

Cluster 4

Cluster paling kecil

Cluster 4 merupakan cluster dengan anggota terkecil, yang hanya di isi oleh ELTY, dan MAPI. cluster 4 terbentuk karena tingginya nilai volatilitas pada tahun 2018

Cluster 5

Market Capitalization Terendah

Cluster 5 merupakan cluster dengan rata rata market capitalization terendah di pasar. Cluster yang dengan total anggota 134 ini miliki rata2 market cap sebesar 2.6 triliun.

Volatilitas tertinggi di 2019

Selain memiliki market cap yang kecil, cluster ini juga memiliki volatilitas yang besar hal ini di tunjukkan pada boxplot dibawah. nilai volatilitas pada tahun 2019 diatas rata rata (garis biru) seluruh emiten yang ada.

data_wide %>% 
  ggplot(aes(x = as.factor(cluster), y = sdclose_2019)) +
  geom_boxplot() +
  geom_boxplot(data = filter(data_wide, cluster==5), fill = "firebrick3") +
  theme_pander() +
  geom_hline(aes(yintercept = mean(sdclose_2019)), lty = 2, col = "blue") +
  labs(x = "Cluster", 
       y = NULL,
       title = "Standard Deviation of Closing Price 2019")

Cluster 6

Volatilitas pada tahun 2017 terbesar

Cluster 6 merupakan cluster paling volatile di tahun 2017. Bila dilihat dari boxplot nilai standar deviasi tahun 2017 jauh diatas cluster yang lainnya, bahkan nilai minimum dari cluster tersebut lebih tinggi dari nilai maksimum pada cluster lain.

Likuiditas terendah di tahun 2017

Walaupun pada tahun 2017 cluster ini paling volatile namun hal tersebut berbanding terbalik dengan likuiditasnya. Nilai median dari volume di tahun yang sama menunjukkan cluster ini merupakan cluster paling tidak liquid.

Cluster 7

Market Cap Besar

Cluster 7 merupakan cluster dengan jumlah anggota 7 emiten. Cluster ini memiliki rata rata market cap terbesar bila dibandingkan dengan cluster lain. Anggota dari cluster ini merupakan ASII, BBCA, BBRI, BMRI, HMSP, TLKM, UNVR yang merupakan emiten dengan market cap terbesar di bursa per Desember 2019.

Volatilitas rendah

Volatilitas cluster ini pada tahun 2018 dan 2019 relatif rendah bila dibandingkan cluster lain. Rendahnya volatilitas dapat dilihat pada boxplot dibawah. Garis tengah pada boxplot (median) cluster 7 lebih rendah dibandingkan cluster lain, dan variansi dari data juga terlihat kecil, yang mana bisa ditunjukkan dari tipisnya box yang terbentuk.

Conclusion

Clustering yang dilakukan terhadap data saham hanya mempertimbangkan feature teknikal dari saham saja. Dari 510 data yang digunakan terdapat 10 data yang teridentifikasi sebagai outlier menggunakan metode DBSCAN, dan data tersebut tidak dimasukkan dalam proses pembuatan cluster. Data yang tidak termasuk kedalam outlier berhasil dilakukan clustering menggunakan algoritma K-Means dan menghasilkan 7 cluster dengan total wss 1080. Setiap cluster memiliki jumlah anggota dan karakteristik yang berbeda beda. Hasil Clustering ini dapat digunakan oleh para pelaku pasar saham dalam memilih emiten berdasarkan karakteristiknya.

Reference

comments powered by Disqus