Bunuh diri merupakan suatu permasalahan yang saat ini dihadapi setiap negara yang ada di dunia. Menurut WHO (World Health Organization), lebih dari 700.000 orang meninggal akibat bunuh diri setiap tahun dengan korban berusia 15-29 tahun [1]. Bunuh diri dapat disebabkan karena berbagai permasalahan, seperti penyakit mental, peristiwa traumatis, dan lain sebagainya [2]. Bunuh diri dapat berakibat buruk bagi korban maupun orang yang terdekat dengan korban. Oleh karena itu perlu ada pencegahan sebelum hal tersebut terjadi.

Salah satu hal yang dapat mempengaruhi seseorang dalam mempunyai gagasan bunuh diri adalah sosial media. Sosial media merupakan sebuah platform yang digunakan oleh hampir seluruh masyarakat di dunia. Menurut We Are Social [3], setiap tahun pengguna sosial media meningkat dan pada tahun 2023, pengguna sosial media mencapai 4.76 miliar. Melihat jumlah tersebut, akan ada banyak media atau teks yang dibagikan oleh pengguna terkait dengan perasaan mereka, termasuk teks yang merepresentasikan pikiran seseorang tentang bunuh diri. Teks yang berkaitan dengan bunuh diri dapat mempengaruhi mental seseorang, baik dari sisi pembagi maupun dari sisi pembaca. Akibat dari postingan tersebut, mental si pembaca akan terpengaruh dengan adanya konten tersebut dan si pembagi tidak mendapatkan pertolongan dan akan terus berpikir tentang bunuh diri.

Oleh karena itu, dapat dilakukan analisis dan permodelan untuk memprediksi apakah sebuah teks mengandung pikiran atau gagasan bunuh diri atau tidak. Diharapkan dengan model dan analisis tersebut, dapat memberikan beberapa manfaat dari berbagai pihak, baik pihak perusahaan sosial media, pihak layanan kesehatan mental, pihak professional, dan pihak masyarakat.

Data Preparation

Deskripsi Dataset

Dataset yang digunakan adalah kumpulan post berbahasa inggris dari Reddit terkait dengan bunuh diri (berasal dari subreddit “SuicideWatch” and “depression”) yang sudah dilabeli dengan label suicide (mengandung unsur bunuh diri) dan non-suicide (tidak mengandung unsur bunuh diri). Dataset dapat diakses pada link berikut.

Library dan Read Dataset

Berikut ini adalah library digunakan dalam analisis data, pembangunan model, dan evaluasi model.

#library untuk pemrosesan dataframe dan EDA Sederhana
library(tidyverse)
library(dplyr)
library(readr)
library(ggplot2)

#library untuk pemrosesan dan analisis teks
library(tm)
library(textstem)
library(wordcloud)
library(textclean)
library(stringr)

#library untuk pembangunan dan evaluasi model
library(caret)
library(e1071)
library(partykit)
library(ROCR)
library(randomForest)
library(rpart)
library(rpart.plot)
library(rattle)

Kemudian dilakukan read data terlebih dahulu dalam file Suicide_Detection.csv

df <- read_csv("Suicide_Detection.csv")
df <- df %>%
  select(text,class)
head(df)

Keterangan Kolom

  • text : konten text
  • class: kelas (suicide/non-suicide)

Exploratory Data Analysis

Check Kelas Imbalance

Untuk memutuskan penanganan lanjutan, akan dilakukan pengecekan terlebih dahulu apakah distribusi kelas bersifat imbalance atau tidak.

freqs = as.data.frame(table(df$class))
colnames(freqs)<-c("Kelas","Jumlah_Teks")
ggplot(data = freqs, mapping = aes(x = Kelas, y = Jumlah_Teks)) +
  geom_col(aes(fill="pink")) + theme(legend.position = 'none')

Berdasarkan bar plot tersebut, terlihat bahwa kelas suicide dan non-suicide mempunyai jumlah kelas yang sama. Namun, karena keterbatasan resource, maka jumlah data akan dikurangi menjadi 20000 di setiap kelas, sehingga dalam markdown ini akan digunakan sebanyak 40000 data teks.

Downsampling

Untuk mengurangi jumlah data, dilakukan downsampling per kelas dengan cara sebagai berikut.

set.seed(100)
df_suicide <- df %>% filter(class %in% "suicide")
df_nonsuicide <- df %>% filter(class %in% "non-suicide")

df_suicide_sample <- df_suicide[sample(nrow(df_suicide), size=20000), ]
df_nonsuicide_sample <- df_nonsuicide[sample(nrow(df_nonsuicide), size=20000), ]

df_final <- rbind(df_suicide_sample, df_nonsuicide_sample)
df_fix <- df_final[sample(1:nrow(df_final)), ]

Kemudian, untuk keperluan analisis lanjutan, akan ditambahkan id teks untuk memudahkan subsetting.

df_fix <- cbind(id_text = rownames(df_fix), df_fix)
head(df_fix)

Bila ingin menggunakan teks hasil downsampling untuk pembangunan model bisa mengarah pada link berikut

Text Analysis

Dalam bagian ini, akan dilihat kata apa saja yang memicu pikiran bunuh diri dengan cara mengecek frekuensi kemunculan kata dalam data tersebut. Analisis teks akan dilakukan per kelasnya.

Text Preprocessing

Sebelum dilakukan analisis, teks perlu dilakukan preprocessing yang bertujuan untuk meminimalkan komponen yang tidak berpengaruh dalam analisis. Teknik preprocessing yang digunakan adalah sebagai berikut

  1. Preprocessing Lower Case
  2. Penghilangan teks URL dan HTML
  3. Penghilangan emoji
  4. Penghilangan tanda baca (punctuation)
  5. Penghilangan angka
  6. Lemmatisasi menggunakan library textstem
  7. Penghilangan kata stopwords, dalam markdown ini digunakan stopword bahasa inggris dari SMART (System for the Mechanical Analysis and Retrieval of Text) Information Retrieval System. Stopword SMART dapat dilihat pada link berikut

Pertama-tama, akan dilakukan penghapusan HTML dan URL terlebih dahulu. Kemudian dilakukan preprocessing lower case untuk membuat semua huruf menjadi huruf kecil. Setelah itu dilakukan penghapusan emoji. Penghapusan HTML dan URL dapat menggunakan library textclean, sedangkan untuk lower case dan penghapusan emoji menggunakan library stringr.

