Stress Level Project

Introduction

Sejak pandemi COVID-19 yang terjadi pada tahun 2020, sistem pembelajaran beralih ke pembelajaran jarak jauh (PJJ). Selama PJJ, penelitian menunjukkan 50,5% pelajar mengalami stres berat (E-Journal Kemkes).

Setelah pandemi COVID-19 sudah mereda dan pembelajaran sudah kembali luring, masalah kesehatan mental pada pelajar masih terus berlanjut. Hasil Survei I-NAMHS menunjukkan 1 dari 3 remaja memilki masalah kesehatan mental (UGM News). Oleh sebab itu, menganalisis faktor yang menjadi alasan pelajar mengalami gangguan mental atau stres perlu dianalisis sehingga dapat dilakukan langkah untuk menangani hal tersebut.

Pada kesempatan kali ini, kita akan mencoba menganalisis beberapa faktor yang dapat berpengaruh kepada tingkat stres pelajar menggunakan dataset yang didapat dari Kaggle. Selanjutnya, kita akan membuat model machine learning untuk memprediksi tingkat stres pelajar berdasarkan faktor - faktor penyebab stres yang tersedia.

Preparation

Libraries

library(rmarkdown)
library(dplyr)
library(inspectdf)
library(ggplot2)
library(glue)
library(plotly)
library(caret)
library(e1071)
library(partykit)
library(pROC)

Import Dataset

Data yang digunakan merupakan data faktor - faktor yang dapat mempengaruhi tingkat stress pelajar. Data tersebut diambil dari Kaggle: Student Stress Factors by CHHABII. Model machine learning yang akan dibuat berguna untuk memprediksi tingkat stres pelajar berdasarkan faktor - faktor yang ada. Target variabel pada data ini adalah ‘stress_level’ yang memiliki kelas tingkatan stres siswa dari level 0 sampai level 2.

stres <- read.csv("data_input/StressLevelDataset.csv")
paged_table(head(stres, 10))

Data Description

  • anxiety_level : tingkat rasa cemas (skala: 1 - 21).
  • self_esteem : tingkat penghargaan terhadap diri sendiri (skala: 1 - 30).
  • mental_health_history : riwayat kesehatan mental (0: No, 1: Yes).
  • depression : tingkat depresi (skala: 1 - 27).
  • headache : tingkat sakit kepala (skala: 1 - 5).
  • blood_pressure : tingkat tekanan darah (skala: 1 - 3).
  • sleep_quality : tingkat kualitas tidur (skala: 0 - 5).
  • breathing_problem : tingkat gangguan pernapasan (skala: 0 - 5).
  • noise_level : tingkat kebisingan di lingkungan sekitar (skala: 0 - 5).
  • living_conditions : tingkat kondisi hidup (skala: 0 - 5).
  • safety: tingkat keamanan (skala: 0 - 5).
  • basic_needs: tingkat kebutuhan dasar (skala: 0 -5).
  • academic_performance: tingkat performa akademik (skala: 0 - 5).
  • study_load : tingkat beban studi (skala: 0 - 5).
  • teacher_student_relationship : tingkat hubungan guru dengan siswa (skala: 0 - 5).
  • future_career_concerns : tingkat kekhawatiran akan karir masa depan (skala: 0 -5).
  • social_support : tingkat dukungan sosial (skala: 0 - 3).
  • peer_pressure : tingkat tekanan dari teman sebaya (skala: 0 - 5).
  • extracurricular_activities : tingkat aktivitas ekstrakurikuler (skala: 0 - 5).
  • bullying : tingkat bullying (skala: 0 - 5).
  • stress_level : tingkat stress (skala: 0 - 2).

Data Wrangling

Pada dataset ini, terdapat tiga kolom yang akan diubah menjadi kategori berdasarkan skala - skala tertentu. Ketiga kolom tersebut adalah anxiety_level, self_esteem, dan depression.

Pertama, skala tingkat anxiety akan merujuk pada Generalized Anxiety Disorder 7-item (GAD-7).

