Course Map

Introduction

Pada course kali ini, kita akan menggunakan package tidyverse yang menggunakan konsep tidy dalam melakukan transformasi data.

Beberapa package umum yang terdapat di dalam tidyverse antara lain:

  • ggplot2: data visualisation
  • dplyr: data manipulation
  • tidyr: data tidying
  • readr: data import
  • purrr: functional programming
  • tibble: modern data frame
  • stringr: working with strings, regular expression
  • forcats: working with factors
options(scipen = 99) # me-non-aktifkan scientific notation
library(tidyverse) # koleksi beberapa package R
library(dplyr) # grammar of data manipulation
library(readr) # membaca data

Data Transformation using dplyr

dplyr adalah package khusus yang mempermudah kita dalam melakukan data wrangling. Tahapan data wrangling yang umum:

  • Inspeksi data
  • Seleksi kolom
  • Filter baris
  • Membuat atau mengubah kolom
  • Agregasi data
  • Mengurutkan baris

Official Documentation & Cheatsheet dplyr: https://dplyr.tidyverse.org/

Load Data

Biasanya kita menggunakan fungsi read.csv() untuk membaca data. Kali ini mari kita coba menggunakan fungsi read_csv() dari library readr untuk membaca data YouTube Trending 2017, All Unique Videos.

vids <- read_csv("data_input/youtubetrends.csv")
head(vids)

Perbedaan menggunakan read_csv() dibandingkan read.csv():

  • read_csv() membaca CSV ke dalam bentuk tibble (modern dataframe), sering digunakan untuk menghandle data yang besar.
  • read_csv() mendeteksi kolom bertipe data tanggal dan mengubahnya secara langsung.

glimpse(): inspeksi data

# base
str(vids)
# dplyr
glimpse(vids)
#> Rows: 2,986
#> Columns: 16
#> $ trending_date          <date> 2017-11-14, 2017-11-14, 2017-11-14, 2017-11-14…
#> $ title                  <chr> "WE WANT TO TALK ABOUT OUR MARRIAGE", "The Trum…
#> $ channel_title          <chr> "CaseyNeistat", "LastWeekTonight", "Rudy Mancus…
#> $ category_id            <chr> "People and Blogs", "Entertainment", "Comedy", …
#> $ publish_time           <dttm> 2017-11-13 12:13:01, 2017-11-13 02:30:00, 2017…
#> $ views                  <dbl> 748374, 2418783, 3191434, 343168, 2095731, 1191…
#> $ likes                  <dbl> 57527, 97185, 146033, 10172, 132235, 9763, 1599…
#> $ dislikes               <dbl> 2966, 6146, 5339, 666, 1989, 511, 2445, 778, 11…
#> $ comment_count          <dbl> 15954, 12703, 8181, 2146, 17518, 1434, 1970, 34…
#> $ comments_disabled      <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
#> $ ratings_disabled       <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
#> $ video_error_or_removed <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
#> $ publish_hour           <dbl> 12, 2, 14, 6, 13, 14, 0, 16, 9, 8, 21, 22, 12, …
#> $ publish_when           <chr> "8am to 3pm", "12am to 8am", "8am to 3pm", "12a…
#> $ publish_wday           <chr> "Monday", "Monday", "Sunday", "Monday", "Sunday…
#> $ timetotrend            <chr> "1", "1", "2", "1", "2", "1", "2", "2", "1", "1…

Deskripsi kolom:

  • trending_date: tanggal trending
  • title: judul video
  • channel_title: nama channel YouTube
  • category_id: kategori video
  • publish_time: tanggal upload video
  • views: jumlah views
  • likes: jumlah likes
  • dislikes: jumlah dislikes
  • comment_count: jumlah komentar
  • comment_disabled: apakah kolom komentar tidak diaktifkan
  • ratings_disabled: apakah rating video tidak diaktifkan
  • video_error_or_removed: apakah video dihapus
  • publish_hour: jam publish
  • publish_when: periode waktu publish
  • publish_wday: hari publish
  • timetotrend: jumlah hari yang dibutuhkan untuk trending

select(): seleksi kolom

Misalkan kita ingin mengambil kolom trending_date dan title saja.

# base
vids[,c("trending_date", "title")]

dplyr: select(data, kolom yg ingin diambil/dibuang)

# dplyr
select(.data = vids, trending_date, title)
# alternatif mengambil kolom berdasarkan substringnya
# tanda '!' digunakan untuk kondisi kebalikannya (tidak ada substring publish)
# fungsi matches lebih general dibanding contains (hanya untuk string)
select(.data = vids, !matches(c('publish', 'time')))

Misalkan kita ingin membuang kolom comments_disabled, ratings_disabled, dan video_error_or_removed karena tidak digunakan:

