Basic Computational Journalism - Text Analysis

Raden Muhammad Hadi

2019-03-23

Instalasi dan memuat library

install.packages("rvest")
install.packages("tidyverse")
install.packages("tidytext")
install.packages("hunspell")
install.packages("textClean")
install.packages("wordcloud2")

library(rvest)
library(tidyverse)
library(tidytext)
library(hunspell)
library(textclean)
library(wordcloud2)

Mining Data From Webpage

Mengambil judul berita

Berikut adalah script dasar untuk ekstrak teks dari suatu halaman html:

# Dari halaman web
read_html("alamat_link") %>% 
  # ekstrak data dari 1 node berdasarkan css selector
  html_node(css = "css_selector") %>% 
  # ekstrak teks dari node tersebut lalu bersihkan
  html_text(trim = T)

Contoh: Mengambil Judul Berita

read_html("https://money.kompas.com/read/2019/03/22/152039326/inflasi-rendah-gejolak-global-mereda-kok-suku-bunga-acuan-bi-tidak-turun") %>% 
  html_node(css = ".read__title") %>% 
  html_text()

Contoh: Mengambil Teks Berita

# Dari link
read_html("https://money.kompas.com/read/2019/03/22/152039326/inflasi-rendah-gejolak-global-mereda-kok-suku-bunga-acuan-bi-tidak-turun") %>% 
  # baca semua nodes berdasarkan css selector
  html_nodes(css = ".read__content p") %>% 
  # ambil teks lalu bersihkan spasi
  html_text(trim = T)
# Dari link yang diberikan
read_html("https://money.kompas.com/read/2019/03/22/152039326/inflasi-rendah-gejolak-global-mereda-kok-suku-bunga-acuan-bi-tidak-turun") %>%
  # Ambil semua node berdasarkan css selector tertentu
  html_nodes(css = ".read__content p") %>% 
  # ekstrak teks dari node tersebut lalu bersihkan spasi
  html_text(trim = T) %>% 
  # gabung semua vektor menjadi 1 dipisah dengan garis baru
  paste0(collapse = "\n")

Contoh: Mengambil judul dan paragraf lalu simpan dalam teks

# masukkan link ke alamat_link
alamat_link <- "https://money.kompas.com/read/2019/03/22/152039326/inflasi-rendah-gejolak-global-mereda-kok-suku-bunga-acuan-bi-tidak-turun"

# masukkan hasilnya ke judul_berita
judul_berita <- 
  # Dari alamat link yang diberikan
  alamat_link %>%
  # Setelah dibaca html nya
  read_html() %>%
  # Dari node dengan kelas 'read__title'
  html_node(css = ".read__title") %>%
  # Diambil teks nya setelah dibersihkan dari spasi
  html_text(trim = T)


# Masukkan hasilnya ke isi_berita
isi_berita <- 
  # dari alamat link yang diberikan
  alamat_link %>%
  # baca html nya
  read_html() %>%
  # Dari semua node berdasarkan kelas '.read__content' lalu tag 'p'
  html_nodes(css = ".read__content p") %>% 
  # Diambil teks nya lalu bersihkan spasi
  html_text(trim = T) %>% 
  # Setelah teks nya digabung semua vektor menjadi 1 dipisah dengan garis baru
  paste0(collapse = "\n")

# Buat dataframe untuk menyimpan berita
data_berita <- data_frame(judul = judul_berita, isi = isi_berita)

Kita dapat menjadikan semua perintah di atas menjadi fungsi seperti berikut:

ambil_berita <- function(link_berita) {
  # masukkan hasilnya ke judul_berita
judul_berita <- 
  # Dari alamat link yang diberikan
  link_berita %>%
  # Setelah dibaca html nya
  read_html() %>%
  # Dari node dengan kelas 'read__title'
  html_node(css = ".read__title") %>%
  # Diambil teks nya setelah dibersihkan dari spasi
  html_text(trim = T)


# Masukkan hasilnya ke isi_berita
isi_berita <- 
  # dari alamat link yang diberikan
  link_berita %>%
  # baca html nya
  read_html() %>%
  # Dari semua node berdasarkan kelas '.read__content' lalu tag 'p'
  html_nodes(css = ".read__content p") %>% 
  # Diambil teks nya lalu bersihkan spasi
  html_text(trim = T) %>% 
  # Setelah teks nya digabung semua vektor menjadi 1 dipisah dengan garis baru
  paste0(collapse = "\n")

# Buat dataframe untuk menyimpan berita
data_berita <- data_frame(judul = judul_berita, isi = isi_berita)
}

# Uji function yang dibuat
berita_yang_diambil <- ambil_berita("https://money.kompas.com/read/2019/03/22/152039326/inflasi-rendah-gejolak-global-mereda-kok-suku-bunga-acuan-bi-tidak-turun")

# lihat isi berita yang diambil
berita_yang_diambil

Menyimpan berita kedalam format csv:

# Simpan kedalam format csv dengan separasi ';'
write_csv2(x = berita_yang_diambil,
           # masukkan kedalam direktori data dan beri nama
           # 'artikel-berita.csv'
           path = "data/berita_yang_diambil",
           # gabung dengan data terbaru jika ada
           append = T)

