Instragram Comments Sentiment Analysis

Proposal Data Career Day

Background Problem

Pemilihan Calon Pejabat (Capres, Cagub, Cabup) merupakan hal yang cukup krusial untuk Negara dan selalu dinantikan oleh Masyarakat. Bagaimana tidak, Pejabat pada suatu Negara menentukan nasib Negara dan seluruh Rakyat nya.

Di mulai dari Pemilu 2019, sumbangsi suara pemilihan yang di berikan oleh Kaum Milenial cukup besar, sekitar 40%. Koordinator Pusat Peneliti Politik LIPI, Sarah Nuraini Siregar menyatakan, berdasarkan hasil survei lembaganya, ada sekitar 35 persen sampai 40 persen pemilih dalam Pemilu 2019 didominasi generasi milenial. “Atau jumlahnya sekitar 80 juta dari 185 juta pemilih,” kata Sarah saat ditemui di Gedung LIPI, Jakarta Selatan, pada Selasa (11/12/2018) [1].

Pada masa sekarang keterlibatan masyarakat di dalam berinteraksi sosial lebih cendrung melalui media digital yakni Sosial Media. Salah satunya yang memiliki pengguna paling banyak di tanah air ialah Instagram. Di mulai dari tahun 2020 pengguan Instagram di Indonesia mencapai 69,2 juta (69.270.000) pengguna.

Pencapaian itu merupakan peningkatan dari bulan ke bulan atas penggunaan platform berbagi foto ini [2]. Meroketnya pengguna Instagram di Indonesia tidak lepas oleh Covid yang menetapkan kebijakan WFH (Work From Home) sehingga membuat komunikasi yang terjalin antar setiap orang lebih banyak melalui Sosial Media. Para pengguna Instagram di Indonesia didominasi oleh golongan usia produktif, yakni pada rentang 18-34 tahun, atau lazim disebut generasi milenial yang mendominasi hingga 25 juta pengguna atau sekitar 36-38 persen (usia 18-24). Sementara untuk rentang usia 25-34, mendominasi dengan 21 juta pengguna (31-33 persen).

Berlanjut pada Oktober 2021, mayoritas pengguna Instagram tetap konsisten untuk kelompok usia 18-24 tahun, yakni sebanyak 33,90 juta. Terlihat jelas pengguna dari Instagram sebagian besar berasal dari Kaum Milenial yang dari cara pandang nya terhadap Politik cukup sensitif dan kritis. Banyak hal yang dapat di lakukan dari power kaum Milenial melalui Instagram, misal nya seperti Petisi sebagai bentuk boikot terhadap suatu produk, individu atau kelompok yang melakukan tindakan ofensif.

Banyak nya pengguna sosial media pada masa sekarang di Indonesia, membuat banyak politikus melek dengan hal tersebut. Baik itu di pergunakan untuk melakukan Kampanye / Sosialisasi pada Akun sosial media nya. Salah satu contoh nya adalah Bapak Ridwan Kamil. Wali Kota Bandung ini merupakan salah satu politikus yang aktif di sosial media nya. Beliau memanfaaatkan akun Instagram nya untuk menjawab berbagai keluhan masyarakat dan menyampaikan program-programnya [3]. Hal tersebut di lakukan untuk mengambil hati para kaum milenial, hingga beliau sendiri pun di nobat kan sebagai Gubernur Milenial [4]. Sehingga dapat di simpulkan memang di perlukan Strategi Kampanye yang sekiranya sesuai dengan warna jiwa mereka sehingga dapat mengambil hati mereka. Oleh karena itu Instagram sudah menjadi wadah yang baik untuk memulai strategi kampanye yang dapat menarik perhatian kaum milenial sehingga dapat memperoleh banyak suara di dalam pemilihan dan dapat menciptakan program kerja yang sesuai dengan kenginan rakyat. Hal tersebut dapat kita lakukan melalui analisa sentimen terhadap postingan akun Instagram Calon Pejabat guna mengatahui apakah setiap postingan sudah menuai komentar positif atau sebaliknya, sehingga Calon Pejabat dapat melakukan evaluasi terkait strategi kampanye nya serta program kerja nya.

Problem Statement

Sudah menjadi rahasia umum terkait biaya yang di keluarkan oleh para Calon Pejabat di dalam melakukan kampanye bisa mencapai milyaran rupiah. Tak sedikit juga para Calon Pejabat yang bangkrut akibat alokasi dana kampanye yang tidak terkontrol dan tidak tepat sasaran [5]. Oleh karena itu dengan memanfaatkan Instagram sebagai Platform Sosial Media dengan pengguna terbanyak di Indonesia terutama pada kaum kawula muda atau Generasi Milenial, untuk melakukan analisa sentimen pada komentar yang tersedia pada setiap postingan Instagram, mampu mengevaluasi metode kampanye agar lebih tepat sasaran berdasarkan komentar negatif atau positif Netizen pada postingan Instagram nya. Sehingga budget yang di keluarkan pun dapat lebih di kontrol dan suara atau dukungan yang di peroleh pun semakin banyak. Bagi para pejabat yang sudah menjabat pun dapat menggunakan program ini untuk melakukan evaluasi program kerja nya agar sesuai dengan apa yang diharapkan oleh rakyat. Sehingga setiap alokasi anggaran atau dana untuk suatu program kerja bisa lebih di maksimalkan dan sesuai dengan target nya.