Kedua, skala tingkat depresi akan merujuk pada Patient Health Questionnaire-9 (PHQ-9).

Ketiga, skala tingkat self esteem akan merujuk pada Rosenberg’s Self-Esteem Scale.

Kemudian, ketiga kolom tersebut akan diubah dan disesuaikan menjadi kategori - kategori berdasarkan skala - skala yang telah disebutkan di atas.

stres$anxiety_level <- ifelse(stres$anxiety_level < 5, "Minimal",
                       ifelse(stres$anxiety_level >=5 & stres$anxiety_level < 10, "Mild",
                       ifelse(stres$anxiety_level >=10 & stres$anxiety_level < 15, "Moderate", "Severe")))

stres$depression <- ifelse(stres$depression < 5, "None-Minimal",
                    ifelse(stres$depression >=5 & stres$depression < 10, "Mild",
                    ifelse(stres$depression >=10 & stres$depression < 15, "Moderate",
                    ifelse(stres$depression >=15 & stres$depression < 20, "Moderately Severe", "Severe"))))

stres$self_esteem <- ifelse(stres$self_esteem < 15, "Low",
                     ifelse(stres$self_esteem >=15 & stres$self_esteem <= 25, "Normal", "High"))

Exploratory Data Analysis (EDA)

Sebelum melakukan eksplorasi data lebih lanjut, kelengkapan data perlu untuk diperiksa terlebih dahulu apakah ada missing value atau tidak.

Missing Value Check

colSums(is.na(stres))
#>                anxiety_level                  self_esteem 
#>                            0                            0 
#>        mental_health_history                   depression 
#>                            0                            0 
#>                     headache               blood_pressure 
#>                            0                            0 
#>                sleep_quality            breathing_problem 
#>                            0                            0 
#>                  noise_level            living_conditions 
#>                            0                            0 
#>                       safety                  basic_needs 
#>                            0                            0 
#>         academic_performance                   study_load 
#>                            0                            0 
#> teacher_student_relationship       future_career_concerns 
#>                            0                            0 
#>               social_support                peer_pressure 
#>                            0                            0 
#>   extracurricular_activities                     bullying 
#>                            0                            0 
#>                 stress_level 
#>                            0

Tidak terdapat data yang hilang (missing value) pada dataset dan dataset siap dilakukan eksplorasi lebih lanjut.

Structure Data Check

Untuk melakukan pengecekan struktur pada dataset, dapat digunakan fungsi glimpse dari package dplyr.

glimpse(stres)
#> Rows: 1,100
#> Columns: 21
#> $ anxiety_level                <chr> "Moderate", "Severe", "Moderate", "Severe…
#> $ self_esteem                  <chr> "Normal", "Low", "Normal", "Low", "High",…
#> $ mental_health_history        <int> 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1,…
#> $ depression                   <chr> "Moderate", "Moderately Severe", "Moderat…
#> $ headache                     <int> 2, 5, 2, 4, 2, 3, 1, 4, 3, 4, 4, 3, 1, 4,…
#> $ blood_pressure               <int> 1, 3, 1, 3, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3,…
#> $ sleep_quality                <int> 2, 1, 2, 1, 5, 1, 4, 1, 2, 1, 1, 1, 4, 1,…
#> $ breathing_problem            <int> 4, 4, 2, 3, 1, 4, 1, 5, 4, 2, 3, 5, 2, 0,…
#> $ noise_level                  <int> 2, 3, 2, 4, 3, 3, 1, 3, 3, 0, 4, 5, 2, 1,…
#> $ living_conditions            <int> 3, 1, 2, 2, 2, 2, 4, 1, 3, 5, 2, 2, 3, 2,…
#> $ safety                       <int> 3, 2, 3, 2, 4, 2, 4, 1, 3, 2, 1, 1, 5, 4,…
#> $ basic_needs                  <int> 2, 2, 2, 2, 3, 1, 4, 1, 3, 2, 1, 1, 5, 3,…
#> $ academic_performance         <int> 3, 1, 2, 2, 4, 2, 5, 1, 3, 2, 1, 1, 5, 1,…
#> $ study_load                   <int> 2, 4, 3, 4, 3, 5, 1, 3, 3, 2, 3, 3, 2, 2,…
#> $ teacher_student_relationship <int> 3, 1, 3, 1, 1, 2, 4, 2, 2, 1, 1, 1, 4, 3,…
#> $ future_career_concerns       <int> 3, 5, 2, 4, 2, 5, 1, 4, 3, 5, 4, 4, 1, 3,…
#> $ social_support               <int> 2, 1, 2, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 0,…
#> $ peer_pressure                <int> 3, 4, 3, 4, 5, 4, 2, 4, 3, 5, 4, 5, 1, 1,…
#> $ extracurricular_activities   <int> 3, 5, 2, 4, 0, 4, 2, 4, 2, 3, 4, 5, 1, 0,…
#> $ bullying                     <int> 2, 5, 2, 5, 5, 5, 1, 5, 2, 4, 5, 4, 1, 1,…
#> $ stress_level                 <int> 1, 2, 1, 2, 1, 2, 0, 2, 1, 1, 2, 2, 0, 2,…