df_fix <- df_fix %>% mutate(cleaned =
  text %>%
    replace_html() %>% #penghapusan html
    replace_url() %>% #penghapusan url
    str_to_lower() %>% #lower case
    str_remove_all(pattern = '[:emoji:]') #penghapusan emoji
)

Kemudian, untuk beberapa preprocessing lain, yaitu penghilangan stopwords, tanda baca, angka, dan lematisasi dapat menggunakan library tm. Namun sebelumnya, kolom teks harus dijadikan format corpus terlebih dahulu.

#konversi menjadi korpus
df_fix.corpus <- VCorpus(VectorSource(df_fix$cleaned))

#fungsi untuk mengganti tanda baca dengan spasi, karena ada tanda baca yang menempel pada kata.
replacePunctuation <- content_transformer(function(x) {
  return (gsub("[[:punct:]]"," ", x))
  })

df_fix.corpus <- df_fix.corpus %>% 
  tm_map(removeWords, stopwords("SMART")) %>% #penghilangan stopwords
  tm_map(removeNumbers) %>% #penghilangan angka
  tm_map(replacePunctuation) %>% #penghilangan punctuation
  tm_map(stripWhitespace) %>% #penghilangan whitespace
  tm_map(content_transformer(lemmatize_strings)) %>% #lematisasi kata dengan textstem
  tm_map(removeWords, stopwords("SMART")) #penghilangan stopwords

Selanjutnya dilakukan pembangunan Document-Term Matrix, yaitu tabel berisikan frekuensi kemunculan kata per dokumen. Contoh Document-Term Matrix ditujukan pada gambar dibawah ini.

Frekuensi kata akan menjadi prediktor untuk model klasifikasi yang akan dibangun. Berikut ini adalah Document-Term Matrix yang sudah dibangun dari corpus yang telah dipreprocessing.

df_fix.dtm <- DocumentTermMatrix(df_fix.corpus)
inspect(df_fix.dtm)
## <<DocumentTermMatrix (documents: 40000, terms: 44266)>>
## Non-/sparse entries: 1235087/1769404913
## Sparsity           : 100%
## Maximal term length: 14616
## Weighting          : term frequency (tf)
## Sample             :
##        Terms
## Docs    day feel friend fuck life make people thing time year
##   16479   0    0      0    0    0    0      0     0    0    0
##   16961   0    0      0    0    0    0      0     0    0    0
##   18356   0    0      0 2520    0    0      0     0    0    0
##   21783  45    0      0    0   14   26      1    19    5   36
##   29040   0    0      0    0    0    0      0     0    0    0
##   30208  11   28     30    8   19   43     21    24   37   31
##   30747  11   17      9    5   13   13      3     9   17   10
##   32398   4   18      1   16   16   30     23    20   17   13
##   34983   6    4      3    0    9   10      2    11    7    4
##   39577  16   20     15    0   37   26     29    17   21    4

Analisis teks bunuh diri (kelas Suicide)

Berikut ini adalah hasil analisis teks yang memicu pikiran bunuh diri. Pertama, akan dilakukan filtering untuk teks yang berlabel suicide.

df_suicide <- df_fix %>% filter(class %in% "suicide")
suicide_terms <- df_fix.dtm[as.numeric(df_suicide$id_text),]

Kemudian, kita akan mencoba untuk menghitung frekuensi kemunculan kata di seluruh teks dengan menggunakan fungsi berikut ini.

terms_freq <- function(terms) {
  x <- as.matrix(terms)
  v <- sort(colSums(x), decreasing=TRUE)
  d <- data.frame(word = names(v), freq=v)
  rm(x)
  return (d)
}

Berikut ini adalah visualisasi wordcloud dari frekuensi kata yang muncul pada kelas suicide. Kata yang ditampilkan mempunyai frekuensi kemunculan minimal 2000.

d <- terms_freq(suicide_terms)
wordcloud(words = d$word, freq = d$freq, min.freq = 2000, colors=brewer.pal(8, "Dark2"))

Berdasarkan wordcloud tersebut, kata yang paling sering muncul adalah kata “Feel”, yang menunjukkan bahwa dalam gagasan bunuh diri, akan ada pembahasan tentang perasaan. Selain kata “Feel”, terdapat kata “Life” yang sering muncul, dimana kehidupan banyak sekali disebutkan ketika mempunyai gagasan bunuh diri. Lalu, terdapat beberapa kata yang berkaitan dengan gagasan bunuh diri, seperti “kill”, “suicide”, “death”, “suicidial”, dan “die”. Beberapa kata lainnya yang sering muncul, seperti “friend”, “relationship”, “school”, dan “work” bisa jadi merupakan alasan mengapa pengguna itu bisa mempunyai pikiran/gagasan bunuh diri. Beberapa kata-kata yang berkaitan dengan perasaan, seperti “depression”, “pain”, “depress”, “hate”, “scare” juga dapat menandakan adanya gagasan tersebut. Sehingga, kemunculan kata-kata tersebut dapat menjadi pertimbangan bahwa pengguna tersebut membutuhkan pertolongan profesional.

Analisis teks non-bunuh diri (kelas non-Suicide)

Berikut ini adalah hasil analisis teks yang tidak memicu pikiran bunuh diri. Pertama, akan dilakukan filtering untuk teks yang berlabel non-suicide.

df_nonsuicide <- df_fix %>% filter(class %in% "non-suicide")
nonsuicide_terms <- df_fix.dtm[as.numeric(df_nonsuicide$id_text),]

Berikut ini adalah visualisasi wordcloud dari frekuensi kata yang muncul pada kelas non-suicide. Kata yang ditampilkan mempunyai frekuensi kemunculan minimal 2000.

d <- terms_freq(nonsuicide_terms)
wordcloud(words = d$word, freq = d$freq, min.freq = 2000, colors=brewer.pal(8, "Dark2"))

Berdasarkan wordcloud tersebut, hanya ada 18 kata yang muncul sebanyak lebih dari 2000 kali di kelas non-suicide. Terlihat bahwa kata yang sering muncul di non-suicide merupakan kata yang sering muncul juga di kelas suicide sehingga ketika menemukan kata-kata tersebut, diperlukan juga untuk menganalisis lebih dalam apakah ada kata lain yang mempengaruhi atau tidak.

Pembangunan Model

Selanjutnya akan dilakukan pembangunan model machine learning. Pada markdown ini, akan dibangun tiga model machine learning, yaitu Naive Bayes, Decision Tree, dan Random Forest. Namun sebelum pembangunan model, perlu dilakukan pembagian dataset terlebih dahulu dengan proporsi 80% data train dan 20% data test dan akan dilakukan transformasi frekuensi untuk mengubah data numerik menjadi data kategorikal.