Project Idea

Di dalam melakukan evaluasi Kampanye atau Program Kerja oleh para Calon Pejabat maupun Pejabat yang telah menjabat dapat, di lakukan melalui Analisa Sentimen pada postingan Akun Instagram, dengan komentar yang terdapat di postingan Akun Instagram tersebut. Oleh karena itu pada project ini akan di kembangan Program Sentiment Analysis Berdasarkan Akun Instagram menggunakan pendekatan berbasis Lexicon untuk mengidentifikasi komentar yang bersifat Positif, Netral ataupun Negatif.

Problem Scope

Pada Project ini akan digunakan Data Komentar pada suatu postingan Akun Instagram yang di ambil menggunakan tekni Web Scrapping. Dataset tersebut hanya akan mengandung kolom komentar dari User yang berkomentar pada postingan Akun Instagram tersebut.

Selanjut nya, untuk kebutuhan Klasifikasi atau Indentifikasi komentar Positif, Netral dan Negatif beserta Klasifikasi emosi meliputi anger, fear, anticipation, trust, surprise, sadness, joy, dan disgust kita akan menggunakan pendekatan berbasis Lexicon.

Business Impact

Sentimen analisis merupakan analisa yang di lakukan terhadap data tidak terstruktur yang pada kasus ini adalah text. Oleh karena itu kita dapat memanfaatkan fitur komentar pada Akun Instagram sebagai data yang akan di lakukan analisa sentimen. Selain dari pada akun Politik atau Para Pejabat, kita dapat memanfaatkan analisa sentimen pada akun lainnya seperti Toko Online (E-Commerce), Personal Usage (Akun Instagram Artist / Selebgram / Influencer) dan sebagainya.

Sudah menjadi rahasia public terkait estimasi budget yang harus di keluarkan oleh seorang Calon Pejabat untuk melakukan kampanye tidak main-main, bisa mencapai milyaran rupiah [3]. Kampanye yang baik ialah kampanye dengan strategi yang efektif dan sesuai dengan sasaran nya. Sehingga dapat mengontrol dan menghemat pengeluaran budget atau biaya dari kampanye yang di lakukan. Melalui analisa sentimen kita dapat mengatahui tingkat keberhasil suatu kampanye melalui feedback atau timbal balik masyarakat. Hal tersebut dapat di capai dengan memanfaatkan Instagram sebagai wadah sosial media yang menampung feedback atau komentar masyarakat. Sehingga dari kumpulan komentar tersebut, dapat di lakukan analisa sentimen yang mampu di jadikan sebagai bahan evaluasi dari metode / cara kampanye yang lebih efektif, baik dari segi budget ataupun sasaran audiens / masyarakat agar lebih tertarget dan terkontrol. Sehingga dapat memperoleh banyak suara / dukungan pastinya.

Exploratory Data Analysis (EDA)

Load library yang akan kita gunakan terlebih dahulu

library(textclean)
library(katadasaR)
library(tokenizers)
library(wordcloud)
library(dplyr)
library(ggplot2)
library(stringr)
library(tm)
library(stopwords)
library(tidytext)
library(qdapTools)
library(readxl)
library(ggthemes)
library(tidyr)
library(trqwe)
library(trqwe)
library(RWeka)
library(radarchart)
library(igraph)
library(ggraph)

Read Data

insta_comment <- read_excel("datasets/comments.xlsx")
str(insta_comment)
#> tibble [569 × 2] (S3: tbl_df/tbl/data.frame)
#>  $ name   : chr [1:569] "zuper_boyz182" "f.riedmueller" "effolseg.co.promotion56" "kejumozzarela" ...
#>  $ comment: chr [1:569] "👆👆👆#gemahripahlohjinawi kunci sukses ekonomi indonesia di masa revolusi industri yg terbarukan" "Hi👑" "Teruntuk anak ku jika suatu saat kamu membaca komen ini. Nak Bapak mu pernah berjuang Menjual F0LL0W3RS Mur4h🌈"| __truncated__ "Jadi sungkan mau promo." ...

Data yang akan kita gunakan hanya kolom comment saja, karena username sifat nya privasi. Jadi kita akan mencoba untuk men-take out variable username.

dim(insta_comment)
#> [1] 569   2

Total Data yang kita miliki ada 569 baris.

Data Pre-Processing

Disini kita akan mencoba untuk membersihkan data komentar Akun Instagram Bapak Presiden Jokowi yang di ambil pada salah satu postingan nya dan mengubah nya ke dalam bentuk yang terstruktur (memisahkan setiap kalimat menjadi beberapa kata agar dapat di mengerti oleh komputer)