Dataset memiliki 1100 baris data dan 21 kolom. Tipe data setiap kolom dapat diubah menjadi tipe factor melihat dari dataset memiliki jumlah kelas yang tergolong sedikit, yaitu 2 sampai 6 kelas. Setelah mengubah tipe data, level kelas pada kolom anxiety_level, self_esteem, dan depression diatur dari kelas terkecil ke tertinggi.

# Mengubah tipe data
stres <- stres %>%
  mutate_all(as.factor)

# Mengatur level pada kolom
stres$anxiety_level <- factor(stres$anxiety_level, levels=c("Minimal", "Mild", "Moderate", "Severe"))
stres$self_esteem <- factor(stres$self_esteem, levels=c("Low", "Normal", "High"))
stres$depression <- factor(stres$depression, levels=c("None-Minimal", "Mild", "Moderate", "Moderately Severe", "Severe"))

glimpse(stres)
#> Rows: 1,100
#> Columns: 21
#> $ anxiety_level                <fct> Moderate, Severe, Moderate, Severe, Sever…
#> $ self_esteem                  <fct> Normal, Low, Normal, Low, High, Low, High…
#> $ mental_health_history        <fct> 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1,…
#> $ depression                   <fct> Moderate, Moderately Severe, Moderate, Mo…
#> $ headache                     <fct> 2, 5, 2, 4, 2, 3, 1, 4, 3, 4, 4, 3, 1, 4,…
#> $ blood_pressure               <fct> 1, 3, 1, 3, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3,…
#> $ sleep_quality                <fct> 2, 1, 2, 1, 5, 1, 4, 1, 2, 1, 1, 1, 4, 1,…
#> $ breathing_problem            <fct> 4, 4, 2, 3, 1, 4, 1, 5, 4, 2, 3, 5, 2, 0,…
#> $ noise_level                  <fct> 2, 3, 2, 4, 3, 3, 1, 3, 3, 0, 4, 5, 2, 1,…
#> $ living_conditions            <fct> 3, 1, 2, 2, 2, 2, 4, 1, 3, 5, 2, 2, 3, 2,…
#> $ safety                       <fct> 3, 2, 3, 2, 4, 2, 4, 1, 3, 2, 1, 1, 5, 4,…
#> $ basic_needs                  <fct> 2, 2, 2, 2, 3, 1, 4, 1, 3, 2, 1, 1, 5, 3,…
#> $ academic_performance         <fct> 3, 1, 2, 2, 4, 2, 5, 1, 3, 2, 1, 1, 5, 1,…
#> $ study_load                   <fct> 2, 4, 3, 4, 3, 5, 1, 3, 3, 2, 3, 3, 2, 2,…
#> $ teacher_student_relationship <fct> 3, 1, 3, 1, 1, 2, 4, 2, 2, 1, 1, 1, 4, 3,…
#> $ future_career_concerns       <fct> 3, 5, 2, 4, 2, 5, 1, 4, 3, 5, 4, 4, 1, 3,…
#> $ social_support               <fct> 2, 1, 2, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 0,…
#> $ peer_pressure                <fct> 3, 4, 3, 4, 5, 4, 2, 4, 3, 5, 4, 5, 1, 1,…
#> $ extracurricular_activities   <fct> 3, 5, 2, 4, 0, 4, 2, 4, 2, 3, 4, 5, 1, 0,…
#> $ bullying                     <fct> 2, 5, 2, 5, 5, 5, 1, 5, 2, 4, 5, 4, 1, 1,…
#> $ stress_level                 <fct> 1, 2, 1, 2, 1, 2, 0, 2, 1, 1, 2, 2, 0, 2,…

