Membuat Word Cloud dari Hasil Crawling Twitter dengan R Tidak seperti data biasanya, data teks memiliki teknik khusus dalam penggalian informasinya (text mining). Salah satu metode text mining yang populer adalah memvisualisasikan data teks dengan word cloud (disebut juga text cloud atau tag cloud). Setiap kata yang terdapat pada teks disusun sedemikian rupa dengan ukuran yang bervariasi sesuai frekuensi kemunculannya dalam data. Semakin sering kata digunakan semakin besar ukuran kata tersebut dalam Word Cloud

Artikel ini bertujuan untuk membuat Word Cloud yang bersumber dari data cuitan (tweets) pengguna twitter yang mengandung kata kunci tertentu. Kata kunci tersebut dapat berupa nama produk, brand, tokoh terkenal, isu viral, dsb. Dalam hal ini, Word Cloud berfungsi untuk menyoroti isu apa saja yang sering dikaitkan dengan kata kunci yang dimasukan pada proses crawling. Word Cloud dapat menjadi fondasi utama dalam analisis sentimen untuk mengetahui arah opini masyarakat terhadap suatu kata kunci.

Cleaning Data Teks

Cleaning merupakan proses pre-processing untuk memperoleh data yang benar-benar mengandung informasi penting sesuai dengan yang dikehendaki. Proses cleaning pada data teks tentunya memiliki teknik yang berbeda dengan data angka, R telah menyediakan package khusus untuk hal ini, yaitu textclean dan tm

Panggil semua packages dengan fungsi library (nama_packages)

library(wordcloud)
## Loading required package: RColorBrewer
library(tm)
## Loading required package: NLP
library(textclean)
library(tidytext)
library(ggplot2)
## 
## Attaching package: 'ggplot2'
## The following object is masked from 'package:NLP':
## 
##     annotate
library(parallel)
library(tokenizers)
library(tau)
library(NLP)
library(stringr)
library(devtools)
## Loading required package: usethis
library(quanteda)
## Package version: 3.3.1
## Unicode version: 13.0
## ICU version: 69.1
## Parallel computing: 4 of 4 threads used.
## See https://quanteda.io for tutorials and examples.
## 
## Attaching package: 'quanteda'
## The following object is masked from 'package:tm':
## 
##     stopwords
## The following objects are masked from 'package:NLP':
## 
##     meta, meta<-
library(kayadata)
library(syuzhet)
library(e1071)
library(sentimentr)
## 
## Attaching package: 'sentimentr'
## The following object is masked from 'package:syuzhet':
## 
##     get_sentences
library(SentimentAnalysis)
## 
## Attaching package: 'SentimentAnalysis'
## The following object is masked from 'package:base':
## 
##     write
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(pacman)
pacman::p_load(textstem, dplyr)

TENTANG DATASET

_Dataset yang digunakan adalah data yang diperoleh dari hasil crowling data di twitter. data ini berisi 100 tweets tentang kebakaran gunung bromo diduga akibat dari oknum petugas foto prawedding yang menyebabkan kebakaran yang luarbiasa__

Import data ke dalam R untuk dilakukan analisis

Untuk mengimport file data dari excel ke R dapat menggunakan fungsi read excel dari library readxl, yang kemudian disimpan dalam variabel Kebakaran.Gunung.Bromo