cleaning_pipeline <- function(tw) {
   # remove username column
    tw_ec <- tw %>% 
      select("comment")
    # replace html & url
    tw_ec_clean <- tw_ec %>% 
      mutate(comment = replace_html(comment)) %>% 
      mutate(comment = replace_url(comment))
    
    # replace emoticons dan emojis
    tw_ec_clean <- tw_ec_clean %>%
      mutate(comment = replace_html(replace_emoji(comment)))
    
    # replace mentions and hashtags
    tw_ec_clean <- tw_ec_clean %>% 
      mutate(comment = replace_tag(comment, pattern = "@([A-Za-z0-9_]+)",replacement="")) %>%  # remove mentions
      mutate(comment = replace_hash(comment, pattern = "#([A-Za-z0-9_]+)",replacement="")) # remove hashtag
    
    # replace slang word
    slang_word <- read.csv("../lexicon.csv")
    
    tw_ec_clean <- tw_ec_clean %>% 
      mutate(comment = replace_internet_slang(comment, slang = paste0("\\b",
                                                                  slang_word$slang, "\\b"),
                                            replacement = slang_word$formal, ignore.case = TRUE))
    
    
    # text stripping
    tw_ec_clean <- tw_ec_clean %>% 
      mutate(comment = strip(comment))
    
    tw_ec_clean <- tw_ec_clean %>% 
      mutate(comment = str_trim(comment, "both"))
    
      
    # change capital to lower case
    tw_ec_clean <- tw_ec_clean %>% 
      mutate(comment = str_to_lower(comment))
  
    
    # stemming, tokenizing and word cloud creation
    stemming <- function(x){
      paste(lapply(x,katadasar),collapse = " ")}
    
    tw_ec_clean <- tw_ec_clean %>% 
      mutate(comment = lapply(tokenize_words(comment),  stemming))
  }

Disini saya sudah mendefinisikan fungsi cleaning_pipeline dengan tujuan agar dapat melakukan pembersihan data text secara berulang dengan mudah jika di butuhkan pada bagian code yang lain.

Pada fungsi diatas kita melakukan serangkaian data pre-processing / data cleaning terhadap data komentar yang kita miliki. Fungsi di atas meliputi proses : - replace_html : berfungsi untuk menghilangkan elemen / tag html pada text, biasa nya di temukan setelah kita mencoba untuk menghilangkan emoji dengan fungsi replace_emoji. Secara otomatis setiap emoji yang akan di coba hilangkan akan berubah menjadi tag html. sehingga kita membutuhkan fungsi replace_html untuk menghilangkan tag html tersebut. Contoh <90>, nah tag html yang di hasil kan oleh emoji kurang lebih seperti itu, oleh karna nya kita membutuhkan replace_html untuk menghilangkan nya.

  • replace_url : berfungsi untuk menghilangkan URL yang terdapat pada text.
  • replace_emoji : berfungsi untuk menghilangkan emoji pada text.
  • replace_tag : berfungsi untuk menghilangkan tag pada text, seperti @username.
  • replace_hash : berfungsi untuk menghilangkan hash atau tagar pada text, seperti #highvaluemale
  • replace_internet_slang : berfungsi untuk menghilangkan kata-kata slang. Misal nya pada bahasa Indonesia (met => selamat, ka => kakak dan lain sebagainya). Kita akan menambahkan lexicon atau kamus Bahasa Indonesia karena kita akan membersihkan slang word pada Bahasa Indonesia
  • strip : berfungsi untuk menghilangkan simbol-simbol yang tidak relavan pada text. Misalnya (pakai BPJS… Giliran), tanda titik di balakang kata BPJS akan di hilangkan menjadi (pakai bpjs giliran).
  • str_trim : berfungsi menghilangkan whitespace / spasi pada awal dan akhir kalimat.
  • str_to_lower : berfungsi mengubah text huruf besar menjadi huruf kecil.
  • stemming : berfungsi untuk mengubah kata menjadi kata dasar nya. Misal nya membenarkan / pembenaran akan di ubah menjadi benar.

sekarang kita bisa menggunakan Function cleaning_pipeline untuk melakuakn Data Pre-Processing terhadap kolom comment

clean_insta_comment <- cleaning_pipeline(insta_comment)
head(clean_insta_comment[[1]], 1)
#> [[1]]
#> [1] "backhand index pointing up backhand index pointing up backhand index pointing up kunci sukses ekonomi indonesia di masa revolusi industri yang baru"

Dapat kita lihat di atas bahwa emoji yang di ubah oleh fungsi replace_emoji menjadi kata-kata CLDR Short Name nya yakni backhand, index, pointing up dan sebagai nya. Oleh karena itu alangkah baik nya jika kita menghilangkan kata-kata tersebut agar tidak memengaruhi hasil analisa sentimen nantinya.

idStopWordsTwo <- readLines("../stopword_id.txt")
emojiStopword <- readLines("datasets/emojiStopword.txt")

clean_insta_comment_corpus <- VCorpus(VectorSource(clean_insta_comment$comment))
clean_insta_comment_corpus <- tm_map(clean_insta_comment_corpus, removeWords, idStopWordsTwo)
clean_insta_comment_corpus <- tm_map(clean_insta_comment_corpus, removeWords, emojiStopword)
clean_insta_comment_corpus <- tm_map(clean_insta_comment_corpus, stripWhitespace)
content(clean_insta_comment_corpus[[1]])
#> [1] " kunci sukses ekonomi indonesia revolusi industri "