Pembagian Dataset

Berikut ini adalah langkah untuk membagi dataset menjadi 80:20. Jangan lupa untuk melakukan set.seed() agar hasil pembagian tetap sama meskipun code dijalankan berkali-kali.

set.seed(100)

#lakukan split data train dengan data test
split_80 <- sample(nrow(df_fix.dtm), nrow(df_fix.dtm)*0.8)
df_train <- df_fix.dtm[split_80, ]
df_test <- df_fix.dtm[-split_80, ]

#mengubah kolom "class" menjadi factor
df_fix$class <- as.factor(df_fix$class)

#mengambil label train dan label test
train_labels <- df_fix[split_80, 3]
test_labels <- df_fix[-split_80, 3]

Berikut ini adalah proporsi label dari data train dan data test.

prop.table(table(train_labels))
## train_labels
## non-suicide     suicide 
##   0.4984375   0.5015625
prop.table(table(test_labels))
## test_labels
## non-suicide     suicide 
##     0.50625     0.49375

Proporsi label train dan label test sudah cukup balance, sehingga tidak perlu dilakukan penanganan lain. Kemudian lakukan pemilihan kata yang akan menjadi prediktor dengan cara menggunakan fungsi findFreqTerms() untuk mengambil kata yang paling sering muncul. Dalam kasus ini, kita akan mengambil kata yang mempunyai minimal 2000 kemunculan.

freq_words <- findFreqTerms(df_train,lowfreq = 2000)
length(freq_words)
## [1] 101

Terdapat 101 kata yang paling sering muncul dalam data tersebut, artinya ada 101 prediktor yang digunakan untuk klasifikasi. Kemudian lakukan subsetting dengan memilih 101 kata tersebut

df_train <- df_train[,freq_words]
df_test <- df_test[,freq_words]

Pelatihan per model

Naive Bayes

Naive Bayes merupakan salah satu algoritma machine learning dengan konsep bayesian yang mengasumsikan bahwa semua prediktor dianggap penting dan bersifat independen (tidak saling bergantung terhadap prediktor lainnya).

Dalam klasifikasi teks, semua kata dianggap penting dan bersifat independen (kata yang muncul tidak dipengaruhi oleh kata lain). Kemudian akan dilihat berapa peluang kelas tersebut jika ada suatu kalimat. Perhitungan peluang menggunakan teorema bayes yang ditujukan pada formula berikut.

\[P(Kelas\mid kata1 \cap kata2 \cap ... \cap kataN)=\frac{P(kata1 \cap kata2 \cap ... \cap kataN \mid Kelas) P(Kelas)}{P(kata1 \cap kata2 \cap ... \cap kataN)}\] Langkah yang dilakukan dalam algoritma Naive Bayes adalah sebagai berikut

  1. Menghitung prior probability dari setiap kelas di seluruh data.
  2. Menghitung likelihood (peluang kemunculan masing-masing kata dalam kelas tersebut).
  3. Menghitung marginal likelihood (peluang kemunculan masing-masing kata di seluruh kelas)
  4. Menghitung posterior probability (peluang sebuah kelas jika ada kalimat).

Kelemahan dari Naive Bayes adalah masalah kekurangan data, sehingga ketika melakukan perhitungan peluang bersyarat akan menghasilkan zero-probability (peluang nol) atau peluang yang mendekati 1. Sehingga perlu digunakan laplace estimator, yaitu menambahkan setiap frekuensi kemunculan dengan 1.

Dalam markdown ini, kita akan membangun model Naive Bayes dengan menggunakan library e1071. Karena Naive Bayes memprediksi dengan melihat peluang kejadian, maka kita perlu melakukan transformasi frekuensi Document-Term Matrix menjadi data kategorikal dengan kondisi berikut ini.

  • Jika frekuensi kemunculan kata lebih dari 0. Maka diganti dengan “Yes”
  • Jika tidak, maka diganti dengan “No”
bernoulli_conv <- function(x){
        x <- ifelse(x>0,"Yes","No")
}

train_bn <- apply(X = df_train, MARGIN = 2, FUN = bernoulli_conv)
test_bn <- apply(X= df_test, MARGIN = 2, FUN = bernoulli_conv)

Setelah itu, gabungkan label dengan hasil transformasi Document-Term Matrix yang akan digunakan sebagai masukkan model. Kemudian ubahlah tipe data dari semua kolom menjadi factor.

train_set <- cbind(as.data.frame(train_bn),train_labels)
test_set <- cbind(as.data.frame(test_bn),test_labels)

train_set <- train_set %>% mutate_if(is.character, as.factor)
test_set <- test_set %>% mutate_if(is.character, as.factor)

Kemudian lakukan pembangunan model dengan parameter laplace = 1 untuk menggunakan laplace estimator.

model_nb <- naiveBayes(train_labels ~ ., data = train_set, laplace = 1)

Decision Tree

Decision Tree merupakan sebuah algoritma machine learning yang menerapkan konsep pengambilan keputusan dengan menggunakan aturan atau rule yang bercabang seperti pohon. Algoritma Decision Tree akan menentukan pohon mana yang aturannya paling representatif untuk memutuskan kelas mana yang paling tepat berdasarkan prediktor yang ada.

Dalam markdown ini, kita akan membangun model dengan menggunakan library rpart. Dalam Decision Tree, frekuensi tidak akan ditransformasikan menjadi kategorikal. Untuk masukkan model, gabungkan dataframe prediktor dengan dataframe label.

train_set_tree <- cbind(as.data.frame(as.matrix(df_train)),train_labels)
test_set_tree <- cbind(as.data.frame(as.matrix(df_test)),test_labels)

Kemudian bangunlah model tersebut.

model_dt <- rpart(train_labels ~ ., data = train_set_tree)
fancyRpartPlot(model_dt, sub = NULL)

Dengan merujuk pada visualisasi Decision Tree di atas, kita dapat melakukan interpretasi dengan mudah. Sebagai contoh jika frekuensi kata “life” lebih dari 0.5, maka 27% kemungkinan kelas suicide. Jika kurang dari 0.5, maka 73% kemungkinan kelas non-suicide dan akan dilakukan pengecekan lagi, apakah ada kata “kill” atau tidak. Jika kata “kill” lebih dari 0.5, maka 7% kemungkinan kelas suicide dan jika sebaliknya, maka akan dilakukan pengecekan lagi ke kata yang lain dan seterusnya.

