# untuk persiapan data
library(dplyr)
library(rsample)
# untuk text processing
library(tm)
library(SnowballC)
library(inspectdf)
# untuk keperluan machine learning
library(e1071)
library(caret)
library(ROCR)
Dalam pembelajaran kali ini, ita akan memanfaatkan data free text sebagi inputan data untuk melatihan model kita. Agar kita dapat melakukan hal tersebut kita pertama-tama perlu untuk mempelajari sebuah konsep persiapan data teks yang disebut dengan Text Mining.
Text Mining adalah salah satu metode analisis data yang fokus utamanya adalah mencari informasi dan pola-pola dari data yang tidak terstruktur (unstructured), yaitu data teks.
Data teks disebut tidak terstruktur karena:
Business Question: Berdasarkan kata-kata pada SMS, kita ingin melakukan klasifikasi apakah suatu SMS termasuk spam atau bukan (ham) sehingga nantinya SMS spam akan diletakkan pada folder spam.
sms_raw <- read.csv("data_input/spam.csv")
sms <- sms_raw %>%
mutate(label = as.factor(label))
head(sms)
Dikarenakan kita ingin melakukan klasifikasi teks yang dianggap Spam atau Ham, sebelum itu, mari kita coba melihat kata-kata apa saja yang biasanya muncul di teks Spam.
# Mengambil 5 data paling atas
sms %>%
filter(label == "spam") %>%
pull(text) %>% # Mengambil kolom dan mengubah jadi bentuk vector
head(5)
## [1] "Free entry in 2 a wkly comp to win FA Cup final tkts 21st May 2005. Text FA to 87121 to receive entry question(std txt rate)T&C's apply 08452810075over18's"
## [2] "FreeMsg Hey there darling it's been 3 week's now and no word back! I'd like some fun you up for it still? Tb ok! XxX std chgs to send, 1.50 to rcv"
## [3] "WINNER!! As a valued network customer you have been selected to receive a 900 prize reward! To claim call 09061701461. Claim code KL341. Valid 12 hours only."
## [4] "Had your mobile 11 months or more? U R entitled to Update to the latest colour mobiles with camera for Free! Call The Mobile Update Co FREE on 08002986030"
## [5] "SIX chances to win CASH! From 100 to 20,000 pounds txt> CSH11 and send to 87575. Cost 150p/day, 6days, 16+ TsandCs apply Reply HL 4 info"
Kata-kata yang sering muncul di kalimat Spam:
Kenapa kita harus melakukan text cleansing? setiap kata akan menjadi predictor/kolom sehingga dibersihkan terlebih dahulu untuk komputasi yang lebih ringan dan terstandarisasi.
Tahapan pertama yang perlu kita lakukan adalah mengubah teks menjadi bentukan corpus. Corpus itu sendiri merupakan bentukan tipe data untuk mengumpulkan beberapa data menjadi satu dokumen.
Disclaimer, hal ini perlul dilakukan karena kita menggunakan
library tm
dalam proses pembersihan data.
Fungsi yang akan digunakan adalah VectorSource()
dilanjutkan dengan fungsi VCorpus()
## <<VCorpus>>
## Metadata: corpus specific: 0, document level (indexed): 0
## Content: documents: 5572
## [1] "WINNER!! As a valued network customer you have been selected to receive a 900 prize reward! To claim call 09061701461. Claim code KL341. Valid 12 hours only."
Menghapus angka -> Untuk karakter angka umumnya tidak bermakna
ketika melakukan klasifikasi data. Oleh karena itu kita menghapus semua
angka pada data text dengan removeNumbers()
## [1] "Nomer HP saya "
## [1] "WINNER!! As a valued network customer you have been selected to receive a prize reward! To claim call . Claim code KL. Valid hours only."
Asalan menghilangkan tanda baca, sama saja dengan alasan menghilangkan angka pada sebuah teks.
Menghilangkan tanda baca menggunakan removePunctuation
.
Tanda baca yang dihilangkan: ! ’ # S % & ’ ( ) * + , - . / : ; <
= > ? @ [ / ] ^ _ { | } ~
## [1] "I am very angry"
## [1] "WINNER As a valued network customer you have been selected to receive a prize reward To claim call Claim code KL Valid hours only"
Mengubah semua text menjadi lowercase dengan fungsi
tolower()
## [1] "winner"
# Case-folding to lowercase
sms_clean <- sms_clean %>% tm_map(content_transformer(tolower))
sms_clean[[9]]$content
## [1] "winner as a valued network customer you have been selected to receive a prize reward to claim call claim code kl valid hours only"
content_transformer()
jika fungsi yang
ingin diterapkan bukan dari package tm
Menghapus kata yang sering muncul di corpus dan biasanya tidak
meaningful dengan removeWords()
. (contoh stopwords bahasa
Inggris: “the”, “to”, “was”, etc.)
## [1] "winner as a valued network customer you have been selected to receive a prize reward to claim call claim code kl valid hours only"
# Remove stopwords
sms_clean <- sms_clean %>% tm_map(removeWords, stopwords("en"))
sms_clean[[9]]$content
## [1] "winner valued network customer selected receive prize reward claim call claim code kl valid hours "
Stemming atau bisa diartikan sebagai, pemotongan kata menjadi kata
dasarnya menggunakan stemDocument
.
stemDocument()
akan menghapus imbuhan kata “ing”, “e”,
“ed”, “er”, “s”, “es”, dll
Mengapa kata imbuhan dihapuskan? Karena yang dibutuhkan dalam text mining ini adalah mendapatkan beberapa kata-kata yang muncul atau tidak muncul dalam suatu sekumpulan text. Kata-kata tersebut akan digunakan sebagai prediktor untuk memprediksi apakah sms masuk kedalam “spam” atau “ham”.
## [1] "winner"
## [1] "winner valu network custom select receiv prize reward claim call claim code kl valid hour"
stripWhitespace
.Hal ini diperlukan karena pada proses tokenizing (selanjutnya), kata akan dipotong berdasarkan karakter spasi.
## [1] "winner valu network custom select receiv prize reward claim call claim code kl valid hour"
Additional Notes:
Summary singkat, secara umum tahapan yang sering dilakukan untuk text cleansing adalah:
Setelah berhasil melakukan proses pembersihan data, kita akan masuk ke tahapan data preprocessing agar nantinya data yang sudah bersih dapat diolah lebih lanjut oleh model machine learning.
Sampai di tahap ini, data kita masih berupa text. Pertanyaannya bagaimana cara model kita belajar apabila prediktornya masih berupa text?
Kita perlu melakukan transformasi data text menjadi Document-Term Matrix (DTM) melalu proses tokenization. Tokenization adalah proses memecah satu kalimat menjadi beberapa term (bisa berupa 1 kata, pasangan kata, dll). Dalam DTM, 1 kata akan menjadi 1 prediktor dengan nilai berupa frekuensi kemunculan kata tersebut dalam sebuah dokumen.
Gunakan fungsi DocumentTermMatrix()
untuk membuat DTM
dan fungsi inspect()
untuk melihat hasil DTM
## <<DocumentTermMatrix (documents: 5572, terms: 6822)>>
## Non-/sparse entries: 43465/37968719
## Sparsity : 100%
## Maximal term length: 40
## Weighting : term frequency (tf)
## Sample :
## Terms
## Docs call can come dont free get just ltgt now will
## 1085 0 0 1 1 0 1 0 0 0 9
## 1579 0 0 0 0 0 0 0 18 0 0
## 1863 0 0 0 3 0 0 0 0 0 0
## 2158 0 0 0 0 0 0 0 0 0 0
## 2370 0 0 0 0 1 0 0 0 0 0
## 2380 0 1 0 0 0 0 0 1 0 0
## 2434 0 3 0 0 1 1 0 6 0 0
## 2848 0 0 0 0 0 0 0 0 0 0
## 3016 0 0 0 0 0 0 0 2 0 0
## 5105 0 0 0 0 1 0 0 0 0 0
Istilah:
Pembuktian
Mari kita amati SMS ke 5105 yang sudah di-cleansing, kemudian dapat kita konfirmasi bahwa kata “free” apakah muncul sebanyak 1 kali?
## [1] "boy love gal propsd bt didnt mind gv lv lttrs bt frnds threw thm d boy decid aproach d gal dt time truck speed toward d gal wn hit d girld boy ran like hell n save ask hw cn u run fast d boy repli boost d secret energi n instant d girl shout energi n thi live happili gthr drink boost evrydi moral d stori hv free msgsd gud ni"
Tahapan selanjutnya adalah kita akan memisahkan ke data train dan data test.
RNGkind(sample.kind = "Rounding")
set.seed(100)
# train-test splitting
index <- sample(nrow(sms_dtm), nrow(sms_dtm)*0.75)
# sms_dtm = DocumentTermMatrix yang tidak ada labelnya
sms_train_x <- sms_dtm[index,]
sms_test_x <- sms_dtm[-index,]
Siapkan juga label untuk targetnya:
# label untuk train dan test, tersimpan pada dataframe sms
sms_train_y <- sms[index, "label"]
sms_test_y <- sms[-index, "label"]
Cek proporsi kelas target pada sms_train_y
:
## sms_train_y
## ham spam
## 0.8631251 0.1368749
Cek dimensi sms_train
yang akan digunakan untuk
pembuatan model:
## [1] 4179 6822
Dari dimensi yang ditampilkan, prediktor yang digunakan cukup banyak.
Ketika prediktor yang sangat banyak, bisa menyebabkan “noise” yang
menggangu peforma model, maka dari itu kita bisa mengsedeharnakannya
dengan menggunakan prediktor yang setidaknya muncul minimal 20 kali.
Fungsi yang digunakan adalah findFreqTerms()
## [1] 348
Note: Penentuan lowfreq = 20
tidak
mutlak dan dapat diubah-ubah untuk feature selection. Perlu
diketahui: Semakin besar lowfreq
, semakin sedikit terms
yang kita gunakan sebagai feature/predictor.
Mari subset data sms_train
hanya untuk kata-kata yang
muncul di sms_freq
:
## <<DocumentTermMatrix (documents: 4179, terms: 348)>>
## Non-/sparse entries: 18787/1435505
## Sparsity : 99%
## Maximal term length: 10
## Weighting : term frequency (tf)
## Sample :
## Terms
## Docs call can come dont free get just ltgt now will
## 1085 0 0 1 1 0 1 0 0 0 9
## 1579 0 0 0 0 0 0 0 18 0 0
## 1863 0 0 0 3 0 0 0 0 0 0
## 2010 0 0 0 2 0 0 0 0 0 0
## 2134 1 0 0 1 0 0 2 0 0 1
## 2158 0 0 0 0 0 0 0 0 0 0
## 2380 0 1 0 0 0 0 0 1 0 0
## 2434 0 3 0 0 1 1 0 6 0 0
## 2848 0 0 0 0 0 0 0 0 0 0
## 2945 0 1 1 2 0 1 0 1 1 1
Model Naive Bayes itu lebih baik ketika menghadapi data kategorikal
Nilai pada matrix sms_train
masih berupa frekuensi.
Untuk perhitungan peluang, frekuensi akan diubah menjadi hanya kondisi
muncul (1) atau tidak (0). Salah satu caranya dengan menggunakan
Bernoulli Converter.
bernoulli_conv <- function(x){
# parameter ifelse: kondisi, Hasil jika Kondisi TRUE, Hasil jika Kondisi FALSE
x <- as.factor(ifelse(x > 0, 1, 0))
return(x)
}
# testing fungsi
bernoulli_conv(c(3,0,0,1,4,0))
## [1] 1 0 0 1 1 0
## Levels: 0 1
Selanjutnya, terapkan bernoulli_conv
ke
sms_train
dan sms_test
:
sms_train_bn <- apply(X = sms_train_x,
MARGIN = 2,
FUN = bernoulli_conv)
sms_test_bn <- apply(X = sms_test_x,
MARGIN = 2,
FUN = bernoulli_conv)
Salah satu model yang cukup baik dalam melakukan prediksi klasifikasi untuk kasus teks adalah Naive Bayes. Maka dari itu, mari kita coba untuk implementasikan.
Prediksi kelas target pada sms_test_bn
. Simpan ke objek
sms_pred_class
, akan digunakan untuk mengevaluasi dengan
confusion matrix.
## [1] ham spam ham ham ham
## Levels: ham spam
Evaluasi model naive_spam
menggunakan confusion matrix
dan metric-metric yang ada:
Fungsi: confusionMatrix(data, reference)
data
: Data prediksi -> data test ->
sms_pred_classreference
: Data aktual -> sms_test_ypositive
= “spam”## Confusion Matrix and Statistics
##
## Reference
## Prediction ham spam
## ham 1202 28
## spam 16 147
##
## Accuracy : 0.9684
## 95% CI : (0.9578, 0.977)
## No Information Rate : 0.8744
## P-Value [Acc > NIR] : < 0.0000000000000002
##
## Kappa : 0.8519
##
## Mcnemar's Test P-Value : 0.09725
##
## Sensitivity : 0.8400
## Specificity : 0.9869
## Pos Pred Value : 0.9018
## Neg Pred Value : 0.9772
## Prevalence : 0.1256
## Detection Rate : 0.1055
## Detection Prevalence : 0.1170
## Balanced Accuracy : 0.9134
##
## 'Positive' Class : spam
##