Dokumentasi DCD
Package yang digunakan
Terlampir berikut adalah library yang digunakan dalam membuat Shiny Dashboard
# library(dplyr) untuk melakukan agregasi lebih lanjut
# library(ggplot2) untuk keperluan visualisasi dan plotting
# library(ppclust) salah satu package yang digunakan untuk membuat model fuzzy clustering
# library(factoextra) digunakan untuk membuat Principal Component Analysis
# library(fclust) package yang membentuk model fuzzy clustering yang akhirnya digunakan
# library(readr) digunakan untuk membaca data csv
# library(lubridate) digunakan untuk mengambil informasi kuartal
# library(tidyverse) untuk melakukan agregasi lebih lanjut
# library(FactoMineR) digunakan untuk melakukan Principal Component Analysis
# library(ggpubr) tambahan fitur untuk package ggplot2
# library(plotly) untuk membuat plot menjadi interaktif
# library(glue) untuk membuat "tag" pada visualisasiRead data
Chunk pertama ini dilakukan untuk membaca dua dataframe yang akan digunakan untuk keperluan dashboard:
ratio_grouped <- read_csv("grouped.csv") # dataframe utama yang digunakan untuk visualisasi dan pembentukan model machine learning, dan## New names:
## Rows: 960 Columns: 16
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (1): ...1 dbl (15): GPM, WC, RE/TA, ROA, ROE, TD/TA, ATR, TD/TE, PM, Marcap/TL,
## CR, Cs...
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
unique_stocks <- read_csv("unique_stocks.csv") # daftar perusahaan yang ada pada ratio_grouped, digunakan untuk menunjukkan jumlah unik yang ada## New names:
## Rows: 273 Columns: 3
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (1): Ticker dbl (2): ...1, count
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
Setelah dataframe telah dibaca, langkah selanjutnya adalah untuk melakukan beberapa perubahan terhadap dataframe yang telah terbaca.
ratio_grouped<- ratio_grouped %>%
column_to_rownames("...1") %>% # mengubah kolom tersebut menjadi nama baris
mutate_if(is.numeric, round, digits = 2) # melakukan pembulatan terhadap angka agar lebih mudah dilihatunique_stocks <- unique_stocks %>%
select(-"...1") #menghilangkan kolom "...1" karena tidak digunakanBerikut adalah tampilan dataframe utama yang sudah mengalami pembersihan:
## GPM WC RE/TA ROA ROE TD/TA ATR TD/TE PM Marcap/TL CR
## AALI Q1 16.79 0.10 51.79 5.36 8.03 20.48 0.74 30.32 5.31 2.10 1.91
## AALI Q2 14.23 0.10 51.29 4.66 6.76 19.55 0.72 27.79 4.43 2.06 2.03
## AALI Q3 18.01 0.11 49.78 4.80 7.19 21.63 0.70 33.80 2.74 2.08 1.69
## AALI Q4 23.20 0.11 51.15 5.12 7.66 20.86 0.70 31.45 9.78 2.04 1.87
## ABBA Q1 46.88 0.16 -1.40 2.15 7.51 10.84 0.71 29.24 -2.69 3.58 1.11
## ABBA Q2 44.87 0.14 -8.47 0.29 1.73 17.58 0.61 53.21 -1.37 3.21 0.98
## Csh_Rat OCF ICR OPM
## AALI Q1 0.39 0.06 7.37 10.25
## AALI Q2 0.29 0.06 9.35 7.64
## AALI Q3 0.25 0.06 6.23 10.67
## AALI Q4 0.25 0.06 8.05 16.38
## ABBA Q1 0.08 0.05 -1.04 -1.35
## ABBA Q2 0.07 0.05 -1.26 0.31
Rata-rata variable
Dataframe ini dibentuk dengan tujuan untuk menunjukkan ringkasan untuk setiap variable yang terdapat pada dataframe “ratio_grouped”.
rata2_data<- ratio_grouped %>%
summarise_all(.funs = "mean") %>%
mutate(across(where(is.numeric), round, 2)) %>%
pivot_longer(cols = c("GPM":"OPM"),names_to = "Variable", values_to = "Rata-Rata")
median_data<- ratio_grouped %>%
summarise_all(.funs = "median") %>%
mutate(across(where(is.numeric), round, 2)) %>%
pivot_longer(cols = c("GPM":"OPM"),names_to = "Variable", values_to = "Rata-Rata")
min_data <- ratio_grouped %>%
summarise_all(.funs = "min") %>%
mutate(across(where(is.numeric), round, 2)) %>%
pivot_longer(cols = c("GPM":"OPM"),names_to = "Variable", values_to = "Rata-Rata")
max_data <- ratio_grouped %>%
summarise_all(.funs = "max") %>%
mutate(across(where(is.numeric), round, 2)) %>%
pivot_longer(cols = c("GPM":"OPM"),names_to = "Variable", values_to = "Rata-Rata")
sd_data <- ratio_grouped %>%
summarise_all(.funs = "sd") %>%
mutate(across(where(is.numeric), round, 2)) %>%
pivot_longer(cols = c("GPM":"OPM"),names_to = "Variable", values_to = "Rata-Rata")
df_list <- list(rata2_data, median_data, min_data, max_data, sd_data)
ringkasan_data <- df_list %>%
reduce(full_join, by = "Variable") %>%
rename("Mean" = "Rata-Rata.x",
"Median" = "Rata-Rata.y",
"Min" = "Rata-Rata.x.x",
"Max" = "Rata-Rata.y.y",
"Standard Deviation" = "Rata-Rata")
ringkasan_data## # A tibble: 15 × 6
## Variable Mean Median Min Max `Standard Deviation`
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 GPM 27.5 21.7 -5.93 83.5 18.1
## 2 WC 0.15 0.15 0.09 0.25 0.03
## 3 RE/TA 17.2 16.8 -46.1 75.0 21.5
## 4 ROA 2.86 2.54 -9.67 17.6 3.45
## 5 ROE 6.35 5.76 -20.5 34.9 7.47
## 6 TD/TA 25.5 25.7 0 60.7 13.1
## 7 ATR 0.84 0.78 0.04 2.57 0.56
## 8 TD/TE 61.4 54.1 0 190. 42.8
## 9 PM 3.89 3.14 -15.2 26.0 5.56
## 10 Marcap/TL 2.8 2.72 1.07 6.14 0.78
## 11 CR 1.52 1.4 0.08 3.99 0.63
## 12 Csh_Rat 0.3 0.22 0 1.18 0.27
## 13 OCF 0.05 0.05 -0.02 0.13 0.02
## 14 ICR 3.34 2.63 -7.61 15.3 3.34
## 15 OPM 9.51 7.88 -12.8 31.1 7.74
Pembentukan Model Clustering
Berikut adalah proses pembentukan model. Pada chunk dibawah, “k” mengacu kepada jumlah cluster yang ingin dibuat oleh model, “ent” mengacu kepada entropy regularization yang membantu meningkatkan kemampuan prediksi model, dan “stand” mengacu kepada fungsi standarisasi terhadap data sebelum diolah.
## The default value type="standard" has been set
## The FkM algorithm with entropy regularization has been chosen
## The default options have been set, to specify different options, use FKM.ent
Perbandingan Dengan Model Clustering Lain
Untuk melihat apakah model yang digunakan adalah model yang baik, kita dapat melihat perbedaan performa model kita dengan model lain. Model lain ini menggunakan fungsi “fcm()” dari package “ppclust”. Perbandingan performa kedua model ini akan menggunakan 5 alat pengukuran, yaitu:
- Partition Coefficient : Pengukuran yang mengevaluasi kualitas output clustering model kita. Jangka nilainya adalah 0 sampai 1, dengan semakin tinggi nilai berarti semakin baik model.
- Partition Entropy : Pengukuran Pengukuran yang menjelaskan seberapa tinggi tingkat terjadinya tumpang tindih dalam proses clustering. Nilai yang semakin rendah menunjukkan model kita memiliki tumpang tindih yang rendah, sehingga lebih baik.
- Modified Partition Coefficient : Pengukuran yang serupa dengan Partition Coefficient. Bedanya, jika Partition Coefficient hanya melihat kemungkinan sebuah data masuk kedalam cluster tertentu, maka Modified Partition Coefficient juga memfaktorkan membership untuk setiap data. Semakin tinggi nilai berarti semakin baik model.
- Fuzzy Silhouette Index : Pengukuran yang menjelaskan seberapa terpisahnya sebuah cluster dengan cluster lainnya, dengan nilai yang semakin tinggi menunjukkan pemisahan yang semakin bagus.
- Xie Beni : Pengukuran yang mengevaluasi seberapa ketatnya data didalam sebuah cluster. Nilai yang semakin rendah menunjukkan bahwa data di dalam cluster sangat ketat.
Chunk berikut menunjukkan proses pembentukan model. Parameter “centers” digunakan untuk mengatur jumlah cluster yang akan dibentuk, parameter “nstart” digunakan untuk mengatur jumlah inisialisasi yang dalam pembentukan model, dengan semakin tinggi angka nstart cenderung berarti hasil machine learning yang semakin optimal. Parameter “fixmemb” mengatur supaya identitas masing-masing titik data tidak berubah setiap kali algoritma clustering dijalankan. Terakhir, parameter “m” mengacu kepada fuzziness exponent, yang mengatur seberapa ketat atau fleksibel model dalam mengelompokkan data kedalam cluster.
Berikut adalah proses validasi untuk model yang dibuat menggunakan fungsi fcm(). Fungsi fcm() ini menghasilkan objek “ppclus”. Untuk dapat divalidasi, objek “ppclus” perlu dikonversi menjadi objek “fclust”. Berikut proses konversi serta validasinya
# convert to fclust object
ratio_validation <- ppclust2(ratio_fcm, "fclust") # konversi menjadi fclust object
idxsf <- SIL.F(ratio_validation$Xca, ratio_validation$U, alpha = 1) # mencari nilai Fuzzy Silhoutte Index
idxpe <- PE(ratio_validation$U) # mencari nilai Partition Entropy
idxpc <- PC(ratio_validation$U) # mencari nilai Partition Coefficient
idxmpc <- MPC(ratio_validation$U) # mencari nilai Modified Partition Coefficient
idxxb <- XB(ratio_validation$Xca, ratio_validation$U, ratio_fcm$v, ratio_validation$m) # mencari nilai Xie Beni IndexChunk berikut ini menunjukkan hasil validasi yang sebelumnya dibuat:
## [1] "Fuzzy Silhouette Index: 0.654945689043731"
## [1] "Partition Entropy: 0.218816880178533"
## [1] "Partition Coefficient: 0.872864746957336"
## [1] "Modified Partition Coefficient: 0.745729493914671"
## [1] "Xie Beni: 0.233982895210793"
Sedangkan chunk berikut digunakan untuk melihat nilai validasi untuk model yang dibuat menggunakan fungsi “Fclust()” dari package “fclust”
## The parameter of fuzziness m is not numeric: the default value m=2 will be used
## PC PE MPC SIL SIL.F XB
## 0.93951201 0.09862099 0.87902401 0.27893406 0.30164550 1.17475653
Berdasarkan hasil validasi yang ditunjukkan, model yang dibuat menggunakan fungsi “fcm()” memiliki nilai yang lebih rendah dengan pada pengukuran PC, MPC, dan XB, dan nilai yang lebih tinggi pada pengukuran PE dan SIL.F. Ini mengindikasikan bahwa model yang dibentuk menggunakan fcm() bisa saja terlalu ekstrim dalam melakukan pengelompokan titik data dan pemisahan cluster. Oleh karena itu, model yang dibuat menggunakan fungsi “Fclust” dipilih dengan harapan bahwa model tersebut lebih cerdas dalam menangkap kemungkinan terjadinya penurunan/peningkatan performa perusahaan.
Principal Component Analysis
Principal Component Analysis (PCA) dilakukan untuk menunjukkan perilaku cluster berdasarkan sebarapa rendah atau tinggi nilai-nilai variable pada cluster-cluster tersebut. Terdapat beberapa langkah yang dilakukan dalam tahap ini.
Koordinat Data
Bagian ini dilakukan untuk menyiapkan visualisasi koordinat data.
# Principal Component Analysis (1st, hanya objek ind.coord yang digunakan kedepannya)
pca_obj <- prcomp(ratio_grouped)
ind.coord <- as.data.frame(get_pca_ind(pca_obj)$coord)
ind.coord$Cluster <- factor(ratio_fclust$clus[,1])
eigenvalue <- round(get_eigenvalue(pca_obj), 1)
variance.percent <- eigenvalue$variance.percent Objek PCA
Bagian ini bertujuan untuk menunjukkan pembentukan objek PCA. Parameter “Scale.” mengacu pada apakah data yang digunakan perlu dilakukan penyeimbangansemua variable yang terdapat pada dataframe. “Penyeimbangan” dilakukan karena ada beberapa variable yang terdapat pada dataframe yang digunakan memiliki standar deviasi dan jangka yang terlalu luas, sehingga bisa mempengaruhi bagaimana objek PCA menginterpretasi pergerakan variable. Oleh karena itu, scaling dilakukan pada data.
Visualisasi
Chunk berikut digunakan untuk membentuk visualisasi data. Pada visualisasi ini terdapat tiga bagian:
- Bagian yang menunjukkan titik-titik data
- Bagian yang menunjukkan cluster
- Bagian yang menunjukkan pergerakkan variable
## Scatter Plot, untuk menunjukkan titik-titk data
for_plotly<- data.frame(pca_object3$x)
for_plotly$clus <- ratio_fclust$clus[,1]
percentage <- round(pca_object3$sdev^2 / sum(pca_object3$sdev^2)*100, 2)
percentage <- paste(colnames(for_plotly),"(",paste(as.character(percentage),"%",")", sep=""))
sample_name <- rownames(for_plotly)
## add frame
hull_group <- for_plotly %>%
mutate(cluster = ratio_fclust$clus[,1]) %>%
group_by(cluster) %>%
slice(chull(PC1, PC2))
## Variables
pca_loadings <- data.frame(Variables = rownames(pca_object3$rotation), pca_object3$rotation)
## Merging
for_plotly <- merge(ratio_grouped, for_plotly, by = 'row.names') %>%
column_to_rownames("Row.names")
## ggplotly object
final_viz <- ggplotly(ggplot()+
geom_polygon(hull_group,mapping = aes(x = PC1,
y = PC2,
fill = as.factor(cluster),
group = as.factor(cluster)),
alpha = 0.2)+
scale_fill_discrete(labels = c("1", "2"))+
geom_point(for_plotly,mapping = aes(x = PC1,
y = PC2,
text = glue("Stock & Quarter : {rownames(for_plotly)}
Gross Profit Margin : {round(for_plotly$GPM,2)}
Working Capital : {round(for_plotly$WC,2)}
Retained Earnings : {round(for_plotly$`RE/TA`,2)}
Return on Assets : {round(for_plotly$ROA,2)}
Return on Equity : {round(for_plotly$ROE,2)}
Debt Ratio : {round(for_plotly$`TD/TA`,2)}
Total Asset Turnover : {round(for_plotly$ATR,2)}
Debt to Equity : {round(for_plotly$`TD/TE`,2)}
Net Profit Margin : {round(for_plotly$PM,2)}
Market Value of Equity/Book Value of Liability : {round(for_plotly$`Marcap/TL`,2)}
Current Ratio : {round(for_plotly$CR,2)}
Cash Ratio : {round(for_plotly$Csh_Rat,2)}
Operating Cash Flow : {round(for_plotly$OCF,2)}
Interest Coverage Ratio : {round(for_plotly$ICR,2)}
Operating Profit Margin : {round(for_plotly$OPM,2)}
"),
fill = as.factor(clus),
stroke = 0),
size = 1.5,
show.legend = F)+
geom_segment(data = pca_loadings, aes(
x = 0,
y = 0,
xend = (PC1*6),
yend = (PC2*6)
),
arrow = arrow(length = unit(1/2, "picas")),
color = "black")+
annotate("text", x = (pca_loadings$PC1*8),
y = (pca_loadings$PC2*7),
label = pca_loadings$Variables)+
guides(fill = guide_legend(title = "Cluster"))+
labs(title = "Hasil Clustering")+
theme(plot.title = element_text(hjust = 0.5)), tooltip = "text")Function Untuk Unseen Data
Terakhir adalah untuk membentuk fungsi yang dapat membaca data baru dan menghasilkan cluster membership yang berdasarkan data tersebut. Fungsinya adalah sebagai berikut
SqEucDs <- function(x,y) sum( (x-y)^2) # Squared Euclidean Distance
unseen_data <- function(newData, centroids = ratio_fclust$H) {
dists = apply(centroids, 1, function(y) SqEucDs(y,newData))
order(dists)[1]
}Dengan fungsi ini, user perlu memasukan ratio keuangan kedalam fungsi dalam urutan tertentu. Berikut adalah urutannya:
- GPM (Gross Profit Margin)
- WC (Working Capital)
- RE/TA (Retained Earnings)
- ROA (Return on Assets)
- ROE (Return on Equity)
- TD/TA (Total Debt/Total Assets)
- ATR (Asset Turnover Ratio)
- TD/TE (Total Debt/Total Equity)
- PM (Net Profit Margin)
- Marcap/TL (Market Value of Equity/Total Debt)
- CR (Current Ratio)
- Csh_Rat (Cash Ratio)
- OCF (Operating Cash Flow)
- ICR (Interest Coverage Ratio)
- OPM (Operating Profit Margin)
Model ini menentukan kelompok clustering yang paling cocok berdasarkan nilai-nilai ratio keuangan yang dimasukkan kedalam fungsi menggunakan nilai centroid yang dihasilkan oleh model yang dibentuk. Chunk berikut menunjukkan nilai centroidnya:
## GPM WC RE/TA ROA ROE TD/TA
## Clus 1 0.3803329 -0.2084441 0.6379772 0.7092534 0.5643033 -0.5180319
## Clus 2 -0.2566589 0.1406637 -0.4305243 -0.4786234 -0.3808071 0.3495820
## ATR TD/TE PM Marcap/TL CR Csh_Rat
## Clus 1 0.02480568 -0.5698805 0.5693659 -0.1903609 0.5846852 0.5351888
## Clus 2 -0.01673955 0.3845708 -0.3842235 0.1284607 -0.3945614 -0.3611599
## OCF ICR OPM
## Clus 1 -0.1563519 0.6539929 0.3360506
## Clus 2 0.1055105 -0.4413322 -0.2267761
Semakin tinggi nilai centroid mengindikasikan bahwa variable tersebut cenderung memiliki nilai yang tinggi dalam cluster tersebut, dan begitupun sebaliknya. Contoh sederhananya: Perusahaan-perusahaan pada Cluster 1 cenderung memiliki nilai GPM yang lebih tinggi dibandingkan perusahaan-perusahaan pada Cluster 2.