setwd("C:/Users/kjl/Documents/Tugas Kuliah/Komputasi Lanjut Semester V")
Kebakaran.Gunung.Bromo <- read.csv("~/Tugas Kuliah/Komputasi Lanjut Semester V/Kebakaran-Gunung-Bromo.csv", sep=";")
tweets<-Kebakaran.Gunung.Bromo$full_text
head(Kebakaran.Gunung.Bromo)
##                       created_at       id_str
## 1 Thu Sep 07 04:36:56 +0000 2023 1.699643e+18
## 2 Thu Sep 07 07:51:08 +0000 2023 1.699692e+18
## 3 Thu Sep 07 06:05:08 +0000 2023 1.699665e+18
## 4 Thu Sep 07 13:44:17 +0000 2023 1.699781e+18
## 5 Thu Sep 07 10:17:58 +0000 2023 1.699729e+18
## 6 Thu Sep 07 08:13:45 +0000 2023 1.699697e+18
##                                                                                                                                                                                                                                                                                                       full_text
## 1 Ini pelajaran berharga buat gunung-gunung lainnya supaya pengelola memperketat dan memeriksa semua barang yang dibawa oleh para wisatawan, kalo para pendaki, biasanya di basecamp itu ranselnya dibongkar semua utk diperiksa dan didata, sampai potensi sampah yg dihasilkan punâ\200¦ https://t.co/sfwhpJMQux
## 2                                                                                                                                                                                                         Denda dongg, kalau modal nikahnya sampai habis kalau perlu sampai jual asetnya, kok goblok jadi orang
## 3                                                                                                                                                                                                                                                   Prewedd ala-ala cinta alam yang malah ngerusak alamðŸ\230©ðŸ\230©
## 4                                                                                                                                                                                                                                                                                Kelakuan orang makin ada² aja
## 5                                                                                                                                                                                                                        Maaf, misal manti pas nikah tenda nya beliau boleh di lempar flare ga 👉ðŸ\217»ðŸ‘\210ðŸ\217»
## 6                                                                                                                                                                                                                                                                  penjara donk semua yang ngerusak, biar kapok
##   quote_count reply_count retweet_count favorite_count lang  user_id_str
## 1           1           2             8             83   in 8.916931e+07
## 2           0           4             8            218   in 1.233937e+18
## 3           0           0             3            164   in 1.009643e+18
## 4           0           0             0              1   in 7.379091e+08
## 5           0           6             0             60   in 5.184182e+08
## 6           0           5             1            152   in 1.385664e+09
##   conversation_id_str      username
## 1        1.699617e+18  dAsalbantani
## 2        1.699617e+18  urlovelymeow
## 3        1.699617e+18   putrriretno
## 4        1.699617e+18      Amadeaxm
## 5        1.699617e+18 hyaluronicc__
## 6        1.699617e+18  pinkawiz_art
##                                                      tweet_url
## 1  https://twitter.com/dAsalbantani/status/1699642885933793314
## 2  https://twitter.com/urlovelymeow/status/1699691756185629160
## 3   https://twitter.com/putrriretno/status/1699665081926386102
## 4      https://twitter.com/Amadeaxm/status/1699780633101553690
## 5 https://twitter.com/hyaluronicc__/status/1699728710340129056
## 6  https://twitter.com/pinkawiz_art/status/1699697449420652748

Duplikat

#duplicate
tweets <- Kebakaran.Gunung.Bromo%>% 
  as.data.frame() %>% 
  distinct()
tweets

Jumlah baris tweet setelah duplikat dihapus

nrow(tweets)
## NULL

Hapus url

tweets <- tweets %>% 
  replace_html() %>%   
  replace_url()
tweets

tweets <- strip(tweets)
head(tweets)

stemming/lemmatizing = kata dasar

#stemming/lemmatizing = kata dasar
stem_strings(tweets)

cetak tweet dengan html yang dikonversi di index

replace_html(replace_emoji(tweets))

melakukan tugas penggantian seluruh variabel teks

tweets <- tweets %>% 
  replace_emoji(.) %>% 
  replace_html(.)

print menggantikan data teks pada indeks [4:5]

replace_tag(tweets)

Menghilangkan elemen tidak penting dengan textclean

Tahapan yang harus dilalui untuk membersihkan data tweets adalah sebagai berikut :

Menghilangkan substring ’’ dengan fungsi gsub() lalu mengganti nama data yang sudah bersih dari substring ’’ menjadi tweets Menghilangkan link-link html dan url, emoji, hashtag, dan mention pada tweets Berikut adalah syntax yang digunakan:

tweets <- tweets %>% 
  replace_tag(tweets, pattern = "@([A-Za-z0-9_]+)",replacement="") %>%  # remove mentions
  replace_hash(tweets, pattern = "#([A-Za-z0-9_]+)",replacement="")      # remove hashtags
tweets

strip simbol

tweets <- strip(tweets)