# base: harus menggunakan index
vids[,-c(10,11,12)]
# dplyr
select(.data = vids, -comments_disabled, -ratings_disabled, -video_error_or_removed)
# alternatif penulisan, agar tidak perlu menuliskan tanda - berulang kali
select(.data = vids, -c(comments_disabled, ratings_disabled, video_error_or_removed))

filter(): filter baris

Misalkan kita ingin mengambil video dari kategori “Music” yang memiliki views lebih dari 1 juta.

# base
vids[vids$category_id == "Music" & vids$views > 1000000,]

Catatan: - filter(.data, kondisi1, kondisi2) sama dengan filter(.data, kondisi1 & kondisi2) - pada kondisi OR, gunakan: filter(.data, kondisi1 | kondisi2)

# dplyr
filter(.data = vids,
       category_id == "Gaming",
       views > 1000000)

Note: - Variables -> kolom - Cases -> baris

Piping %>%

Simbol %>% digunakan untuk menyambungkan proses yang *sequential** atau berurutan. Untuk lebih memahaminya, mari kita menuliskan kegiatan pagi dari bangun tidur sampai berangkat kerja menggunakan konsep piping:

  1. bangun_tidur()
  2. cek_hp()
  3. makan()
  4. mandi()
  5. berangkat()

Tanpa piping:

berangkat(mandi(makan(cek_hp(bangun_tidur(saya)))))

Piping membuat penggabungan tahapan di atas menjadi lebih mudah:

saya %>% 
  bangun_tidur() %>% 
  cek_hp() %>% 
  makan() %>% 
  mandi() %>% 
  berangkat()

Shortcut Piping: ctrl/cmd + shift + m

Contoh:

  1. Buang kolom comments_disabled, ratings_disabled, dan video_error_or_removed
  2. Ambil video dari kategori “Music” yang memiliki views lebih dari 1 juta.
# base
vids_temp <- vids[,-c(10,11,12)]
vids_music <- vids_temp[vids_temp$category_id == "Music" & vids_temp$views > 1000000,]
vids_music
# dplyr
vids %>% 
  select(-c(comments_disabled, ratings_disabled, video_error_or_removed)) %>%
  filter(category_id == "Music", views > 1000000)

🏄️ Dive Deeper

Misal untuk kebutuhan analisis lanjutan kita akan mempersiapkan data terlebih dahulu. Kita ingin menampilkan judul video (title), channel (channel_title) yang trending, dan durasi (timetotrend) yang mereka butuhkan hingga trending. Analisis hanya untuk kategori Gaming dan Music saja.

Sajikan data yang dibutuhkan menggunakan dplyr dan konsep piping:

# your code here
vids %>% 
  filter(category_id == "Music" | category_id == "Gaming") %>% 
  select(title, channel_title, timetotrend) 
# alternatif jawaban menggunakan %in% operator
vids %>% 
  filter(category_id %in% c('Gaming', 'Music')) %>% 
  select(title, channel_title, timetotrend)

mutate: modifikasi kolom

  • Membuang kolom yang tidak digunakan:

    • comments_disabled
    • ratings_disabled
    • video_error_or_removed
  • Memperbaiki tipe data:

    • channel_title jadi factor
    • category_id jadi factor
    • publish_when jadi factor
    • publish_wday jadi factor
    • timetotrend jadi factor
unique(vids$timetotrend)
#> [1] "1"  "2"  "8+" "4"  "3"  "5"  "6"  "7"  "0"
  • Membuat kolom baru:

    • likesp: likes per views
    • dislikesp: dislikes per views
    • commentp: comment_count per views

Lalu simpan ke nama objek vids_clean:

Tips: ketika melakukan cleansing data sebaiknya data disimpan dengan object yang berbeda.

# base
vids$category_id <- as.factor(vids$category_id)

Syntax: mutate(.data, nama_kolom = isi_kolom)

# dplyr
vids_clean <- vids %>% 
  mutate(
    channel_title = as.factor(channel_title),
    category_id = as.factor(category_id),
    publish_when = as.factor(publish_when),
    publish_wday = as.factor(publish_wday),
    timetotrend = as.factor(timetotrend),
    likesp = likes / views,
    dislikesp = dislikes / views,
    commentp = comment_count / views
    ) %>% 
  select(-c(comments_disabled, ratings_disabled, video_error_or_removed))


head(vids_clean)
# alternatif untuk mengubah banyak kolom sekaligus ke tipe factor
# dapat digabungkan dengan fungsi contains(). ex: vars(contains("publish"))
vids %>% 
  mutate_at(vars(channel_title, category_id, publish_when, publish_wday, timetotrend), as.factor) %>% 
  mutate

Agregasi Data