Lalu bagaimana Decision Tree menentukan prediktor mana yang akan di split dan bagaimana menentukan prediktor paling atas (root) dan prediktor di cabangnya (node) dalam tree? Decision Tree akan mencari nilai information gain terbesar dalam proses menentukan root dan nodenya.

Beberapa pertimbangan dalam menggunakan model Decision Tree adalah sebagai berikut

  1. Ketika data latih berubah, maka struktur pohon juga akan ikut berubah.
  2. Algoritma decision tree menggunakan konsep “greedy algorithm” yang memilih atribut dengan information gain paling tinggi di setiap split.
  3. Sangat sensitif terhadap overfitting, bila semua data digunakan untuk menghasilkan pohon.

Random Forest

Random Forest adalah pengembangan dari Decision Tree yang menggunakan konsep ensemble method. Dalam ensemble method, beberapa model akan digabungkan menjadi satu prediksi yang bertujuan untuk menurunkan variance, meningkatkan bias, atau meningkatkan prediksi. Cara kerja Random Forest ditujukan pada gambar berikut.

Dalam Random Forest, beberapa kombinasi pohon akan dibangun berdasarkan data yang sudah di resample. Kemudian dari masing-masing pohon akan dilakukan prediksi. Kemudian akan dilakukan majority voting untuk menentukan kelas mana yang paling banyak diprediksi oleh pohon-pohon tersebut.

Dalam markdown ini, kita akan membangun model dengan menggunakan library dari caret. Untuk mencari parameter terbaik dari Random Forest, kita akan menggunakan teknik evaluasi k-fold cross validation. Illustrasi dari k-fold cross validation merujuk pada link berikut

Dalam k-fold cross validation, data akan dibagi menjadi k bagian, lalu di iterasi pertama, akan digunakan partisi/fold pertama sebagai data test dan sisa datanya akan menjadi data untuk pelatihan model. Kemudian di iterasi selanjutnya akan digunakan fold kedua sebagai data test dan sisa datanya akan menjadi data train. Lakukan hal yang sama sampai dengan partisi ke-k.

Dalam markdown ini, akan digunakan library caret, dengan menggunakan metode evaluasi repeatedcv. Jumlah fold akan di set menjadi 3 fold dan dilakukan 2 kali perulangan.

set.seed(100)
# Ketika ingin mencoba dijalankan, silakan untuk uncomment code berikut
# ctrl <- trainControl(method="repeatedcv", number=3, repeats=2, verboseIter = TRUE) 
# fb_model <- train(train_labels ~ ., data=train_set_tree, method="rf", trControl = ctrl)
# fb_model

Karena pelatihan Random Forest memakan waktu yang cukup lama, sebaiknya model disimpan agar dapat digunakan kembali tanpa perlu melatih ulang. Untuk menyimpan model dapat menggunakan fungsi saveRDS().

# saveRDS(fb_model, "fb_model.rds")

Model yang akan digunakan dapat di load dengan menggunakan fungsi readRDS().

fb_model <- readRDS("fb_model.rds")
fb_model
## Random Forest 
## 
## 32000 samples
##   101 predictor
##     2 classes: 'non-suicide', 'suicide' 
## 
## No pre-processing
## Resampling: Cross-Validated (3 fold, repeated 2 times) 
## Summary of sample sizes: 21333, 21334, 21333, 21333, 21334, 21333, ... 
## Resampling results across tuning parameters:
## 
##   mtry  Accuracy   Kappa    
##     2   0.8577813  0.7156346
##    51   0.8563438  0.7126893
##   101   0.8498907  0.6997835
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 2.

Setelah dilakukan pelatihan, nilai mtry yang menghasilkan akurasi terbaik adalah mtry = 2. nilai mtry merupakan jumlah prediktor yang digunakan dalam split setiap pohon yang terbentuk, sehingga disini akan ada 2 prediktor yang digunakan di setiap pohon.

Evaluasi

Setelah dilakukan pembangunan model, dilakukan evaluasi per-model dengan menggunakan confusion matrix. Illustrasi confusion matrix merujuk pada link berikut.

Keterangan

  • TP (True Positive), jumlah prediksi positif yang benar.
  • FP (False Positive), jumlah label negatif yang terprediksi menjadi positif
  • FN (False Negative), jumlah label positif yang terprediksi menjadi negatif
  • TN (True Negative), jumlah prediksi negatif yang benar.

Dari confusion matrix tersebut, dapat dihitung empat metrik berikut

  • Accuracy : Rasio prediksi yang benar dari semua data.
  • Precision : Rasio prediksi positif yang benar dari seluruh hasil prediksi positif.
  • Recall/Sensitivity : Rasio prediksi positif yang benar dari seluruh label positif.
  • Specificity : Rasio prediksi negatif yang benar dari seluruh hasil prediksi negatif.

Selain confusion matrix, kita akan coba melihat kurva ROC yang merupakan hasil plot antara True Positive Rate (Sensitivity) dan False Positive Rate (1-Specificity) . Semakin kurva mendekati 90 derajat keatas, model akan semakin berhasil memisahkan kelas positif dan kelas negatif. Illustrasi ROC merujuk pada link berikut.

Sesuai dengan tujuannya, yaitu berhasil memprediksi teks yang mengandung gagasan bunuh diri, kelas positif dalam kasus ini adalah kelas suicide, sedangkan kelas negatif dalam kasus ini adalah kelas non-suicide.

Naive Bayes

Pada model Naive Bayes, lakukan prediksi dengan menggunakan model yang sudah dibuat sebelumnya dan tampilkan confusion matrixnya.

prediction_nb <- predict(model_nb, test_bn)
cf_nb <- confusionMatrix(prediction_nb, test_set$test_labels, positive = "suicide")
cf_nb
## Confusion Matrix and Statistics
## 
##              Reference
## Prediction    non-suicide suicide
##   non-suicide        3659    1107
##   suicide             391    2843
##                                          
##                Accuracy : 0.8128         
##                  95% CI : (0.804, 0.8212)
##     No Information Rate : 0.5062         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.6246         
##                                          
##  Mcnemar's Test P-Value : < 2.2e-16      
##                                          
##             Sensitivity : 0.7197         
##             Specificity : 0.9035         
##          Pos Pred Value : 0.8791         
##          Neg Pred Value : 0.7677         
##              Prevalence : 0.4938         
##          Detection Rate : 0.3554         
##    Detection Prevalence : 0.4042         
##       Balanced Accuracy : 0.8116         
##                                          
##        'Positive' Class : suicide        
## 