Struktur data sudah sesuai menjadi factor dan level factor untuk kolom ‘anxiety_level’, ‘self_esteem’, dan ‘depression’ sudah diatur berurutan dari tingkatan terkecil ke tertinggi.

Data Summary

Selanjutnya, kita dapat mengetahui proporsi kelas pada setiap variabel kategori dengan menggunakan fungsi inspect_cat dari package inspectdf seperti berikut:

Berdasarkan plot tersebut, beberapa insights yang dapat diambil adalah proporsi kelas target stress_level cukup seimbang untuk tiap kelasnya. Selain itu, untuk variabel lainnya tidak dapat dikatakan cukup seimbang untuk setiap kelasnya, kecuali kelas 0 untuk beberapa variabel.

Selanjutnya, kita akan mencoba untuk melihat korelasi antara variabel anxiety_level terhadap variabel target stress_level. Plot kita lakukan dengan menggunakan fungsi ggplot dari library ggplot2 dan fungsi ggplotly dari library plotly.

Dari plot tersebut, tingkat anxiety cenderung berbanding lurus dengan tingkat stres pelajar. Ketika tingkat anxiety semakin meningkat maka tingkat stres juga cenderung untuk meningkat. Selanjutnya, kita juga akan melihat korelasi antara riwayat terkait kesehatan mental dengan tingkatan stres menggunakan fungsi yang sama dengan plot sebelumnya.

Dari plot tersebut, pelajar yang tidak memiliki riwayat terkait kesehatan mental cenderung memiliki tingkat stres yang lebih rendah. Sementara itu, pelajar yang memilki riwayat terkait kesehatan mental cenderung memiliki tingkat stres yang lebih tinggi.

Modelling

Naive-Bayes Model

Model machine learning yang akan digunakan kali ini adalah Naive-Bayes Model. Model Naive Bayes adalah metode klasifikasi yang didasari oleh Bayes’ Theorem of Probability dan merupakan salah satu model yang sering dipakai. Model Naive-Bayes baik digunakan untuk dataset yang memiliki variabel prediktor bertipe factor. Karakteristik Naive Bayes memiliki 2 asumsi, yaitu:

  1. Variabel target dependen terhadap variabel - variabel prediktornya.
  2. Hubungan antar variabel prediktor adalah independen.

Cross-Validation

Sebelum melakukan pemodelan, kita perlu membagi dataset menjadi data train dan data test. Proporsi yang akan digunakan adalah 80% untuk data train dan 20% untuk data test. Data train akan digunakan untuk membangun model dan data test akan digunakan untuk melakukan evaluasi model nantinya.

RNGkind(sample.kind = "Rounding") 
set.seed(172)

# Train-Test Splitting
index <- sample(x = nrow(stres), size= nrow(stres)*0.8)
stres_train <- stres[index, ] 
stres_test <- stres[-index, ]

Lalu, kita memeriksa proporsi tiap kelas pada variabel target stress_level. Hasil menunjukkan proporsinya untuk tiap kelasnya sudah cukup seimbang.

prop.table(table(stres_train$stress_level))
#> 
#>      0      1      2 
#> 0.3375 0.3250 0.3375

Model Fitting

