1 Introduction

Kesehatan mental merujuk kepada kondisi kesejahteraan emosional, psikologis, dan sosial seseorang. Ini mencakup cara kita berpikir, merasakan, dan berperilaku. Pentingnya Kesehatan Mental karena dapat memengaruhi cara kita berpikir, merasa, dan berinteraksi dengan orang lain. Kesehatan Mental juga vital untuk kesejahteraan secara keseluruhan dan dapat mempengaruhi kesehatan fisik. Di sini terdapat dataset terkait Mental Health yang diperoleh dari Kaggle. Dari dataset tersebut kita akan coba untuk melakukan clustering analysis menggunakan metode K-means.

2 Import Data

library(dplyr)
library(FactoMineR)
library(factoextra)
library(ggiraphExtra)
library(ggplot2)
library(reshape2)
library(GGally)
library(plotly)
mental <- read.csv("data_input/mental_health_dataset.csv")

rmarkdown::paged_table(mental)
glimpse(mental)
#> Rows: 10,000
#> Columns: 14
#> $ age                    <int> 56, 46, 32, 60, 25, 38, 56, 36, 40, 28, 28, 41,…
#> $ gender                 <chr> "Male", "Female", "Female", "Non-binary", "Fema…
#> $ employment_status      <chr> "Employed", "Student", "Employed", "Self-employ…
#> $ work_environment       <chr> "On-site", "On-site", "On-site", "On-site", "On…
#> $ mental_health_history  <chr> "Yes", "No", "Yes", "No", "Yes", "Yes", "No", "…
#> $ seeks_treatment        <chr> "Yes", "Yes", "No", "No", "Yes", "Yes", "Yes", …
#> $ stress_level           <int> 6, 10, 7, 4, 3, 3, 2, 8, 7, 8, 6, 10, 10, 5, 1,…
#> $ sleep_hours            <dbl> 6.2, 9.0, 7.7, 4.5, 5.4, 9.9, 5.5, 7.1, 6.5, 3.…
#> $ physical_activity_days <int> 3, 4, 2, 4, 0, 3, 1, 5, 6, 0, 2, 7, 1, 6, 1, 3,…
#> $ depression_score       <int> 28, 30, 24, 6, 24, 17, 25, 25, 28, 7, 14, 13, 1…
#> $ anxiety_score          <int> 17, 11, 7, 0, 12, 9, 3, 8, 6, 18, 9, 2, 17, 7, …
#> $ social_support_score   <int> 54, 85, 62, 95, 70, 63, 87, 72, 46, 88, 85, 23,…
#> $ productivity_score     <dbl> 59.7, 54.9, 61.3, 97.0, 69.0, 69.3, 63.1, 58.4,…
#> $ mental_health_risk     <chr> "High", "High", "Medium", "Low", "High", "Mediu…

Dari hasil pembacaan dataset di atas, terdapat 10.000 data observasi dengan 14 kolom. Adapun untuk penjelasan masing-masing kolom adalah sebagai berikut.

  • age : Usia responden dalam tahun.
  • gender : Identitas gender responden.
  • employment_status : Status pekerjaan saat ini.
  • work_environment : Metode pelaksanaan pekerjaan masing-masing responden.
  • mental_health_history : Riwayat kesehatan mental.
  • seeks_treatment : Melakukan usaha untuk mencari pengobatan terhadap kesehatan mental.
  • stress_level : Level stress responden.
  • sleep_hours : Jumlah jam tidur responden.
  • physical_activity_days : Jumlah hari dalam melakukan aktivitas fisik.
  • depression_score : Nilai rating untuk kondisi depresi.
  • anxiety_score : Nilai rating untuk kondisi anxiety.
  • social_support_score : Nilai rating untuk Support Sosial yang dimiliki.
  • productivity_score : Nilai rating untuk produktivitas.
  • mental_health_risk : Risiko akan masalah kesehatan mental.

3 Data Cleansing