Disini seperti yang kita lihat diatas. CLDR Short Name dari emoji nya sudah di hilangkan. Kita memanfaatkan fungsi tm_map untuk menghilangkan setiap kata-kata emoji / CLDR Short Name yang kita temui pada text comment. Tetapi sebelum itu kita mencoba untuk membuat kolom comment menjadi bentuk Corpus, sehingga setiap observasi nya berbentuk Document dengan memanfaatkan fungsi VCorpus dan VectorSource. Lalu disini saya sudah menyiapkan kumpulan CLDR Short Name dari setiap Emoji serta Stopword (kata umum yang tidak memberikan informasi penting) bahasa Indonesia. Dengan memanfaatkan fungsi tm_map dengan parameter removeWords kita sudah bisa menghilangkan kata-kata emoji dan stopword nya. Terakhir kita menggunakan stripWhitespace untuk menghapus whitespace atau spasi di setiap kalimat.

Convert kembali Corpus ke Data Frame

clean_insta_comment_df <- data.frame(comment=unlist(sapply(clean_insta_comment_corpus, `[`, "content")), 
    stringsAsFactors=F)

clean_insta_comment_df <- clean_insta_comment_df %>% 
    mutate(comment = str_trim(comment, "both"))

rownames(clean_insta_comment_df) <- NULL

Setelah data sudah di bersihkan, kita bisa mengembalikan text comment dalam bentuk corpus ke dalam bentuk Data Frame. Memanfaatkan fungsi sapply kita akan mengubah list comment sebagai input dan output yang akan kita dapatkan adalah vector, dari vector tersebut kita akan mencoba untuk mengubah nya ke dalam bentuk Data Frame.

clean_insta_comment_df <- data.frame(comment=unlist(sapply(clean_insta_comment_corpus, `[`, "content")), 
    stringsAsFactors=F)

# hapus spasi pada awal dan akhir setiap text comment 
clean_insta_comment_df <- clean_insta_comment_df %>% 
    mutate(comment = str_trim(comment, "both"))

head(clean_insta_comment_df)
#>                                                                                                                                                                                                                                                                                                                                                                                                            comment
#> 1.content                                                                                                                                                                                                                                                                                                                                                         kunci sukses ekonomi indonesia revolusi industri
#> 2.content                                                                                                                                                                                                                                                                                                                                                                                                        h
#> 3.content                                                                                                                                                                                                                                                                                            anak ku baca komen nak mu juang jual f ll w rs mur h igtiktokshoppedll bantu beli ya kakak ganteng nan cantik
#> 4.content                                                                                                                                                                                                                                                                                                                                                                                            sungkan promo
#> 5.content presiden tulus jujur bangun indonesia pilih kasih anak indonesia timur terima kasih dek peduli adil maju timur indonesia sayang periode sungguh bangga presiden jokowi bangga anak indonesia presiden dunia globe showing asiaaustralia bangga dunia hormat harga dedikasi integritas jujuran berani sederhana kerendahhatianmu pandai loyalitas sehatsehat dek tuhan berkat presiden keluarga amin suit
#> 6.content                                                                                                                                                                                                                                                                                                          kulo asli blora pakalhamdulillah jl raya prov ds candi pasar todanan bagus banget latih gastrek

Rownames dari data frame kita masih terlihat aneh dan tidak informatif. Mari kita hilangkan rownames nya.

rownames(clean_insta_comment_df) <- NULL
head(clean_insta_comment_df)
#>                                                                                                                                                                                                                                                                                                                                                                                                    comment
#> 1                                                                                                                                                                                                                                                                                                                                                         kunci sukses ekonomi indonesia revolusi industri
#> 2                                                                                                                                                                                                                                                                                                                                                                                                        h
#> 3                                                                                                                                                                                                                                                                                            anak ku baca komen nak mu juang jual f ll w rs mur h igtiktokshoppedll bantu beli ya kakak ganteng nan cantik
#> 4                                                                                                                                                                                                                                                                                                                                                                                            sungkan promo
#> 5 presiden tulus jujur bangun indonesia pilih kasih anak indonesia timur terima kasih dek peduli adil maju timur indonesia sayang periode sungguh bangga presiden jokowi bangga anak indonesia presiden dunia globe showing asiaaustralia bangga dunia hormat harga dedikasi integritas jujuran berani sederhana kerendahhatianmu pandai loyalitas sehatsehat dek tuhan berkat presiden keluarga amin suit
#> 6                                                                                                                                                                                                                                                                                                          kulo asli blora pakalhamdulillah jl raya prov ds candi pasar todanan bagus banget latih gastrek

Tujuan kita melakukan perubahan Corpus ke Data Frame adalah untuk melakukan tokenization atau pemisahan kalimat menjadi beberapa kata-kata. Kita membutuhkan tokenization agar mempermudah kita di dalam melakukan analisa sentimen menggunakan pendekatan berbasis Lexicon.

Load NRC Lexicon by Saif Mohammad berbahasa Indonesia

senti_id_word <- read.csv("nrc_lexicon_en_id.csv")
senti_id_word <- senti_id_word %>% 
  rename("Indonesia" = "Indonesian..id.") %>% 
  select(-English..en....1)