Basic Pre-Processing

Lowercasing dan Tokenization

berita %>% 
  select(isi) %>% 
  unnest_tokens(output = "tokenized", input = "isi")

Remove Unnecessary Part of String

# remove everithing inside paranthesis
berita$isi[1] %>% 
  str_replace(pattern = "\\(\\d+\\)", replacement = "")
# removing paranthesis and date inside it
berita[1,2] %>% 
  gsub(pattern = "[()]", replacement = "") %>% 
  replace_date(replacement = "")
# Removing character before '-'
berita[1,2] %>% 
  str_replace(pattern = ".*-", "") %>% 
  str_trim()

stemming

hunspell_stem("mempertanggungjawabkan", dict = dictionary("id_ID"))[[1]]
berita[1,2] %>% 
  unnest_tokens(output = "tokenized", "isi") %>% 
  mutate(tokenized = hunspell_stem(tokenized, dict = dictionary("id_ID"))) %>% 
  unnest()

Membuang stopwords

# Mengambil stopword
stopwords_indo <- read_csv("https://raw.githubusercontent.com/masdevid/ID-Stopwords/master/id.stopwords.02.01.2016.txt", col_names = "stopword")

berita[1,2] %>% 
  unnest_tokens(output = "tokenized", input = "isi") %>% 
  anti_join(y = stopwords_indo, by = c("tokenized"="stopword"))

Visualisasi Wordcloud

berita[1,2] %>%
  mutate(isi = gsub(pattern = "[()]", replacement = "", x = isi))%>% 
  mutate(isi = replace_date(replacement = "", x = isi)) %>%
  mutate(isi = str_replace(pattern = ".*-", replacement = "",string = isi)) %>%
  unnest_tokens(output = "tokenized", input = "isi") %>% 
  mutate(tokenized = hunspell_stem(tokenized, dict = dictionary("id_ID"))) %>% 
  unnest() %>% 
  anti_join(y = stopwords_indo, by = c("tokenized"="stopword")) %>% 
  count(tokenized, sort = T) %>% 
  wordcloud2()

Visualisasi diagram batang

berita[1,2] %>%
  mutate(isi = gsub(pattern = "[()]", replacement = "", x = isi))%>% 
  mutate(isi = replace_date(replacement = "", x = isi)) %>%
  mutate(isi = str_replace(pattern = ".*-", replacement = "",string = isi)) %>%
  unnest_tokens(output = "tokenized", input = "isi") %>% 
  mutate(tokenized = hunspell_stem(tokenized, dict = dictionary("id_ID"))) %>% 
  unnest() %>% 
  anti_join(y = stopwords_indo, by = c("tokenized"="stopword")) %>% 
  count(tokenized, sort = T) %>% 
  mutate(tokenized = reorder(tokenized,n)) %>% 
  top_n(10) %>% 
  ggplot(aes(x = tokenized, y = n)) +
  geom_col() +
  coord_flip() +
  labs(
    x = "Kata",
    y = "Frekuensi",
    title = "Frekuensi Kata pada Berita"
  )

Basic Sentiment Analysis

Kita akan melakukan sentimen analisis berdasarkan leksikon. Pertama, ambil stopword pada link berikut:

read_csv("https://raw.githubusercontent.com/masdevid/ID-OpinionWords/master/negative.txt", col_names = "kata") %>% 
  mutate(sentimen = "negatif") -> negatif

read_csv("https://raw.githubusercontent.com/masdevid/ID-OpinionWords/master/positive.txt", col_names = "kata") %>% 
  mutate(sentimen = "positif") -> positif

bind_rows(positif, negatif) -> sentimen_indo
berita %>%
  mutate(isi = gsub(pattern = "[()]", replacement = "", x = isi))%>% 
  mutate(isi = replace_date(replacement = "", x = isi)) %>%
  mutate(isi = str_replace(pattern = ".*-", replacement = "",string = isi)) %>%
  unnest_tokens(output = "tokenized", input = "isi") %>% 
  mutate(tokenized = hunspell_stem(tokenized, dict = dictionary("id_ID"))) %>% 
  unnest() %>% 
  anti_join(y = stopwords_indo, by = c("tokenized"="stopword")) %>% 
  inner_join(y = sentimen_indo, by = c("tokenized" = "kata")) %>% 
  group_by(judul, tokenized) %>% 
  count(sentimen) %>% 
  ungroup() %>% 
  spread(sentimen, n, fill = 0) %>% 
  mutate(total_sentimen = positif - negatif) %>% 
  group_by(judul) %>% 
  summarise(total_sentimen = sum(total_sentimen)) -> sentimen_berita

Visualisasi Sentimen

sentimen_berita %>% 
  ggplot(aes(x = judul, y = total_sentimen)) +
  geom_col() + 
  coord_flip()
sentimen_berita %>% 
  mutate(status = ifelse(total_sentimen >= 0, "positif", "negatif")) %>% 
  ggplot(aes(x = judul, y = total_sentimen, fill = status)) +
  geom_col() + 
  coord_flip()