Berikut ini adalah plot ROC dari Naive Bayes.

nb_prediction_raw <- predict(model_nb, test_bn, type = "raw")
nb_df <- data.frame("prediction"=nb_prediction_raw[,2], "trueclass"=as.numeric(test_labels=="suicide"))
nb_roc <- ROCR::prediction(nb_df$prediction, nb_df$trueclass)  
plot(performance(nb_roc, "tpr", "fpr"))

Decision Tree

Pada model Decision Tree, lakukan prediksi dengan menggunakan model yang sudah dibuat sebelumnya dan tampilkan confusion matrixnya.

test_set_sub <- test_set_tree %>% select (-test_labels)
prediction_dt <- predict(model_dt, newdata = test_set_sub, type="class")
cf_dt <- confusionMatrix(prediction_dt, test_set_tree$test_labels, positive = "suicide")
cf_dt
## Confusion Matrix and Statistics
## 
##              Reference
## Prediction    non-suicide suicide
##   non-suicide        3229     536
##   suicide             821    3414
##                                          
##                Accuracy : 0.8304         
##                  95% CI : (0.822, 0.8385)
##     No Information Rate : 0.5062         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.661          
##                                          
##  Mcnemar's Test P-Value : 1.263e-14      
##                                          
##             Sensitivity : 0.8643         
##             Specificity : 0.7973         
##          Pos Pred Value : 0.8061         
##          Neg Pred Value : 0.8576         
##              Prevalence : 0.4938         
##          Detection Rate : 0.4268         
##    Detection Prevalence : 0.5294         
##       Balanced Accuracy : 0.8308         
##                                          
##        'Positive' Class : suicide        
## 

Berikut ini adalah plot ROC dari Decision Tree.

dt_prediction_raw <- predict(model_dt, newdata = test_set_sub, type="prob")
dt_df <- data.frame("prediction"=dt_prediction_raw[,2], "trueclass"=as.numeric(test_labels=="suicide"))
dt_roc <- ROCR::prediction(dt_df$prediction, dt_df$trueclass)  
plot(performance(dt_roc, "tpr", "fpr"))

Random Forest

Pada model Random Forest, lakukan prediksi dengan menggunakan model yang sudah dibuat sebelumnya dan tampilkan confusion matrixnya.

test_set_sub <- test_set_tree %>% select (-test_labels)
prediction_rf <- predict(fb_model, newdata = test_set_sub, type="raw")
cf_rf <- confusionMatrix(prediction_rf, test_set$test_labels, positive="suicide")
cf_rf
## Confusion Matrix and Statistics
## 
##              Reference
## Prediction    non-suicide suicide
##   non-suicide        3646     711
##   suicide             404    3239
##                                           
##                Accuracy : 0.8606          
##                  95% CI : (0.8528, 0.8681)
##     No Information Rate : 0.5062          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.7209          
##                                           
##  Mcnemar's Test P-Value : < 2.2e-16       
##                                           
##             Sensitivity : 0.8200          
##             Specificity : 0.9002          
##          Pos Pred Value : 0.8891          
##          Neg Pred Value : 0.8368          
##              Prevalence : 0.4938          
##          Detection Rate : 0.4049          
##    Detection Prevalence : 0.4554          
##       Balanced Accuracy : 0.8601          
##                                           
##        'Positive' Class : suicide         
## 

Berikut ini adalah plot ROC dari Random Forest.

rf_prediction_raw <- predict(fb_model, newdata = test_set_sub, type="prob")
rf_df <- data.frame("prediction"=rf_prediction_raw[,2], "trueclass"=as.numeric(test_labels=="suicide"))
rf_roc <- ROCR::prediction(rf_df$prediction, rf_df$trueclass)  
plot(performance(rf_roc, "tpr", "fpr"))

Hasil Analisis

Untuk menentukan model mana yang paling baik untuk kasus ini, perlu adanya perbandingan antar model. Berikut ini adalah tabel hasil evaluasi dari keseluruhan model yang ada.

df_nb <- data.frame(t(as.matrix(cf_nb, what = "classes")))
df_nb <- cbind(df_nb, data.frame(t(as.matrix(cf_nb,what = "overall"))))

df_dt <- data.frame(t(as.matrix(cf_dt, what = "classes")))
df_dt <- cbind(df_dt, data.frame(t(as.matrix(cf_dt,what = "overall"))))

df_rf <- data.frame(t(as.matrix(cf_rf, what = "classes")))
df_rf <- cbind(df_rf, data.frame(t(as.matrix(cf_rf,what = "overall"))))

all.eval <- rbind(Naive_Bayes = df_nb, 
                  Decision_Tree = df_dt,
                  Random_Forest = df_rf) %>%
  select("Accuracy","Sensitivity","Specificity","Precision") %>% data.frame()

all.eval

Dalam kasus ini, kita ingin agar teks yang sebenarnya tidak ada gagasan bunuh diri tidak salah terprediksi menjadi teks mengandung gagasan bunuh diri. Karena ketika prediksi tersebut salah sasaran, akan mempengaruhi mental seseorang yang semula baik-baik saja menjadi mempertanyakan keadaan mentalnya sendiri. Oleh karena itu, kita ingin mengurangi nilai False Positive dengan cara kita akan berfokus pada nilai Precision yang terbesar.

Berdasarkan hasil evaluasi, nilai Precision yang terbesar adalah Random Forest (88%) dengan jumlah mtry 2, sehingga kita bisa mempertimbangkan memilih model tersebut.

Sedangkan ROC secara keseluruhan adalah sebagai berikut

plot(performance(nb_roc, "tpr", "fpr"), col = "green")
plot(performance(dt_roc, "tpr", "fpr"), add=TRUE, col = "red")
plot(performance(rf_roc, "tpr", "fpr"), add=TRUE, col = "blue")
legend(x = "bottomright", box.col = "brown", box.lwd = 2 , title="Model", 
       legend=c("Naive Bayes", "Decision Tree", "Random Forest"), 
       fill = c("green","red", "blue"))

Berdasarkan perbandingan tersebut, grafik yang paling mendekati 90 derajat ke atas adalah Random Forest, artinya Random Forest dapat memisahkan kedua kelas lebih baik dibandingkan dengan model-model lainnya. Namun, kita bisa mencoba model yang lebih robust lagi untuk meningkatkan performansi model.