head(senti_id_word)
#>   X    Indonesia Anticipation Fear Sadness Trust Anger Disgust Joy Surprise
#> 1 1      kembali            0    0       0     0     0       0   0        0
#> 2 2       sempoa            0    0       0     1     0       0   0        0
#> 3 3  mengabaikan            0    1       1     0     0       0   0        0
#> 4 4 ditinggalkan            0    1       1     0     1       0   0        0
#> 5 5 ditinggalkan            0    1       1     0     1       0   0        1
#> 6 6       mereda            0    0       0     0     0       0   0        0
#>   Positive Negative
#> 1        0        0
#> 2        0        0
#> 3        0        1
#> 4        0        1
#> 5        0        1
#> 6        0        0

Pada NRC Lexicon diatas, sudah tersedia klasifikasi kata-kata yang meliputi Emotion Classification dan Positve & Negative Classfiication sebanyak 14.182 kata.

Mari kita lakukan

insta_clean_tidy <- DocumentTermMatrix(clean_insta_comment_corpus)

Disini kita mencoba untuk mengubah text comment kita yang tadinya berbentuk Data Frame menjadi DocumentTermMatrix. DTM adalah adalah proses dimana kita mengubah text menjadi beberapa term (kata-kata) dengan frekuensi dari setiap kata-kata tersebut. DTM berada pada level Document yang artinya memecah kata-kata dari suatu kalimat per observasi atau baris nya.

insta_clean_tidy <- tidy(insta_clean_tidy)

Untuk mendapatkan tampilan yang lebih rapi, kita menggunakan fungsi tidy() yang otomatis mengubah DTM ke dalam bentuk tibble. Tibble sendiri sama seperti Data Frame cuman terdapat beberapa method khusus yang dapat kita gunakan pada format data tibble.

insta_clean_tidy_sentimen <- 
  inner_join(insta_clean_tidy, senti_id_word, by = c("term" = "Indonesia")) %>% 
  select(term, Positive, Negative) %>% 
  mutate(polarity = Positive - Negative,
         label = ifelse(polarity < 0, "negatif", "positif"))

Sekarang kita akan melakukan analisa sentimen dengan fungsi inner_join. Jadi setiap kata-kata yang sama dengan kata-kata yang terdapat pada NRC Lexicon nya akan otomatis di klasifikasi kan apakah masuk ke dalam kategori Positve atau Negatif. Setelah menklasifikasikan kan kata-kata yang termasuk ke dalam Positif dan Negatif. Kita akan melakukan Scoring dengan mengurangi total kata positif dan negatif pada setiap observasi atau baris komentar nya. Jika lebih kecil dari 0 atau maka negatif, jika lebih besar dari 0 maka positif dan jika 0 maka netral.

# Plot
ggplot(
  insta_clean_tidy_sentimen[1:100,], 
  aes(reorder(term, polarity), polarity, fill = label)
) +
  geom_bar(stat = "identity") + 
  ggtitle("Sentiment Word Frequency Positive, Netral & Negatif") + 
  theme_gdocs() +
  labs(x = "Words", y = "Polarity") +
  theme(axis.text.x = element_text(angle = 90, vjust = -0.1))

Disini kita mencoba untuk memvisulisasikan kata-kata positif, netral dan negatif menggunakan bar plot. Terlihat kata yang menjulang ke atas atau berwarna biru dengan score diatas 0 adalah kata positif dan kata yang menjulang ke bawah dengan score di bawah 0 adalah kata negatif.

senti_analyze <- clean_insta_comment_df %>%
  mutate(linenumber = row_number()) %>% #line number for later sentence grouping 
  unnest_tokens(word, comment) %>% 
  inner_join(senti_id_word, by = c("word" = "Indonesia")) %>%
  group_by(linenumber) %>% #group by for sentence polarity
    summarise(sentiment = sum(Positive - Negative)) %>% # final sentence polarity from words
    left_join(
    clean_insta_comment_df %>%
    mutate(linenumber = row_number()) #get the actual text next to the sentiment value
  ) 

senti_analyze_label <- senti_analyze %>% 
  mutate(label = case_when(sentiment < 0 ~ "negatif",
                           sentiment > 0 ~"positif",
                           TRUE ~ "netral"))

head(senti_analyze)
#> # A tibble: 6 × 3
#>   linenumber sentiment comment                                                  
#>        <int>     <int> <chr>                                                    
#> 1          1         0 kunci sukses ekonomi indonesia revolusi industri         
#> 2          3         4 anak ku baca komen nak mu juang jual f ll w rs mur h igt…
#> 3          5        31 presiden tulus jujur bangun indonesia pilih kasih anak i…
#> 4          6         2 kulo asli blora pakalhamdulillah jl raya prov ds candi p…
#> 5          7        -1 bendung lupa impor                                       
#> 6          8         0 tunggu gerbang temuin

Di atas kembali kita melakukan analisa sentimen dengan fungsi inner_join. Yang berbeda disini kita melakukan left join yang artinya kita akan mengembalikan semua hasil sentimen positif dan negatif pada tabel sebelah kiri (clean_insta_comment_df) lalu mencari matching row atau baris yang sama dengan tabel kanan (clean_insta_comment_df sebelum inner join) dengan kolom linenumber sebagai key column nya. Di dapatkan lah kolom comment yang utuh dengan hasil sentimen nya.

Berdasarkan hasil sentimen diatas, kita juga dapat melihat proporsi kelas Positif, Netral dan Negatif nya menggunakan Pie Chart