Karena masih terdapat beberapa kolom yang belum sesuai dengan tipe datanya maka perlu melakukan penyesuaian tipe data.

mental_clean <- mental %>% 
  mutate_at(vars(sleep_hours, productivity_score), as.numeric) %>%
  mutate_at(vars(gender, employment_status, work_environment, mental_health_history, seeks_treatment, mental_health_risk), as.factor)

Kemudian kita akan mengecek apakah terdapat Missing Value pada dataset kita.

mental_clean %>% is.na() %>% colSums()
#>                    age                 gender      employment_status 
#>                      0                      0                      0 
#>       work_environment  mental_health_history        seeks_treatment 
#>                      0                      0                      0 
#>           stress_level            sleep_hours physical_activity_days 
#>                      0                      0                      0 
#>       depression_score          anxiety_score   social_support_score 
#>                      0                      0                      0 
#>     productivity_score     mental_health_risk 
#>                      0                      0

4 Exploratory Data Analysis

Apakah antar variable memiliki skala yang sama? Mari kita cek range untuk tiap kolom.

mental_clean %>%
  select_if(is.numeric) %>% 
  summary
#>       age         stress_level     sleep_hours     physical_activity_days
#>  Min.   :18.00   Min.   : 1.000   Min.   : 3.000   Min.   :0.000         
#>  1st Qu.:30.00   1st Qu.: 3.000   1st Qu.: 5.500   1st Qu.:2.000         
#>  Median :41.50   Median : 6.000   Median : 6.500   Median :4.000         
#>  Mean   :41.56   Mean   : 5.572   Mean   : 6.473   Mean   :3.506         
#>  3rd Qu.:53.00   3rd Qu.: 8.000   3rd Qu.: 7.500   3rd Qu.:5.000         
#>  Max.   :65.00   Max.   :10.000   Max.   :10.000   Max.   :7.000         
#>  depression_score anxiety_score   social_support_score productivity_score
#>  Min.   : 0.00    Min.   : 0.00   Min.   :  0.00       Min.   : 42.80    
#>  1st Qu.: 7.00    1st Qu.: 5.00   1st Qu.: 25.00       1st Qu.: 65.80    
#>  Median :15.00    Median :11.00   Median : 50.00       Median : 77.60    
#>  Mean   :15.04    Mean   :10.56   Mean   : 50.12       Mean   : 77.31    
#>  3rd Qu.:23.00    3rd Qu.:16.00   3rd Qu.: 76.00       3rd Qu.: 89.20    
#>  Max.   :30.00    Max.   :21.00   Max.   :100.00       Max.   :100.00

Dari hasil pengecekan di atas, range dari masing-masing kolom numerik memiliki skala yang berbeda. Hal ini dapat memengaruhi hasil clustering analysis nantinya sehingga kita perlu melakukan scaling.

mental_scale <- scale(mental_clean %>%
  select_if(is.numeric))
summary(mental_scale)
#>       age             stress_level      sleep_hours      
#>  Min.   :-1.713332   Min.   :-1.5832   Min.   :-2.35626  
#>  1st Qu.:-0.840578   1st Qu.:-0.8907   1st Qu.:-0.66013  
#>  Median :-0.004189   Median : 0.1482   Median : 0.01832  
#>  Mean   : 0.000000   Mean   : 0.0000   Mean   : 0.00000  
#>  3rd Qu.: 0.832200   3rd Qu.: 0.8408   3rd Qu.: 0.69677  
#>  Max.   : 1.704954   Max.   : 1.5334   Max.   : 2.39290  
#>  physical_activity_days depression_score    anxiety_score     
#>  Min.   :-1.5357        Min.   :-1.672803   Min.   :-1.67047  
#>  1st Qu.:-0.6596        1st Qu.:-0.894232   1st Qu.:-0.87966  
#>  Median : 0.2165        Median :-0.004438   Median : 0.06931  
#>  Mean   : 0.0000        Mean   : 0.000000   Mean   : 0.00000  
#>  3rd Qu.: 0.6546        3rd Qu.: 0.885357   3rd Qu.: 0.86012  
#>  Max.   : 1.5308        Max.   : 1.663927   Max.   : 1.65092  
#>  social_support_score productivity_score
#>  Min.   :-1.714640    Min.   :-2.45443  
#>  1st Qu.:-0.859334    1st Qu.:-0.81872  
#>  Median :-0.004027    Median : 0.02047  
#>  Mean   : 0.000000    Mean   : 0.00000  
#>  3rd Qu.: 0.885492    3rd Qu.: 0.84543  
#>  Max.   : 1.706587    Max.   : 1.61350