Pemodelan Naive-Bayes dilakukan terhadap data train dengan menggunakan fungsi naiveBayes dari library e1071. Pemodelan disimpan pada object model_nb.

model_nb <- naiveBayes(formula = stress_level ~ ., data = stres_train)

Predict

Setelah model sudah terbuat, dilakukan prediksi terhadap data test dengan model_nb menggunakan fungsi predict.

nb_pred <- predict(object = model_nb, newdata = stres_test, type = "class")

Evaluation

Confusion Matrix

confusionMatrix(data = nb_pred,
                reference = stres_test$stress_level,
                positive = "2")
#> Confusion Matrix and Statistics
#> 
#>           Reference
#> Prediction  0  1  2
#>          0 64  4  2
#>          1  4 63  2
#>          2  8  5 68
#> 
#> Overall Statistics
#>                                           
#>                Accuracy : 0.8864          
#>                  95% CI : (0.8368, 0.9251)
#>     No Information Rate : 0.3455          
#>     P-Value [Acc > NIR] : <2e-16          
#>                                           
#>                   Kappa : 0.8296          
#>                                           
#>  Mcnemar's Test P-Value : 0.1804          
#> 
#> Statistics by Class:
#> 
#>                      Class: 0 Class: 1 Class: 2
#> Sensitivity            0.8421   0.8750   0.9444
#> Specificity            0.9583   0.9595   0.9122
#> Pos Pred Value         0.9143   0.9130   0.8395
#> Neg Pred Value         0.9200   0.9404   0.9712
#> Prevalence             0.3455   0.3273   0.3273
#> Detection Rate         0.2909   0.2864   0.3091
#> Detection Prevalence   0.3182   0.3136   0.3682
#> Balanced Accuracy      0.9002   0.9172   0.9283

Untuk melihat seberapa baik model_nb secara keseluruhan, kita dapat melihat melalui metrik akurasi. Hasil confusion matrix menunjukkan model_nb memiliki akurasi sebesar 88.64%. Selain itu, metrik lain yang penting dalam memprediksi tingkat stres pelajar adalah Sensitivity atau Recall. Metrik Sensitivity penting karena kondisi False Negative (FN) menjadi concern pada kasus ini. Kondisi False Negative dari kelas 2 adalah ketika pelajar diprediksi memiliki tingkat stres kelas 0 atau kelas 1, namun aktualnya memiliki tingkat stres kelas 2. Metrik Sensitivity pada kelas 2 sebesar 94,44%. Berdasarkan kedua metrik tersebut, model ini dapat dikatakan sebagai model dengan performa yang baik.

ROC and AUC

Selain menggunakan Confusion Matrix, kita juga dapat menggunakan Receiver-Operating Curve (ROC) dan Area Under Curve (AUC) untuk melakukan evaluasi model. ROC merupakan kurva yang menggambarkan hubungan antara True Positive Rate dengan False Positive Rate untuk setiap ambang atau threshold. Model dengan performa yang baik idealnya memiliki True Positive Rate yang tinggi dan False Positive Rate yang rendah. Sementara itu, AUC adalah luas area di bawah kurva. Semakin mendekati nilai 1, performa model semakin baik.

Hasil menunjukkan nilai AUC untuk setiap hubungan antar kelas mendekati nilai 1. Hal ini menunjukkan model_nb sudah cukup baik untuk memprediksi variabel target stress_level berdasarkan faktor - faktor yang ada.

Conclusion

Model Naive-Bayes yang dibuat (model_nb) merupakan model yang cukup baik dalam memprediksi tingkat stres pelajar berdasarkan faktor - faktor penyebab stres yang ada. Performa yang baik dari model ini terlihat dari metrik akurasi yang bernilai 88,64% dan metrik sensitivity yang bernilai 94,44%. Dengan hasil pemodelan ini, harapannya dapat dijadikan salah satu tools atau pertimbangan untuk menentukan tingkat stres seorang pelajar sehingga dapat diberikan treatment atau penanganan yang tepat.