# Data transformation
df <- senti_analyze_label %>% 
  group_by(label) %>% # Variable to be transformed
  count() %>% 
  ungroup() %>% 
  mutate(perc = `n` / sum(`n`)) %>% 
  arrange(perc) %>%
  mutate(labels = scales::percent(perc))

pie <- ggplot(df, aes(x = "", y = perc, fill = label)) +
  geom_col(color = "black") +
  geom_label(aes(label = labels), color = c("white", "white", "white"),
            position = position_stack(vjust = 0.5),
            show.legend = FALSE) +
  guides(fill = guide_legend(title = "Komentar")) +
  scale_fill_viridis_d() +
  coord_polar(theta = "y") + 
  theme_void()

pie + scale_fill_manual(values=c("#990000", "#024ebf", "#00a110")) 

Dengan melakukan aggregasi atau perhitungan berdasarkan setiap label nya, didapatkan lah persentasi setiap label nya. Disini dapat kita simpulkan komentar yang paling banyak adalah komentar Positif dan Netral. Ini masuk akal jika mengingat data komentar yang kita ambil berasal dari akun Instagram Bapak Presiden Jokowi yang notaben merupakan orang nomor satu di Indonesia. Sehingga di dalam berkomentar negatif pun para netizen bisa berpikir dua kali, karena resiko nya yang besar.

Berikut gambar persebaran atau distribusi dari setiap label kata-kata positif, netral dan negatif menggunakan density dan histogram serta line plot. Pad histogram diatas dapat kita lihat keseluruhan komentar cendrung banyak di klasifikasi kan ke dalam label positif dan netral. Kita dapat melihat apakah klasifikasi sentimen score nya sudah cukup akurat apa belum dengan melihat data komentar yang telah di lakukan sentimen scoring.

senti_analyze_label %>% 
  filter(label == "positif") %>% 
  select(label, comment) %>% 
  head(10)
#> # A tibble: 10 × 2
#>    label   comment                                                              
#>    <chr>   <chr>                                                                
#>  1 positif anak ku baca komen nak mu juang jual f ll w rs mur h igtiktokshopped…
#>  2 positif presiden tulus jujur bangun indonesia pilih kasih anak indonesia tim…
#>  3 positif kulo asli blora pakalhamdulillah jl raya prov ds candi pasar todanan…
#>  4 positif keren                                                                
#>  5 positif terimakasih presiden jokowi sukses gubernur jateng ganjar pranowo tu…
#>  6 positif sehat                                                                
#>  7 positif pacar sambung hotspot teman putus                                    
#>  8 positif sehat jokowi                                                         
#>  9 positif selamat malam moga sehat                                             
#> 10 positif sok proud you sok much mr president jujur bangga best president bp p…
senti_analyze_label %>% 
  filter(label == "netral") %>% 
  select(label, comment) %>% 
  head(10)
#> # A tibble: 10 × 2
#>    label  comment                                                   
#>    <chr>  <chr>                                                     
#>  1 netral kunci sukses ekonomi indonesia revolusi industri          
#>  2 netral tunggu gerbang temuin                                     
#>  3 netral pesan ayam kodok dapur mama naga                          
#>  4 netral bantu beli beras                                          
#>  5 netral loker                                                     
#>  6 netral jokowi tolong wanita jual belikan bal pengin pulang larang
#>  7 netral salam bal pakdee ku                                       
#>  8 netral bendung desa kalinanas wes rampung                        
#>  9 netral sumber katahanan pangan air                               
#> 10 netral wisata gunung kemungkus
senti_analyze_label %>% 
  filter(label == "negatif") %>% 
  select(label, comment) %>% 
  head(10)
#> # A tibble: 10 × 2
#>    label   comment                                                              
#>    <chr>   <chr>                                                                
#>  1 negatif bendung lupa impor                                                   
#>  2 negatif jokowi nge slot kalah ya                                             
#>  3 negatif presiden tolong jual belikan bal harga murah larang pulng            
#>  4 negatif petan kampung jual beras harga turun pakenggak banding biaya sawah   
#>  5 negatif kawasan tandusya kemarau kering                                      
#>  6 negatif jalan batas                                                          
#>  7 negatif tolong lihat jalan kabupaten tasik sungai kering batu batu mohon ban…
#>  8 negatif moga harga minyak turun sembako turun pusing emak bagibagi gajih sua…
#>  9 negatif assalamualaikum aspal jalan raya m rusak ampun jeneng damelke aspal …
#> 10 negatif sayange kulo wing sakit ra biso lihat jenegan

Jika dilihat dari contoh komentar dengan ketiga label positif, negatif dan netral diatas. Kita sudah cukup baik melakukan klasifikasi dengan pendeketan Lexicon. Setiap komentar dengan masing-masing label terlihat sesuai dengan realita nya. Kalimat Positif banyak berasal dari kata-kata tulus, jujur, terima kasih, selamat dan sebagainya. Sedangkan kata-kata negatif banyak berasal dari kata-kata tolong, turun harga minyak goreng sembako, jalan rusak dan sebagai nya. Begitu pun dengan yang label netral.

insta_count <- insta_clean_tidy %>% 
  count(document)