menghapus kata penghubung atau kata yang tidak baku

tweets <-removeWords(tweets, c("di","dan","yang","akan","agar","seperti","yaitu","kami","kami",
  "mari","pada","jelang","dimana","dengan","sudah","ini","seluruh",
  "diminta","tak","itu","hai","bisa","wib","oleh","mai","jam", "aug",
  "masa","berikut","kalau","klik","ibodwq","terd","httpstconvv","tue","wed",
  "httpstcoxu","yzmrlyx","tahapan","refaabdi","kota","kpu","kpuid","rt",
  "hingga","saat", "belum","apa","sih","suara","pesta","dindap","http",
  "httpstco","gak","jadi","asn","bakal","wkwk","wkwkw","aug","iya","goblok",
  "uu","i","ada","ngene","yang","bjir","ðÿðÿ","un","anjir","tahi","tbtb",
  "my","wios","sialan","wkwkwkwk","sip","omo","like","plss","ket","e",
  "after","ha","pakðÿ", "but","rill","cashback","allah","and","o","ðÿ'^ðÿ",
  "nya","ya","ðÿ","no","nuruk","ki","jir","anjing","biar","kagak","sayang",
  "mah","anjay","ngaruh","kalo","gua","thesis","skripsiðÿ","duh","ih",
  "ots","a","pft","plis","plan","ra","rabi","o","skripshit","duit","sih",
  "nih", "amp", "ï","tuh","tau","â","â","aaaa","deh","ðÿº","kan", "gara",
  "coba","dll","iki","gue","kena","oon","pas","sad","up","wkwkwk","waleh",
  "ajg","ah","adaâ","alaala","alah","alamðÿ","allahâ","ayo","end","bgt",
  "udh","gak", "tolol","bu","biak","is", "kok", "flare", "trs", "org"))
head(rev)
##                   
## 1 function (x)    
## 2 UseMethod("rev")

lower case = mengubah huruf kapital menjadi huruf kecil

tweets <- tolower(tweets)
tweets

Mengembalikan Kata yang disingkat Menjadi Kata Aslinya

tweets <- replace_contraction(tweets)
tweets

Mengembalikan Kata yang Mengalami Perpanjangan Menjadi Kata Aslinya

tweets <- replace_word_elongation(tweets)
tweets

Menyimpang data yang sudah dibersihkan

write.csv(rev,file = "C:/Users/kjl/Documents/data-bersih3.csv", row.names = F) 

Membuat Word Cloud

Word Cloud memperhatikan frekuensi setiap kata dalam pembuatannya, maka diperlukan sebuah matriks yang dapat menyajikan frekuensi setiap kata. Matriks tersebut dapat diperoleh dengan fungsi TermDocumentMatrix()

Selanjutnya, matriks tersebut diurutkan berdasarkan frekuensi kata dari yang terbesar. Untuk mempermudah pemahaman terhadap kata yang paling sering muncul, dapat dibuat sebuah dataframe dengan syntax seperti berikut :

Mengubah Data Frame Menjadi Data Faktor

tdm <- TermDocumentMatrix(tweets)
m <- as.matrix(tdm)
v <- sort(rowSums(m),decreasing = TRUE)

Mengubah Data Faktor Menjadi Data Frame

d <- data.frame(word = names(v), freq = v)

Membuat Word cloud

wordcloud(d$word, d$freq,
          random.order = FALSE,
          max.words = 500,
          colors = brewer.pal(name="Dark2",8))

Dengan Word Cloud di atas terlihat bahwa kata Prewed, Orang, dan Bromo adalah kata yang paling sering dikaitkan dengan Kebakaran di Bromo pada cuitan pengguna twitter akhir-akhir ini. Berdasarkan Word Cloud ini dapat diambil sebuah informasi penting bahwa sedang di bromo sedang terjadi kebakaran tengah ramai dibicarakan oleh masyarakat Indonesia khususnya pengguna twitter.

Informasi-informasi ini dapat dijadikan fondasi dasar untuk analisis data teks atau analisis wacana lanjutan seperti analisis sentimen untuk melihat kecenderungan arah opini masyarakat.

