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 visualisationdplyr: data manipulationtidyr: data tidyingreadr: data importpurrr: functional programmingtibble: modern data framestringr: working with strings, regular expressionforcats: working with factorsoptions(scipen = 99) # me-non-aktifkan scientific notation
library(tidyverse) # koleksi beberapa package R
library(dplyr) # grammar of data manipulation
library(readr) # membaca datadplyrdplyr adalah package khusus yang mempermudah kita dalam melakukan data wrangling. Tahapan data wrangling yang umum:
Official Documentation & Cheatsheet
dplyr: https://dplyr.tidyverse.org/
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:
select(): seleksi kolomMisalkan 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 barisMisalkan 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
%>%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:
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:
comments_disabled, ratings_disabled, dan video_error_or_removed# 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)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 kolomMembuang kolom yang tidak digunakan:
comments_disabledratings_disabledvideo_error_or_removedMemperbaiki tipe data:
channel_title jadi factorcategory_id jadi factorpublish_when jadi factorpublish_wday jadi factortimetotrend jadi factorunique(vids$timetotrend)#> [1] "1" "2" "8+" "4" "3" "5" "6" "7" "0"
Membuat kolom baru:
likesp: likes per viewsdislikesp: dislikes per viewscommentp: comment_count per viewsLalu 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) %>%
mutatePada 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_aggNote: 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 viewsarrange: mengurutkan barisUrutkan 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))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.
vids_count.vids_count <- vids_clean %>%
group_by(category_id) %>%
summarise(count = n()) %>%
arrange(desc(count))
vids_countHint: summarise(nama_kolom = n())
Kategori dengan jumlah video trending terbanyak adalah Entertainment
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)dplyrPasangkan 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.
plotlylibrary(ggplot2) # plot statis
library(plotly) # plot interaktif
library(glue) # setting tooltip
library(scales) # mengatur skala pada plotPlot 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:
ggplot()ggplotly()Sebelumnya kita telah menyiapkan 2 data hasil analisis (vids_count & vids_top_channel). Mari visualisasikan 2 data tersebut menggunakan interactive plotting.
Business Question:
Buatlah analisis kategori video yang paling sering masuk ke dalam jajaran video trending!
# data
vids_countPenentuan plot:
Ingat kembali aes:
# ggplot: bar plot
# geom_col()
plot1 <- vids_count %>%
ggplot(aes(x = count,
y = reorder(category_id, count), # reorder(A, berdasarkan B)
fill = count)) +
geom_col() +
scale_fill_gradient(low = "red", high = "black") +
theme_minimal() +
theme(legend.position = "none") +
labs(title = 'Trending Categories on Youtube US 2017',
x = 'Video Count',
y = NULL)
plot1📌 Notes:
Diubah menjadi interaktif
# interactive plot
# secara default, tooltip pada objek plotly akan menampilkan seluruh informasi yang ada pada fungsi aes(): "all"
# parameter tooltip = "x" hanya menampilkan variable x pada tooltipnya
# parameter tooltip = "y" hanya menampilkan variable y pada tooltipnya
# parameter tooltip = NULL tidak menampilkan tooltipnya
ggplotly(plot1)Tooltip adalah informasi atau label yang ditampilkan ketika user meng-hover plot. Informasi pada tooltip dapat dikustomisasi dengan menggunakan fungsi glue().
Intuisi penggunaan glue():
# contoh penggunaan fungsi glue dari library glue
nama <- c("Wulan", "Rany", "Frengky")
glue("Nama Instructor: {nama}")#> Nama Instructor: Wulan
#> Nama Instructor: Rany
#> Nama Instructor: Frengky
makanan <- c(5000, 15000, 35000)
glue("Harga Makanan: {comma(makanan)}")#> Harga Makanan: 5,000
#> Harga Makanan: 15,000
#> Harga Makanan: 35,000
Tahapan kustomisasi tooltip:
glue() digunakan untuk menampilkan nilai pada kolom. Contoh format output tooltip: Category: asdsf
Video Counts: 123text pada aes()tooltip = "text" pada ggplotly()# menambahkan kolom berisi informasi tooltip
vids_count <- vids_count %>%
mutate(label = glue("Category: {category_id}
Video Count: {count} Videos"))
vids_countCatatan: \n adalah newline (merepresentasikan Enter)
# buat ulang ggplot
plot1 <- vids_count %>%
ggplot(aes(x = count,
y = reorder(category_id, count), # reorder(A, berdasarkan B)
fill = count,
text = label)) +
geom_col() +
scale_fill_gradient(low = "red", high = "black") +
theme_minimal() +
theme(legend.position = "none") +
labs(title = 'Trending Categories on Youtube US 2017' ,
x = 'Video Count',
y = NULL)
plot1# buat ulang plotly
ggplotly(plot1, tooltip = "text")Business Question:
Dari kategori Entertainment, lakukan analisis top 10 channel YouTube dengan rata-rata jumlah views tertinggi! (boleh gunakan objek vids_top_channel)
nama_library::nama_fungsi()
# pemisah ribuan
scales::comma(100000000000000)#> [1] "100,000,000,000,000"
# data
vids_10 <- vids_top_channel %>%
mutate(label = glue("Channel: {channel_title}
Sum Views: {scales::comma(sum_views)}")) %>%
head(10)
vids_10# ggplot: lollipop plot
# geom_point() + geom_segment()
plot2 <- vids_10 %>%
ggplot(aes(x = sum_views,
y = reorder(channel_title, sum_views),
color = sum_views,
text = label)) +
geom_point(size = 3) +
geom_segment(aes(x = 0, #define lokasi titik x awal atau posisi garis dimulai dari 0
xend = sum_views, #define garis x berakhir sesuai dengan nilai sum_views
yend = channel_title), #define titik y berakhir/berada sesuai dengan kategori pada channel_title
size = 1) + #ukuran ketebalan garis
labs(x = 'Total Views',
y = NULL,
title = 'Top 10 YouTube Channels in Entertainment') +
scale_color_gradient(low = "red", high = "black") +
scale_x_continuous(labels = scales::comma) +
theme_minimal() +
theme(legend.position = "none",
plot.margin = margin(r = 20))
plot2# plotly
ggplotly(plot2, tooltip = "text")Business Question:
Setelah menganalisis top 10 channel dari kategori video Entertainment, kita ingin melihat aktivitas viewers pada kategori tersebut di setiap publish_hour. Tipe plot apa yang baiknya digunakan? Buatlah interactive plotnya.
Tahapan dari data vids_clean: - filter category_id: “Entertainment” - tabel agregasi: mean(views) untuk masing-masing publish_hour - mutate (buat kolom baru) untuk tooltip
# data
vids_trend <- vids_clean %>%
filter(category_id == "Entertainment") %>%
group_by(publish_hour) %>%
summarise(mean_views = mean(views)) %>%
ungroup() %>% # opsional, karena grouping hanya 1 kolom
mutate(label = glue("Publish Hour: {publish_hour}
Average Views: {scales::comma(mean_views)}"))
vids_trend# ggplot
plot3 <- vids_trend %>%
ggplot(aes(x = publish_hour, y = mean_views)) +
geom_line(color = "red") +
geom_point(aes(text = label)) +
scale_y_continuous(labels = scales::comma) +
labs(
title = "Viewers Activity for Entertainment Videos",
x = "Publish Hour",
y = "Average Views"
) +
theme_minimal()
plot3# plotly
ggplotly(plot3, tooltip = "text")ggpubrlibrary(ggpubr) # publikasi plotggarrange()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)data <- data %>%
mutate(label = glue("informasi tooltip {kolom}"))
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)) +
...
ggplotly()ggplotly(plot, tooltip = "text")
ggarrange(): menyusun beberapa ggplot ke sebuah halaman, kekurangan: hanya bisa plot statisggexport(): menyimpan hasil ggarrange() ke sebuah file external (misal pdf atau png)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
# install.packages("flexdashboard")
# install.packages("shiny")
# install.packages("shinydashboard")
# install.packages("DT") # data table pada dashboardshortcut comment multiple line: ctrl + shift + c
flexdashboard:
vertical_layout: fill (default) atau scrollorientation: columns (default) atau rowsflexdashboard:
include = FALSE agar tidak tampil.flexdashboard:
shiny)flexdashboard: https://pkgs.rstudio.com/flexdashboard/articles/using.htmlflexdashboard: https://pkgs.rstudio.com/flexdashboard/articles/layouts.htmlflexdashboard: https://pkgs.rstudio.com/flexdashboard/articles/theme.htmlshiny:
shiny:
Penting: Selalu refer ke cheatsheet maupun dokumentasi dalam membuat dashboard dengan shiny.
shiny:shiny:Pertimbangan dalam menggunakan shiny:
shinydashboard adalah library yang memudahkan kita untuk membuat dashboard menggunakan shiny. Layouting dashboard menjadi lebih mudah karena sudah disediakan template oleh library tersebut. Meskipun begitu, layouting dashboard menjadi lebih terbatas.
UI shinydashboard terdiri dari 3 komponen:
dashboardHeader() untuk bagian header di pojok kiri atas dashboard.dashboardSidebar() untuk menu di bagian samping dashboard.dashboardBody() untuk konten utama dari dashboard.Referensi:
shiny Cheatsheet: https://raw.githubusercontent.com/rstudio/cheatsheets/main/shiny.pdfshiny Gallery: https://shiny.rstudio.com/gallery/shiny Input Gallery: https://shiny.rstudio.com/gallery/widget-gallery.htmlshinyWidgets: http://shinyapps.dreamrs.fr/shinyWidgets/shinydashboard: https://rstudio.github.io/shinydashboard/