insta_join_count <- inner_join(insta_clean_tidy, insta_count) %>% 
  select(document, n, term)

Sekarang kita akan coba untuk melakukan analisa terkait effort (usaha penulis di dalam menulis komentar panjang atau pendek nya) dan polarity (scoring sentimen). Tujuan nya adalah untuk mengatahui apakah korelasi atau hubungan panjang atau pendek komentar yang di tulis user dengan score sentimen yang di dapat. Apakah semakin panjang komentar yang di tulis semakin positif atau semakin pendek komentar yang di tulis maka semakin negetif kata-kata nya. Insight yang bisa kita dapatkan dari sini ialah interaktifitas dari netizen yang berkomentar. Karena jika semakin panjang komentar yang di tulis lalu semakin positif score sentimen nya, itu artinya user yang berkomentar berkemungkinan besar memberikan saran dan masukan di samping kata-kata yang positif.

pos_neg_with_effort <- inner_join(insta_join_count, senti_id_word, by = c("term" = "Indonesia")) %>% 
  group_by(document, term) %>% 
  summarise(sentiment = sum(Positive - Negative)) %>% 
  left_join(insta_join_count)

pos_neg_pol <- pos_neg_with_effort %>%
  mutate(
    pol = ifelse(
      sentiment >= 0, 
      "Positive", 
      "Negative"
    )
  )

Setelah kita menghitung kata-kata di setiap komentar nya dengan fungsi count, kita kembali melakukan join sesuai dengan nomor document nya agar dapat di hitung sentimen score nya.

# Plot
ggplot(
  pos_neg_pol, 
  aes(sentiment, n, color = pol)
) + 
  geom_point(alpha = 0.25) +
  geom_smooth(method = "lm", se = FALSE) +
  theme_gdocs() +
  ggtitle("Relationship between word effort & polarity")

Terlihat pada plot scatter diatas. Rata-rata komentar yang panjang memiliki sentimen score yang tinggi. Tetapi disini bisa kita lihat komentar yang pendek lebih mendominasi dan sentimen score yang di peroleh juga semakin kecil. Itu artinya rata-rata netizen yang berkomentar cendrung tidak terlalu interaktif karena lebih banyak berkomentar secara singkat. Untuk komentar yang negatif berbanding terbalik dengan yang positif walaupun sama-sama di dominasi oleh komentar yang pendek. Tetai disini yang menarik ialah semakin panjang komentar negatif yang di tulis maka sentime score nya semakin besar. Ini masuk akal jika kita mengingat keluh kesah rakyat Indonesia kepada Bapak Presiden Jokowi. Mulai dari kenaikan harga minyak, kerusakan jalan dan sebagainya.

Sekarang mari kita coba untuk memvisualisasikan frekuensi komparasi kata-kata positif dengan negatif menggunakan WordCloud

pol_subsections <- function(df) {
  x.pos <- subset(df$comment, df$sentiment > 0)
  x.neg <- subset(df$comment, df$sentiment < 0)
  x.pos <- paste(x.pos, collapse = " ")
  x.neg <- paste(x.neg, collapse = " ")
  all.terms <- c(x.pos, x.neg)
  return(all.terms)
}

Disini saya sudah mendefinisikan fungsi pol_subsections dengan tujuan untuk menggabungkan komentar dengan sentimen score diatas 0 (positif) dan komentar dengan sentimen score di bawah 0 (negatif). Lalu kita gabungkan dengan fungsi paste().

# Custom function
all_terms <- pol_subsections(senti_analyze_label)

# Make a corpus
all_corpus <- all_terms %>%
  VectorSource() %>% 
  VCorpus()
# Basic TDM
all_tdm <- TermDocumentMatrix(
  all_corpus
) %>%
  as.matrix() %>%
  set_colnames(c("positive", "negative"))
# Make a comparison cloud
comparison.cloud(
  all_tdm,
  max.words = 50,
  colors = c("darkgreen", "darkred")
)

Dengan memanfaatkan fungsi comparison.cloud, kita dapat membandingkan kata-kata positif ataupun negatif. Tetapi sebelum itu kita wajib untuk mengubah data text kita ke dalam TermDocumentMatrix (TDM) agar dapat di hitung setiap frekuensi kata-kata negatif ataupun positif nya. Kata-kata positif banyak berasal dari kata Sehat. Ini artinya banyak yang mendoakan Bapak Presiden Jokowi. Sementar kata-kata negatif berasal dari kata-kata biaya, mohon dan sebagainya. Ini dapat kita kaitkan dengan biaya atau harga minyak goreng yang mahal di masa sekarang sehingga banyak masyarakat yang memohon untuk di turunkan terkait harga minyak goreng nya.

Sekarang kita akan mencoba untuk mengklasifikasi kan emosi yang terkandung pada setiap kata-kata positif ataupun negatif yang telah kita miliki.

sentiment_emotion_3 <- clean_insta_comment_df %>%
  unnest_tokens(word, comment) %>% 
  inner_join(senti_id_word, by = c("word" = "Indonesia")) %>% 
  select(-X) 