tdm <-TermDocumentMatrix (tweets,
                        control = list(wordLengths= c (1, inf)))
tdm

Periksa kata-kata yang sering muncul

(freq.terms <- findFreqTerms(tdm, lowfreq = 14))
## [1] "prewed"
term.freq <- rowSums(as.matrix(tdm))
term.freq <- subset(term.freq, term.freq >= 14)
df <- data.frame(term = names(term.freq), freq = term.freq)
ggplot(df, aes(x = term, y = freq)) + geom_bar(stat = "identity") +
  xlab("Terms") + ylab("Count") + coord_flip()

Menghapus istilah-istilah yang jarang?

tdm2 <- removeSparseTerms(tdm, sparse = 0.95)
m2 <- as.matrix(tdm2)

ANALISIS CLUSTER

Analisis Cluster adalah salah satu teknik multivariat yang bertujuan mengklasifikasi suatu objek-objek ke dalam suatu kelompok-kelompok yang berbeda antara lain antara kelompok satu dengan lainnya. Objek-objek yang telah memiliki kedekatan jarak relatif sama dengan objek lainnya (Qonitatin & Novita, 2017). Karakteristik objek-objek dalam satuan kelompok memiliki tingkat kemiripan yang tinggi, sedangkan karakteristik antar objek pada suatu kelompok dengan kelompok lain memiliki tingkat kemiripan yang rendah (Mattjik & Sumertajaya, 2011).

distMatrix <- dist(scale (m2))
fit <- hclust (distMatrix, method = "ward")
## The "ward" method has been renamed to "ward.D"; note new "ward.D2"
plot(fit) 
rect.hclust(fit, k = 3)

Dengan melihat selisih terpanjang dari gamabar diatas terlihat bahwa pemotongan yang tepat akan menghasilkan 3 cluster.

ANALISIS CLUSTER K-MEANS

K-Means Clustering merupakan salah satu metode data clustering non hirarki yang berusaha mempartisi data yang ada ke dalam bentuk satu atau lebih cluster atau kelompok sehingga data yang memiliki karakteristik yang sama dikelompokkan ke dalam satu cluster yang sama dan data yang mempunyai karakteristik yang berbeda dikelompokkan ke dalam kelompok lainnya. K-Means adalah metode clustering berbasis jarak yang membagi data ke dalam sejumlah cluster dan algoritma ini hanya bekerja pada data dengan atribut numerik. Algoritma K-Means termasuk partitioning clustering yang memisahkan data ke k daerah bagian yang terpisah. Algoritma K-Means sangat terkenal karena kemudahan dan kemampuannya meng-cluster data yang besar dan data outlier dengan sangat cepat. K-Means merupakan metode non hirarki yang pada awalnya mengambil sebagian banyaknya komponen populasi untuk dijadikan pusat cluster awal. Berikutnya K-Means menguji masing-masing komponen di dalam populasi data dan menandai komponen tersebut ke salah satu pusat cluster yang telah didefinisikan tergantung dari jarak minimum antar komponen dengan tiap-tiap cluster. Posisi pusat cluster akan dihitung kembali sampai semua komponen data digolongkan ke dalam tiap-tiap pusat cluster dan terakhir akan terbentuk posisi pusat cluster yang baru.