Pada dplyr, kita dapat melakukan aggregasi data menggunakan urutan fungsi berikut:

  • 🛠 group_by(): melakukan pengelompokkan berdasarkan kolom tertentu, sehingga proses apapun setelahnya dilakukan berdasarkan pengelompokkan tersebut.
  • 🛠 summarise(): menghitung nilai statistik tertentu.
  • 🛠 ungroup(): melepaskan pengelompokkan agar proses apapun setelahnya dilakukan untuk keseluruhan data.

Beberapa fungsi statistik yang sering digunakan: 1. count = n() 2. rata rata = mean() 3. median = median() 4. std = std()

Hitung rata-rata views video trending yang dimiliki oleh tiap channel YouTube (gunakan vids_clean)!

# base
aggregate(views ~ channel_title, data = vids_clean, FUN = mean)
# dplyr
vids_agg <- vids_clean %>% 
  group_by(channel_title) %>% # mengelompokkan berdasarkan kolom channel_title
  summarise(mean_views = mean(views)) %>% # merata2kan untuk setiap channel_title
  ungroup()

vids_agg

Note: penggunaan ungroup() memang sering kali tidak terlihat efeknya, namun best practice setelah melakukan tahapan yang menggunakan grouping adalah melepas grouping tersebut menggunakan ungroup. Berikut contohnya mengapa ungroup diperlukan:

Cari tahu periode (hari dan jam) kapan seorang YouTuber Music mendapatkan rata-rata views terbanyak!

# tanpa ungroup: mengambil top_n untuk masing-masing publish_wday
vids_clean %>% 
  filter(category_id == "Music") %>% 
  group_by(publish_wday, publish_when) %>% 
  summarise(mean_views = mean(views)) %>% 
  top_n(1)
# dengan ungroup: mengambil top_n untuk keseluruhan data
vids_clean %>% 
  filter(category_id == "Music") %>% 
  group_by(publish_wday, publish_when) %>% 
  summarise(mean_views = mean(views)) %>% 
  ungroup() %>% # ungroup untuk memastikan proses selanjutnya berdasarkan keseluruhan data
  top_n(1) # mencari top 1 berdasarkan average views

Ilustrasi penggunan fungsi group dengan dan tanpa ungroup

arrange: mengurutkan baris

Urutkan channel YouTube dengan rata-rata views tertinggi hingga terendah (gunakan vids_agg)

# base
vids_agg[order(vids_agg$mean_views, decreasing = T),]
# dplyr
# default arrange() adalah ascending
vids_agg %>% 
  arrange(desc(mean_views))

🏄️ Dive Deeper

Background: Rany saat ini adalah seorang Data Science Instructor di Algoritma. Rany ingin menjadi seorang YouTuber namun masih bingung terkait konten apa yang sebaiknya dibuat. Rany adalah seseorang yang ambisius karena ingin videonya sering masuk ke jajaran video trending.

  1. Dari cerita di atas, rekomendasikan kategori video apa yang sebaiknya Rany buat. Dengan kata lain, cari tahu banyaknya jumlah video yang trending dari setiap kategori video. Lalu, simpan ke objek bernama vids_count.
vids_count <- vids_clean %>% 
  group_by(category_id) %>% 
  summarise(count = n()) %>% 
  arrange(desc(count))

vids_count

Hint: summarise(nama_kolom = n())

Kategori dengan jumlah video trending terbanyak adalah Entertainment

  1. Berdasarkan rekomendasi kategori video di atas, Rany ingin mengetahui beberapa channel terkenal yang nantinya akan digunakan sebagai referensi channel yang akan dibuat. Dengan kata lain, cari tahu top 10 YouTube channel dengan jumlah views tertinggi pada kategori video tersebut! Simpan ke dalam objek bernama vids_top_channel.
vids_top_channel <- vids_clean %>% 
  filter(category_id == "Entertainment") %>% 
  group_by(channel_title) %>% 
  summarise(sum_views = sum(views)) %>% 
  arrange(desc(sum_views))

head(vids_top_channel, 10)

📝 Summary dplyr

Pasangkan masing-masing nama fungsi dplyr dengan kegunaannya yang telah kita pelajari hari ini!

Kegunaan:

A. select(): Memilih atau menghapus kolom B. summarise(): Meringkas data dengan menerapkan fungsi statistik pada kolom tertentu C. read_csv(): Membaca file CSV D. ungroup(): Melepas efek pengelompokkan E. arrange(): Mengurutkan baris berdasarkan nilai pada kolom tertentu F. group_by(): Melakukan pengelompokkan baris berdasarkan kolom tertentu G. glimpse(): Melihat struktur data H. filter(): Melakukan subsetting baris berdasarkan kondisi tertentu I. mutate(): Membuat kolom baru atau transformasi kolom