Model Improvement

Karena model tersebut akan menyangkut kesehatan mental orang lain, kita akan perlu meningkatkan performance dari model kita. Oleh karena itu kita akan mencoba menggunakan XGBoost.

XGBoost merupakan salah satu metode machine learning yang menggunakan konsep ensemble method yang membangun kumpulan dari model Decision Tree. Konsep ini mirip dengan Random Forest namun terdapat perbedaan pada proses trainingnya. Secara sederhana, XGBoost menggunakan konsep Boosting, yaitu membangun model Decision Tree yang kuat dari sejumlah model Decision Tree yang lemah.

Untuk menggunakan model XGBoost, kita dapat mengganti method di fungsi train() caret menjadi “xgbTree”

set.seed(100)
# ctrl <- trainControl(method="repeatedcv", number=3, repeats=2, verboseIter = TRUE)
# fb_model_tuned <- train(train_labels ~ ., data=train_set_tree, method="xgbTree", trControl = ctrl)
# fb_model_tuned

Sama seperti model Random Forest, kita dapat menyimpan model tersebut dengan fungsi saveRDS agar tidak perlu dijalankan dari awal.

# saveRDS(fb_model_tuned, "fb_model_tuned_xgb.rds")
fb_model_tuned <- readRDS("fb_model_tuned_xgb.rds")
fb_model_tuned
## eXtreme Gradient Boosting 
## 
## 32000 samples
##   101 predictor
##     2 classes: 'non-suicide', 'suicide' 
## 
## No pre-processing
## Resampling: Cross-Validated (3 fold, repeated 2 times) 
## Summary of sample sizes: 21333, 21334, 21333, 21333, 21334, 21333, ... 
## Resampling results across tuning parameters:
## 
##   eta  max_depth  colsample_bytree  subsample  nrounds  Accuracy   Kappa    
##   0.3  1          0.6               0.50        50      0.8601094  0.7203271
##   0.3  1          0.6               0.50       100      0.8675468  0.7351844
##   0.3  1          0.6               0.50       150      0.8716250  0.7433320
##   0.3  1          0.6               0.75        50      0.8601875  0.7204854
##   0.3  1          0.6               0.75       100      0.8674687  0.7350302
##   0.3  1          0.6               0.75       150      0.8708594  0.7418029
##   0.3  1          0.6               1.00        50      0.8602031  0.7205156
##   0.3  1          0.6               1.00       100      0.8671718  0.7344380
##   0.3  1          0.6               1.00       150      0.8700781  0.7402423
##   0.3  1          0.8               0.50        50      0.8604375  0.7209849
##   0.3  1          0.8               0.50       100      0.8677812  0.7356530
##   0.3  1          0.8               0.50       150      0.8712656  0.7426141
##   0.3  1          0.8               0.75        50      0.8603281  0.7207647
##   0.3  1          0.8               0.75       100      0.8677812  0.7356549
##   0.3  1          0.8               0.75       150      0.8704062  0.7408963
##   0.3  1          0.8               1.00        50      0.8600625  0.7202353
##   0.3  1          0.8               1.00       100      0.8669218  0.7339389
##   0.3  1          0.8               1.00       150      0.8701719  0.7404294
##   0.3  2          0.6               0.50        50      0.8694531  0.7389844
##   0.3  2          0.6               0.50       100      0.8740312  0.7481285
##   0.3  2          0.6               0.50       150      0.8751250  0.7503121
##   0.3  2          0.6               0.75        50      0.8692343  0.7385487
##   0.3  2          0.6               0.75       100      0.8736875  0.7474433
##   0.3  2          0.6               0.75       150      0.8759531  0.7519685
##   0.3  2          0.6               1.00        50      0.8682812  0.7366449
##   0.3  2          0.6               1.00       100      0.8738750  0.7478190
##   0.3  2          0.6               1.00       150      0.8755313  0.7511266
##   0.3  2          0.8               0.50        50      0.8691406  0.7383589
##   0.3  2          0.8               0.50       100      0.8741719  0.7484107
##   0.3  2          0.8               0.50       150      0.8760625  0.7521858
##   0.3  2          0.8               0.75        50      0.8687344  0.7375487
##   0.3  2          0.8               0.75       100      0.8737031  0.7474732
##   0.3  2          0.8               0.75       150      0.8760781  0.7522198
##   0.3  2          0.8               1.00        50      0.8683750  0.7368327
##   0.3  2          0.8               1.00       100      0.8732187  0.7465077
##   0.3  2          0.8               1.00       150      0.8750938  0.7502532
##   0.3  3          0.6               0.50        50      0.8730000  0.7460633
##   0.3  3          0.6               0.50       100      0.8764844  0.7530244
##   0.3  3          0.6               0.50       150      0.8765156  0.7530840
##   0.3  3          0.6               0.75        50      0.8727344  0.7455327
##   0.3  3          0.6               0.75       100      0.8767969  0.7536479
##   0.3  3          0.6               0.75       150      0.8770000  0.7540508
##   0.3  3          0.6               1.00        50      0.8717813  0.7436263
##   0.3  3          0.6               1.00       100      0.8755782  0.7512133
##   0.3  3          0.6               1.00       150      0.8770157  0.7540850
##   0.3  3          0.8               0.50        50      0.8735157  0.7470917
##   0.3  3          0.8               0.50       100      0.8768282  0.7537090
##   0.3  3          0.8               0.50       150      0.8769844  0.7540186
##   0.3  3          0.8               0.75        50      0.8724531  0.7449697
##   0.3  3          0.8               0.75       100      0.8759688  0.7519923
##   0.3  3          0.8               0.75       150      0.8772188  0.7544894
##   0.3  3          0.8               1.00        50      0.8718594  0.7437857
##   0.3  3          0.8               1.00       100      0.8755157  0.7510893
##   0.3  3          0.8               1.00       150      0.8767969  0.7536485
##   0.4  1          0.6               0.50        50      0.8638750  0.7278492
##   0.4  1          0.6               0.50       100      0.8696874  0.7394577
##   0.4  1          0.6               0.50       150      0.8732969  0.7466688
##   0.4  1          0.6               0.75        50      0.8634844  0.7270701
##   0.4  1          0.6               0.75       100      0.8695937  0.7392729
##   0.4  1          0.6               0.75       150      0.8722344  0.7445471
##   0.4  1          0.6               1.00        50      0.8628437  0.7257898
##   0.4  1          0.6               1.00       100      0.8692031  0.7384938
##   0.4  1          0.6               1.00       150      0.8716719  0.7434246
##   0.4  1          0.8               0.50        50      0.8640000  0.7280991
##   0.4  1          0.8               0.50       100      0.8703281  0.7407405
##   0.4  1          0.8               0.50       150      0.8726875  0.7454507
##   0.4  1          0.8               0.75        50      0.8635781  0.7272571
##   0.4  1          0.8               0.75       100      0.8694687  0.7390218
##   0.4  1          0.8               0.75       150      0.8725781  0.7452329
##   0.4  1          0.8               1.00        50      0.8636875  0.7274771
##   0.4  1          0.8               1.00       100      0.8693437  0.7387751
##   0.4  1          0.8               1.00       150      0.8718750  0.7438305
##   0.4  2          0.6               0.50        50      0.8719688  0.7440075
##   0.4  2          0.6               0.50       100      0.8750625  0.7501865
##   0.4  2          0.6               0.50       150      0.8754532  0.7509651
##   0.4  2          0.6               0.75        50      0.8704531  0.7409811
##   0.4  2          0.6               0.75       100      0.8743125  0.7486879
##   0.4  2          0.6               0.75       150      0.8752812  0.7506223
##   0.4  2          0.6               1.00        50      0.8704844  0.7410449
##   0.4  2          0.6               1.00       100      0.8740313  0.7481298
##   0.4  2          0.6               1.00       150      0.8755626  0.7511881
##   0.4  2          0.8               0.50        50      0.8708125  0.7416964
##   0.4  2          0.8               0.50       100      0.8747656  0.7495930
##   0.4  2          0.8               0.50       150      0.8757969  0.7516506
##   0.4  2          0.8               0.75        50      0.8711094  0.7422930
##   0.4  2          0.8               0.75       100      0.8747656  0.7495945
##   0.4  2          0.8               0.75       150      0.8762657  0.7525911
##   0.4  2          0.8               1.00        50      0.8705000  0.7410755
##   0.4  2          0.8               1.00       100      0.8747344  0.7495342
##   0.4  2          0.8               1.00       150      0.8758750  0.7518128
##   0.4  3          0.6               0.50        50      0.8735625  0.7471830
##   0.4  3          0.6               0.50       100      0.8754844  0.7510211
##   0.4  3          0.6               0.50       150      0.8756563  0.7513615
##   0.4  3          0.6               0.75        50      0.8738125  0.7476852
##   0.4  3          0.6               0.75       100      0.8757032  0.7514618
##   0.4  3          0.6               0.75       150      0.8763438  0.7527384
##   0.4  3          0.6               1.00        50      0.8740625  0.7481859
##   0.4  3          0.6               1.00       100      0.8765469  0.7531474
##   0.4  3          0.6               1.00       150      0.8767969  0.7536464
##   0.4  3          0.8               0.50        50      0.8738750  0.7478092
##   0.4  3          0.8               0.50       100      0.8763126  0.7526777
##   0.4  3          0.8               0.50       150      0.8752657  0.7505815
##   0.4  3          0.8               0.75        50      0.8736875  0.7474340
##   0.4  3          0.8               0.75       100      0.8768594  0.7537707
##   0.4  3          0.8               0.75       150      0.8773282  0.7547053
##   0.4  3          0.8               1.00        50      0.8736406  0.7473418
##   0.4  3          0.8               1.00       100      0.8768438  0.7537427
##   0.4  3          0.8               1.00       150      0.8772969  0.7546461
## 
## Tuning parameter 'gamma' was held constant at a value of 0
## Tuning
##  parameter 'min_child_weight' was held constant at a value of 1
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were nrounds = 150, max_depth = 3, eta
##  = 0.4, gamma = 0, colsample_bytree = 0.8, min_child_weight = 1 and subsample
##  = 0.75.