m3 <- t(m2) # transpose the matrix to cluster documents (tweets)
m3
##      Terms
## Docs  denda orang aja mau bromo prewed
##   1       0     0   0   0     0      0
##   2       1     1   0   0     0      0
##   3       0     0   0   0     0      0
##   4       0     1   1   0     0      0
##   5       0     0   0   0     0      0
##   6       0     0   0   0     0      0
##   7       0     0   0   0     0      0
##   8       0     0   0   1     0      0
##   9       0     0   0   0     0      0
##   10      0     0   0   0     0      0
##   11      0     0   0   0     0      0
##   12      0     0   0   0     0      0
##   13      0     0   0   0     0      0
##   14      0     0   0   0     1      0
##   15      0     0   1   1     0      1
##   16      0     0   0   0     0      0
##   17      0     0   0   0     0      0
##   18      0     0   0   1     0      0
##   19      0     0   0   1     0      0
##   20      0     1   0   1     0      0
##   21      0     0   0   0     0      0
##   22      1     0   0   0     0      0
##   23      0     1   0   0     0      1
##   24      0     0   0   0     0      0
##   25      0     0   0   0     0      0
##   26      0     0   0   0     0      1
##   27      0     0   0   0     0      0
##   28      0     0   0   0     0      0
##   29      0     0   0   0     0      0
##   30      0     0   0   0     0      0
##   31      0     0   0   0     0      1
##   32      0     0   0   0     0      0
##   33      0     0   0   0     0      1
##   34      0     0   0   0     1      0
##   35      0     0   0   0     0      0
##   36      0     0   0   0     0      1
##   37      0     1   1   0     0      1
##   38      0     0   0   0     0      0
##   39      0     0   0   0     0      0
##   40      0     0   0   0     0      0
##   41      0     0   0   0     2      0
##   42      0     0   0   0     0      0
##   43      0     0   1   0     0      0
##   44      0     0   0   0     0      0
##   45      0     0   0   0     0      0
##   46      0     0   0   0     1      0
##   47      0     0   0   0     0      0
##   48      0     0   0   0     0      0
##   49      0     0   0   0     0      0
##   50      0     0   1   0     0      0
##   51      0     0   0   0     0      2
##   52      0     0   0   0     0      0
##   53      0     0   0   0     1      0
##   54      0     2   0   0     0      0
##   55      0     0   0   0     0      0
##   56      0     0   0   0     0      0
##   57      0     0   0   0     0      0
##   58      1     0   0   0     1      0
##   59      0     0   0   0     0      0
##   60      0     0   0   0     0      0
##   61      0     0   0   0     0      0
##   62      0     0   0   0     0      0
##   63      0     0   0   0     0      1
##   64      0     0   0   0     1      0
##   65      0     0   0   0     0      0
##   66      0     0   0   0     1      0
##   67      0     0   0   0     1      0
##   68      0     0   0   0     0      0
##   69      0     0   0   0     0      0
##   70      1     0   0   0     0      1
##   71      1     0   0   0     0      0
##   72      0     1   0   1     0      0
##   73      0     0   0   0     0      0
##   74      0     0   0   1     0      0
##   75      0     0   0   0     0      0
##   76      0     0   0   0     0      0
##   77      0     0   0   0     0      0
##   78      0     0   0   0     0      0
##   79      0     0   0   0     1      0
##   80      0     0   0   0     0      1
##   81      0     0   0   0     0      0
##   82      0     0   0   0     0      0
##   83      0     0   0   0     0      0
##   84      0     0   0   0     0      0
##   85      0     0   0   0     0      1
##   86      0     1   0   0     0      0
##   87      0     0   0   0     0      1
##   88      0     0   0   0     0      0
##   89      0     0   0   0     0      0
##   90      0     0   0   0     0      0
##   91      0     0   0   0     0      0
##   92      0     0   0   0     0      0
##   93      0     0   0   0     0      0
##   94      0     0   0   0     0      0
##   95      0     1   0   0     0      0
##   96      1     0   1   1     0      0
##   97      0     0   1   1     0      0
##   98      0     0   0   0     0      1
##   99      0     0   0   0     0      0
##   100     0     1   0   0     0      0
set.seed(122)
k<- 3
kmeansResult<-kmeans(m3, k)
round(kmeansResult$centers, digits=3)
##   denda orang   aja   mau bromo prewed
## 1  0.10   1.1 0.200 0.200   0.0  0.200
## 2  0.10   0.0 0.000 0.000   1.1  0.000
## 3  0.05   0.0 0.062 0.088   0.0  0.162
for (i in 1:k) {
  cat(paste("cluster ", i, ": ", sep = ""))
  s <- sort(kmeansResult$centers[i, ], decreasing = T)
  cat(names(s)[1:5], "\n")
  # print the tweets of every cluster
  # print(tweets[which(kmeansResult£cluster==i)])
}
## cluster 1: orang aja mau prewed denda 
## cluster 2: bromo denda orang aja mau 
## cluster 3: prewed mau aja denda orang