head(sentiment_emotion_3)
#>       word Anticipation Fear Sadness Trust Anger Disgust Joy Surprise Positive
#> 1    kunci            0    0       0     0     0       0   0        0        0
#> 2    kunci            0    0       0     0     0       0   0        0        0
#> 3   sukses            1    0       0     1     0       0   1        0        1
#> 4  ekonomi            0    0       0     0     0       0   0        0        0
#> 5  ekonomi            0    0       0     1     0       0   0        0        0
#> 6 revolusi            1    1       1     0     1       0   0        1        1
#>   Negative
#> 1        0
#> 2        1
#> 3        0
#> 4        0
#> 5        0
#> 6        1

Diatas kita kembali melakukan analisa sentimen dengan mengklasifikasikan kata-kata setiap observasi nya ke dalam Emotion Classification. Total terdepat jenis emosi premier. Diambil dari konsep Plutchik’s wheel of emotions. Dimana memiliki 8 emosi utama / premier. Karena dari 8 emosi ini memiliki turunan nya masing-masing. Semakin kontras warna nya semakin kuat emosi nya dan semakin pudar warna nya semakin rendah emosi nya.

senti_pos <- sentiment_emotion_3 %>% filter(Positive == 1) %>%
  select("Anticipation",
         "Fear",
         "Sadness",
         "Trust",
         "Anger",
         "Disgust",
         "Joy",
         "Surprise")
senti_pos <- pivot_longer(
  senti_pos,
  c(
    "Anticipation",
    "Fear",
    "Sadness",
    "Trust",
    "Anger",
    "Disgust",
    "Joy",
    "Surprise"
  ),
  names_to = "emotion",
  values_to = "count"
)


senti_neg <- sentiment_emotion_3 %>% filter(Negative == 1) %>% 
  select("Anticipation",
         "Fear",
         "Sadness",
         "Trust",
         "Anger",
         "Disgust",
         "Joy",
         "Surprise")
senti_neg <- pivot_longer(
  senti_neg,
  c(
    "Anticipation",
    "Fear",
    "Sadness",
    "Trust",
    "Anger",
    "Disgust",
    "Joy",
    "Surprise"
  ),
  names_to = "emotion",
  values_to = "count"
)

head(senti_neg, 10)
#> # A tibble: 10 × 2
#>    emotion      count
#>    <chr>        <int>
#>  1 Anticipation     0
#>  2 Fear             0
#>  3 Sadness          0
#>  4 Trust            0
#>  5 Anger            0
#>  6 Disgust          0
#>  7 Joy              0
#>  8 Surprise         0
#>  9 Anticipation     1
#> 10 Fear             1

Kita ubah menjadi bentuk long format agar mudah di kalkulasi kan menggunkan fungsi sum()

sentiment_pos_emotion_agg <- senti_pos %>% 
  group_by(emotion) %>% 
  summarize(total_count = sum(count)) %>% 
  mutate(label = "positif")

sentiment_neg_emotion_agg <- senti_neg %>% 
  group_by(emotion) %>% 
  summarize(total_count = sum(count))  %>% 
  mutate(label = "negatif")

Aggregasikan menggunakan fungsi sum dan jangan lupa untu mengelompokkan nya dengan fungsi group_by berdasarkan kolom emotion

join_pos_neg <- rbind(sentiment_pos_emotion_agg, sentiment_neg_emotion_agg)

scores <- join_pos_neg %>% 
  spread(label, total_count)

chartJSRadar(scores)

Kita akan menggabungkan aggregasi kata-kata positif dengan negatif menggunakan rbind. Dan setelah itu kita akan mencoba untuk spread atau mengubah bentuk kolom nya menjadi wide format berdasarkan kolom label dan total_count. Terakhir tinggal panggil fungsi chartJSRadar dari package radarchart. Dapat kita simpulkan emosi yang mendominasi pada kata-kata positif ialah trust atau kepercayaan. Ini artinya banyak rakyat yang menanamkan kepercayaan kepada Bapak Presiden Jokowi. Disamping itu untuk kata-kata negatif nya banyak berasal dari Fear dan Sadness atau ketakutan dan kesedihan. Ini bisa kita artikan sebagai bentuk ketakutan masyarakat terhadap permasalahan negara. Contoh nya seperti harga minya goreng yang kiat meningkat, jalan rusak, air bersih dan sebagainya.

Berikut contoh emotion classification nya menggunakan word cloud. Jadi bisa lebih jelas kata-kata apa saja yang termasuk ke dalam klasifikasi emosi tertentu.

Output

Output dari project ini berupa Dasboard Analysis yang menampilkan Exploratory Data untuk menunjukkan kata-kata yang cendrung Negatif, Netral ataupun Positif pada suatu komentar postingan Akun Instagram. Di samping itu juga akan di sertakan Klasifikasi Emosi dari setiap komentar yang ada, mulai dari anger, fear, anticipation, trust, surprise, sadness, joy, dan disgust. User juga dapat melakukan analisa berdasarkan suatu postingan Akun Instagram tertentu sesuai dengan yang di inginkan, dengan menyediakan URL postingan Akun Instagram yang di tuju. Terdapat juga beberapa Inputan yang bisa di sesuiakan dengan kengininan User agar menampilkan Plot atau Visualisasi tertentu.

Berikut tampilan Design Wireframe Dashboard Analysis nya

Referensi