Berdasarkan summary model, parameter terbaik pada model XGBoost tersebut adalah sebagai berikut

  • nrounds = 150,
  • max_depth = 3,
  • eta = 0.4,
  • gamma = 0,
  • colsample_bytree = 0.8,
  • min_child_weight = 1 dan
  • subsample = 0.75

Berikut ini adalah confusion matrix dari model XGBoost yang sudah dilatih

test_set_sub <- test_set_tree %>% select (-test_labels)
prediction_rf_tuned <- predict(fb_model_tuned, newdata = test_set_sub, type="raw")
cf_xg <- confusionMatrix(prediction_rf_tuned, test_set_tree$test_labels, positive="suicide")
cf_xg
## Confusion Matrix and Statistics
## 
##              Reference
## Prediction    non-suicide suicide
##   non-suicide        3683     606
##   suicide             367    3344
##                                          
##                Accuracy : 0.8784         
##                  95% CI : (0.871, 0.8855)
##     No Information Rate : 0.5062         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.7565         
##                                          
##  Mcnemar's Test P-Value : 2.349e-14      
##                                          
##             Sensitivity : 0.8466         
##             Specificity : 0.9094         
##          Pos Pred Value : 0.9011         
##          Neg Pred Value : 0.8587         
##              Prevalence : 0.4938         
##          Detection Rate : 0.4180         
##    Detection Prevalence : 0.4639         
##       Balanced Accuracy : 0.8780         
##                                          
##        'Positive' Class : suicide        
## 

Kemudian berikut ini adalah kurva ROC dan AUC dari model XGBoost tersebut

xg_prediction_raw <- predict(fb_model_tuned, newdata = test_set_sub, type="prob")
xg_df <- data.frame("prediction"=xg_prediction_raw[,2], "trueclass"=as.numeric(test_labels=="suicide"))
xg_roc <- ROCR::prediction(xg_df$prediction, xg_df$trueclass)  
plot(performance(xg_roc, "tpr", "fpr"))

Kemudian, kita akan mencoba membandingkan model XGBoost dengan Random Forest yang sudah kita bangun sebelumnya.

df_rf <- data.frame(t(as.matrix(cf_rf, what = "classes")))
df_rf <- cbind(df_rf, data.frame(t(as.matrix(cf_rf,what = "overall"))))

df_xg <- data.frame(t(as.matrix(cf_xg, what = "classes")))
df_xg <- cbind(df_xg, data.frame(t(as.matrix(cf_xg,what = "overall"))))

all.eval <- rbind(Random_Forest = df_rf,
                  XgBoost = df_xg) %>%
  select("Accuracy","Sensitivity","Specificity","Precision") %>% data.frame()