5 Data Preprocessing

Dalam tahap Data Preprocessing ini kita akan melakukan pemisahan data numerik dan data non-numerik karena pada saat melakukan PCA (Principal Component Analysis) hanya dapat diterapkan pada data numerik sehingga data non-numerik perlu diproses atau diubah menjadi bentuk numerik.

Kenapa data non-numerik harus diubah ke data numerik karena jika data non-numerik digabungkan dengan data numerik, algoritma PCA dapat memberikan bobot yang tidak pantas pada data non-numerik, yang dapat menyesatkan hasil analisis.

Dengan mengikutsertakan data non-numerik ke dalam analisis dapat membantu memahami kelompok atau klasifikasi dalam data setelah PCA diterapkan, memberikan konteks tambahan terhadap distribusi titik-titik data.

# nama kolom numerik (quantitative)
quantiy <- mental_clean %>% 
  select_if(is.numeric) %>% 
  colnames()

# indeks kolom numerik
quantiyvar <- which(colnames(mental_clean) %in% quantiy)

# nama kolom kategorik (qualitative)
qualiy <- mental_clean %>% 
  select_if(is.factor) %>% 
  colnames()

# indeks kolom kategorik
qualiyvar <- which(colnames(mental_clean) %in% qualiy)

6 Clustering

Clustering adalah pengelompokan data berdasarkan karakteristiknya. Clustering bertujuan untuk menghasilkan cluster dimana:

  • tiap observasi di 1 cluster yang sama yang memiliki karakteristik yang mirip
  • tiap observasi dari cluster yang berbeda memiliki karakteristik yang berbeda.

Kita bisa menggunakan K-means Clustering untuk pendekatan ini.

6.1 K-means Clustering

K-means adalah salah satu algoritma clustering yang centroid-based, artinya tiap cluster memiliki satu centroid yang mewakili cluster tersebut. Banyaknya cluster \(k\) ditentukan oleh user.

6.1.1 Pemilihan k Optimum

Penentuan nilai k yang optimum menggunakan methode Elbow dimana metode ini memperhitungkan Within Sum of Squares ($withinss) yaitu jumlah jarak kuadrat dari tiap observasi ke centroid tiap cluster. Interpretasinya adalah k yang optimum dipilih ketika nilai \(k\) ditambah, penurunan Total WSS tidak terlalu drastis (atau dapat dikatakan melandai).

fviz_nbclust(mental_scale, FUNcluster = kmeans, method = "wss")

Dari hasil visualisasi metode Elbow di atas, penurunan WSS melandai ketika k berada di angka 3 sehingga kita akan menggunakan nilai k = 3.

6.1.2 K-means

# k-means dengan 3 cluster
RNGkind(sample.kind = "Rounding")
set.seed(100)

mental_km <- kmeans(x = mental_scale, # data yang sudah di scaling
                    centers = 3) # jumlah k (cluster yang diinginkan)
# memasukkan label cluster ke data awal dengan nama kelompok
mental$kelompok1 <- as.factor(mental_km$cluster)
mental
# clustering visualization
fviz_cluster(object = mental_km, 
             data = mental_scale)

# cluster profiling
mental %>%
  group_by(kelompok1) %>% 
  summarise_all(.funs = "mean") %>% 
  select(-c(gender, employment_status, work_environment, mental_health_history, seeks_treatment, mental_health_risk))