Gunakan konsep piping (%>%) untuk mempermudah pengolahan data.

Interactive Plot using plotly

library(ggplot2) # plot statis
library(plotly) # plot interaktif
library(glue) # setting tooltip
library(scales) # mengatur skala pada plot

Plot interaktif memungkinkan user untuk berinteraksi dengan plot dan menghasilkan visualisasi yang lebih informatif dan menarik.

Official Documentation plotly: https://plotly.com/r/

📊 Tahapan pembuatan interactive plot menggunakan plotly:

  1. Formulasikan business question
  2. Persiapan data
  3. visualisasi statis dengan ggplot()
  4. Mengubah objek ggplot menjadi plotly dengan ggplotly()

Sebelumnya kita telah menyiapkan 2 data hasil analisis (vids_count & vids_top_channel). Mari visualisasikan 2 data tersebut menggunakan interactive plotting.

Exporting Plots with ggpubr

library(ggpubr) # publikasi plot

ggarrange()

Menyusun plot statis ke dalam sebuah plot.

ggarrange(plot1, plot2, nrow = 2)

publicat <- ggarrange(plot1, plot2, plot3, nrow=2)

# tampilkan halaman 1
publicat[[1]]

ggexport()

Export visualisasi dalam ragam file extension. Berikut contoh untuk PDF:

ggexport(publicat, filename = "assets/publication_inclass.jpg")
#> [1] "assets/publication_inclass%03d.jpg"

“png”, “jpeg”, “jpg”, “bmp” and “tiff”

Berikut referensi untuk menyimpan ke ekstensi file lain:

subplot()

Menyusun plot interaktif ke dalam sebuah plot.

subplot(
  ggplotly(plot1, tooltip = "text"),
  ggplotly(plot2, tooltip = "text"),
  ggplotly(plot3, tooltip = "text"), nrows=2)

📝 Summary Plotting

  • Tahapan membuat interactive plot:
  1. Formulasi business question
  2. Persiapan data dan tambahkan kolom untuk tooltip, yaitu informasi yang ditampilkan ketika hover plot
data <- data %>% 
 mutate(label = glue("informasi tooltip {kolom}"))
  1. Visualisasi statis dengan ggplot(), tambahkan parameter text pada aes()
# alternatif 1: pada ggplot()
plot <- ggplot(data, aes(x = kolom_a, y = kolom_b, text = kolom_tooltip)) +
  geom_point()

# alternatif 2: pada geom tertentu, umumnya apabila multiple geom
plot <- ggplot(data, aes(x = kolom_a, y = kolom_b)) +
  geom_point(aes(text = kolom_tooltip)) +
  ...
  1. Ubah menjadi plot interaktif dengan ggplotly()
ggplotly(plot, tooltip = "text")
  • Exporting plots:
  1. ggarrange(): menyusun beberapa ggplot ke sebuah halaman, kekurangan: hanya bisa plot statis
  2. ggexport(): menyimpan hasil ggarrange() ke sebuah file external (misal pdf atau png)
  3. subplot(): menyusun beberapa plot interaktif (plotly) ke sebuah plot, kekurangan: sulit mengatur penataan plot. Maka dari itu, lebih baik plot disusun ke dalam sebuah dashboard.

E-book interactive web-based data visualization with R, plotly, and shiny: https://plotly-r.com/index.html


Dashboard

# install.packages("flexdashboard")
# install.packages("shiny")
# install.packages("shinydashboard")
# install.packages("DT") # data table pada dashboard

shortcut comment multiple line: ctrl + shift + c

Flexdashboard

  • Langkah membuat file Rmd dengan template flexdashboard:
    1. Pilih Menu File > New File > R Markdown
    2. Pada bagian “From Template”, pilih “Flex Dashboard”
    3. Klik tombol “OK”
    4. Simpan file Rmd dan beri nama file (bisa dengan shortcut CTRL + S)

Shiny

  • Komponen pada shiny:
    • User Interface (UI): bagian yang berinteraksi dengan pengguna, yaitu input dan output
    • Server: tempat processing / render data
  • Tahapan untuk membuat shinydashboard:
    1. File -> New File -> Shinywebapp
    2. Pada New Shiny Web App, isi nama aplikasi (jangan terlalu panjang dan jangan ada spasi)
    3. Pilih Single File pada application type (default).
    4. Create
  • Alur pengerjaan shiny:
    1. Definisikan layout
    2. Buat input pada UI
    3. Definisikan fungsi render pada Server
    4. Tampilkan output pada UI

Penting: Selalu refer ke cheatsheet maupun dokumentasi dalam membuat dashboard dengan shiny.

  • Penjelasan layouting pada shiny:

  • Penjelasan penempatan input, render, dan output pada shiny:

Additional References