all.eval

Model XGBoost berhasil meningkatkan performansi dari model klasifikasi kita dan mendapatkan nilai Precision 90.11%. Tidak hanya precision saja, namun nilai Akurasi juga meningkat menjadi 87.83% jika dibandingkan dengan model Random Forest. Untuk kurva ROC dari model Random Forest dan XGBoost adalah sebagai berikut.

plot(performance(rf_roc, "tpr", "fpr"), col = "blue")
plot(performance(xg_roc, "tpr", "fpr"), add=TRUE, col = "black")
legend(x = "bottomright", box.col = "brown", box.lwd = 2 , title="Model", 
       legend=c("Random Forest", "XGBoost"), 
       fill = c("blue", "black"))

Agar dapat terlihat perbandingannya, kita dapat melihat nilai AUC dari kedua model tersebut. AUC adalah luas dibawah kurva ROC. Semakin nilai AUC mendekati 1, maka model akan semakin baik dalam memisahkan kedua kelasnya.

auc_rf <- performance(rf_roc, "auc")
auc_xg <- performance(xg_roc, "auc")

auc_df <- data.frame(
  Random_Forest = auc_rf@y.values,
  XGBoost = auc_xg@y.values
)
auc_df %>% rename(
  Random_Forest = X0.926234974214721,
  XGBoost = X0.939759306141588
)

Berdasarkan nilai AUC, XGBoost mempunyai performansi yang lebih baik dibandingkan dengan Random Forest, yaitu 93.97%. Hal ini menandakan bahwa XGBoost merupakan model paling baik yang dapat memisahkan dua kelas dengan baik. Berdasarkan hal tersebut, model yang akan dipilih adalah model XGBoost.

Percobaan dengan Input

Model ini diharapkan bisa digunakan oleh pihak yang bekerja di bidang kesehatan mental dan sosial media. Oleh karena itu, pengguna dapat menggunakan model tersebut dengan memasukan input teks secara bebas.

Supaya lebih rapi, seluruh fungsi yang digunakan untuk pembuatan model baik preprocessing teks sampai dengan prediksi model akan dibungkus menjadi satu fungsi prediksi.

#fungsi prediksi
text_prediction <- function(x, freq_words, fb_model_tuned){
  text <- x %>%
    replace_html() %>% #penghapusan html
    replace_url() %>% #penghapusan url
    str_to_lower() %>% #lower case
    str_remove_all(pattern = '[:emoji:]')
  
  text.corpus <- VCorpus(VectorSource(text))
  
  replacePunctuation <- content_transformer(function(x) {
    return (gsub("[[:punct:]]"," ", x))
    })
  
  text.corpus <- text.corpus %>% 
    tm_map(removeWords, stopwords("SMART")) %>% #penghilangan stopwords
    tm_map(removeNumbers) %>% #penghilangan angka
    tm_map(replacePunctuation) %>% #penghilangan punctuation
    tm_map(stripWhitespace) %>% #penghilangan whitespace
    tm_map(content_transformer(lemmatize_strings)) %>% #lematisasi kata dengan textstem
    tm_map(removeWords, stopwords("SMART")) #penghilangan stopwords
  
  text.dtm <- DocumentTermMatrix(text.corpus, control=list(dictionary=freq_words))
  
  text_df <- as.data.frame(as.matrix(text.dtm))
  
  targets <- predict(fb_model_tuned, newdata = text_df, type="raw")
  
  return (targets)
}

Misalkan terdapat contoh satu teks yang mengindikasi gagasan bunuh diri. Kita akan mencobakan teks tersebut ke dalam model yang sudah dibuat. Teks percobaan ini didapatkan dari link berikut

#gagasan bunuh diri (ideation)
texts_suicide = c("A book is usually what I do when Im getting down, but it doesnt work when I start getting panicky. Ill try the carbs, the caffeine doesnt work because Ive gotten it in a movie theater and had a soda with me...', 'A few reasons. I feel backed into a corner mostly. And Im Tired of being Tired of everything. If that makes sense.', 'Thank you! I understand its a sad thing. But I also want people to realize that there can be humor in anything and its the best way to deal with this. Its how I would do it. ', 'I really dont want to ask for help. Id rather not let anyone know Im having these kind of issues.") 

text_prediction(texts_suicide,freq_words,fb_model_tuned)
## [1] suicide
## Levels: non-suicide suicide

Model ini berhasil memprediksi gagasan bunuh diri dalam teks tersebut. Sekarang kita akan mencobakan teks yang tidak mengandung gagasan tersebut.

#bukan gagasan bunuh diri (supportive)
texts_suicide = c("Try and get her to seek a therapist.They will help her.") 

text_prediction(texts_suicide,freq_words,fb_model_tuned)
## [1] non-suicide
## Levels: non-suicide suicide

Ketika teks tersebut tidak mengandung gagasan bunuh diri, model berhasil memprediksi teks tersebut. Oleh karena itu, model ini cocok digunakan untuk menganalisis apakah teks tersebut mengandung gagasan bunuh diri atau tidak.

Kesimpulan

Dalam pembangunan model dan analisis, dapat diberikan kesimpulan sebagai berikut

  1. Kata-kata yang berkaitan dengan terjadinya bunuh diri adalah kata-kata tentang kehidupan, perasaan negatif, dan kata tentang pembunuhan (“kill”, “suicide”, “suicidial”) berdasarkan frekuensi kemunculan kata di kelas suicide. Namun dalam kelas non-suicide, terdapat beberapa kata-kata yang disebutkan juga di kelas suicide sehingga perlu dilakukan analisis lebih dalam lagi.
  2. Model terbaik berdasarkan nilai precision dan nilai AUC adalah model XGBoost dengan nilai precision sebesar 90.11%.

Beberapa rekomendasi untuk aksi selanjutnya adalah sebagai berikut

  1. Perusahaan sosial media dapat membuat sistem untuk filtering teks yang mengandung unsur bunuh diri, seperti warning terhadap konten agar pengguna sosial media tidak banyak terpapar konten tersebut.
  2. Perusahaan sosial media dapat menggunakan hasil klasifikasi untuk mengembangkan personalized ads yang akan memberikan rekomendasi layanan kesehatan mental.
  3. Untuk pihak profesional atau psikolog dapat menggunakan sistem tersebut untuk mendeteksi apakah cerita dari klien mengandung ide/gagasan bunuh diri atau tidak untuk memutuskan penanganan lebih lanjut.