Dari hasil profiling di atas, kita dapatkan sebuah insight:

  • Cluster 1 : Memiliki skor social support yang rata-rata dan memiliki skor anxiety yang tinggi, namun di sisi lain memiliki skor depresi rendah dan produktivitas yang tinggi.
  • Cluster 2 : Memiliki skor social support yang rata-rata dan memiliki skor anxiety yang rata-rata, namun di sisi lain memiliki skor depresi tinggi dan produktivitas yang cukup rendah.
  • Cluster 3 : Memiliki skor social support yang rata-rata dan memiliki skor anxiety yang rendah, namun di sisi lain memiliki skor depresi rendah dan produktivitas yang tinggi.

7 Principal Component Analysis (PCA)

Ide dasar dari PCA adalah untuk membuat sumbu (axis) baru yang dapat menangkap variasi data sebanyak mungkin. Sumbu baru ini adalah yang dinamakan sebagai Principal Component (PC).

# melakukan PCA dengan FactoMineR
mental_pca <- PCA(X = mental_clean, # data awal
                scale.unit = T, # scaling
                quali.sup = qualiyvar, # index kolom qualitative
                graph = F, # tidak menampilkan graph
                ncp = 8) # jumlah PC atau jumlah kolom numerik dari data awal

7.1 Visualize High Dimensional Data

Hasil PCA dapat kita visualisasikan untuk memahami pola hubungan antara variabel dan individu menggunakan biplot. Biplot (dua plot) adalah grafik yang menggambarkan posisi variabel dan individu dalam satu plot.

Karena plot yang akan dibuat hanya bisa 2 dimensi sehingga PC yang dapat divisualisasikan hanyalah PC1 dan PC2 saja.

plot.PCA(mental_pca)

Dari hasil pembuatan biplot yang berisi posisi variabel dan posisi individu di atas sulit untuk digunakan dalam pengambilan insight. Maka kita akan membagi plot tersebut menjadi 2 plot yaitu plot individual serta plot variabel.

7.1.1 Individual Factor Map

Plot yang menunjukkan posisi setiap individu atau observasi data dalam analisis PCA, yang membantu kita mengidentifikasi pencilan (outlier) dan melihat pola hubungan antara individu dalam dataset.

plot.PCA(x = mental_pca, # objek PCA
         choix = "ind", # pilihan untuk menampilkan visualisasi individu
         invisible = "quali", # untuk menghilangkan nama variabel, karena mengganggu visual
         select = "contrib 5", # jumlah outlier yang ditampilkan
         habillage = "mental_health_risk" # opsional: untuk mewarnai titik observasi berdasarkan category
         )

Dari hasil visualisasi di atas 5 responden yang menjadi outlier adalah responden dengan baris observasi : 964, 3066, 6353, 7495 dan 8701. Namun dengan melihat sebaran data secara keseluruhan, outlier tersebut masih terbilang normal karena masih dekat dengan mayoritas data.

7.1.2 Variables Factor Map

Dengan plot ini kita bisa mengetahui kontribusi variabel ke tiap PC dan seberapa banyak informasi yang dijelaskan oleh setiap variabel ke setiap PC. Serta dapat Mengetahui correlation antar variable awal.

plot.PCA(x = mental_pca,
         choix = "var")

Insight yang didapat dari plot di atas adalah:

  • PC1 paling banyak merangkum 2 variabel yaitu depression_score dan productivity_score. Dan jika melihat arah panah dari masing-masing variabel yang bertolak belakang (180 derajat), hal tersebut menandakan kedua variabel memiliki korelasi negatif.
  • PC2 paling banyak merangkum variabel numeric selain depression_score dan productivity_score. Namun dari plot di atas terdapat hal yang menjadi sorotan yaitu panjang panah dari masing-masing yang berbeda-beda, hal tersebut menjadi paramter untuk menentukan besarnya kontribusi masing-masing variabel terhadap PC. Untuk lebih jelasnya bisa divisualisasikan dengan fviz_contrib().
  • Antara variabel yang ada di PC1 dan PC2 tidak memiliki korelasi karena sudut yang dibuat antar panah membentuk sudut 90 derajat.
fviz_contrib(X = mental_pca, axes = 2, choice = "var")

Dari hasil visualisasi menggunakan fviz_contrib() di atas, variabel yang berkontribusi terhadap PC adalah variabel yang jumlahnya melewati batas nilai kontribusi yang diharapkan (Garis horizontal putus-putus merah). Terdapat 3 variabel yang berkontribusi terhadap PC2 yaitu anxiety_score, age dan social_support_score.

7.2 Dimensionality Reduction

Untuk mereduksi jumlah kolom dalam data, kita akan menggunakan hasil PCA, yaitu mental_pca$ind$coord. Kita akan memanipulasi data ini dengan menghapus beberapa kolomnya.

mental_pca$ind$coord %>% as.data.frame()

Adapun untuk langkah-langkah melakukan reduksi dimensi dari hasil PCA adalah sebagai berikut.

1️⃣ Lihat Eigenvalues: Periksa nilai eigenvalues dari $eig untuk semua PC.

# menampilkan cummulative proportion variance/eigen value
mental_pca$eig
#>        eigenvalue percentage of variance cumulative percentage of variance
#> comp 1 1.93972016             24.2465020                          24.24650
#> comp 2 1.02839009             12.8548761                          37.10138
#> comp 3 1.02041883             12.7552354                          49.85661
#> comp 4 1.01366270             12.6707837                          62.52740
#> comp 5 0.99764543             12.4705679                          74.99797
#> comp 6 0.99124380             12.3905475                          87.38851
#> comp 7 0.94810242             11.8512803                          99.23979
#> comp 8 0.06081658              0.7602072                         100.00000

2️⃣ Tentukan Jumlah PC: Pilih jumlah PC yang menjelaskan proporsi kumulatif variasi yang cukup besar.

Kita perlu mereduksi kolom dari belakang. Untuk mengetahui berapa banyak kolom yang perlu direduksi, kita bisa melihat seberapa banyak kumulatif variasi yang dijelaskan secara total oleh setiap variabel.

Kita ingin mempertahankan informasi minimal 80%, maka PC yang kita gunakan adalah PC 1 - 6 karena pada PC tersebut kumulatif variansi yang ditangkap sebesar 87%.

3️⃣ Reduksi Dimensi: Subset PC terpilih untuk mereduksi dimensi.

# mengambil data hasil PCA sebanyak PC yang dibutuhkan
mental_keep <- mental_pca$ind$coord[ , 1:6 ] %>% as.data.frame()
mental_keep

Yang selanjutnya data gabungan tersebut yaitu mental_keep bisa digunakan untuk pemodelan menggunakan salah satu algoritma supervised learning sesuai dengan dataset tersebut.

8 Conclusion

Kita bisa menarik beberapa kesimpulan dari clustering analysis dan principle component analysis sebelumnya antara lain:

  • Pengelompokan K-means dapat dilakukan menggunakan kumpulan data ini, meskipun, pengelompokan tersebut tidak menyerupai mental health risk. K-means mengelompokan responden berdasarkan skor anxiety mereka, dari ketiga kelompok tersebut bisa dilihat bahwa skor depresi berpengaruh berbanding lurus dengan skor produktivitas.
  • Dimensionality reduction sebenarnya kurang berpengaruh dilakukan terhadap dataset yang ada karena antar variabel hampir semuanya tidak memiliki korelasi. Sehingga kurang tepat melakukan principle component analysis. Hal tersebut dibuktikan juga dengan variansi yang ditangkap hampir sama di setiap PC.

Berikut 3D-plot Visualization for Multidimentional Data terhadap PCA.

mental_xc <- cbind(mental_keep, cluster = mental$kelompok1)

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