Ini adalah catatan untuk memandu secara singkat dalam melakukan eksplorasi data menggunakan R dan beberapa package yang menjadi bagian dari package tidyverse. Tujuan dari tutorial ini adalah agar peserta dapat mencoba mengakses data yang berasal dari database (pada kesempatan ini menggunakan MySQL) melalui R dan menggunakan data dari file CSV yang dapat diunduh. Database yang akan diakses telah disediakan oleh pembicara di localhost-nya. Namun, Anda hanya dapat mengaksesnya ketika kegiatan sedang berlangsung.
Materi yang akan dibahas:
Untuk dapat mengikuti tutorial ini dengan baik, ada beberapa hal yang perlu dipersiapkan oleh peserta. Yaitu:
Koneksi internet yang baik dan terhubung dalam jaringan yang sama dengan PC pembicara untuk dapat mengakses database.
Menginstall software
Data & Script yang dapat diperoleh dari repository ini dan pada database yang disediakan pembicara.
Package R yang dibutuhkan: readr, tidyr, dplyr, ggplot2 (atau tidyverse), dan RMySQL.
Catatan: Data diperoleh dari packages nycflights13 yang disimpan ke dalam database. Jika Anda ingin mencoba diluar kegiatan atau tidak dapat terhubung dengan database pembicara, Anda dapat menginstall package nycflights13 untuk memperoleh data yang digunakan pada database. Dua data lain berupa file CSV untuk disesuaikan dengan kebutuhan tutorial. Data ini terdiri dari 336,776 penerbangan dari New York City (NYC) selama tahun 2013. Data asli berasal dari US Bureau of Transportation Statistics, dan dapat dilihat dokumentasinya dengan ?nycflights13::flights.
install.packages("nycflights13")
library(nycflights13)
Pastikan Anda sudah berhasil install package tersebut.
Jalankan perintah di bawah ini untuk install package (jika Anda belum pernah install) yang akan digunakan untuk dapat mengikuti tutorial ini sampai selesai.
install.packages(c("readr", "tidyr", "dplyr", "ggplot2", "RMySQL"))
# atau
install.packages(c("tidyverse", "RMySQL"))
Panggil package yang sudah Anda install dengan fungsi library().
# Panggil package yang sudah terisntall
library(RMySQL)
library(readr)
library(tidyr)
library(dplyr)
library(ggplot2)
# atau cukup memanggil
# library(tidyverse)
# untuk memanggil package di atas selain RMySQL
Package reader, tidyr, dplyr dan ggplot2 (dan beberapa package lain yang tidak digunakan di tutorial ini) termasuk dalam bagian package tidyverse. tidyverse adalah kumpulan package yang dibuat oleh Hadley Wickham dkk untuk kebutuhan data science menggunakan R.
RMySQL digunakan untuk membuat koneksi antara R dan database MySQL. Beberapa fungsi yang akan digunakan pada tutorial ini antara lain dbConnect() yang berasal dari package DBI untuk membuat koneksi, dbReadTable() untuk import data dari database ke R dan fungsi dbDisconnect() untuk memutuskan koneksi yang sudah tidak digunakan.readr berguna untuk import data dari tabular data file (csv, text file, dll).tidyr memiliki fungi-fungsi untuk “merapihkan” data. Terutama yang sering digunakan adalah fungsi gather() dan spread().dplyr adalah package yang sangat berguna untuk melakukan manipulasi/transformasi data menggunakan R.ggplot2 adalah salah satu package yang sangat banyak digunakan oleh pengguna R untuk kebutuhan visualisasi.
Tidyverse
tidyverse menggunakan tibble sebagai pengganti data.frame. > Tibbles are data frames, but they tweak some older behaviours to make life a little easier. R is an old language, and some things that were useful 10 or 20 years ago now get in your way. It’s difficult to change base R without breaking existing code, so most innovation occurs in packages – Grolemund & Wickham.
Beberapa kelebihan tibble dibandingkan data.frame diantaranya adalah ketika menampilkan data, tibble tidak menampilkan semua baris dan kolom. Jika ada lebih dari 10 baris data, maka hanya akan ada 10 baris pertama yang ditampilkan dan beberapa variabel sesuai dengan lebar console R Anda. Untuk lebih memahami tentang tibble, silahkan membaca artikel ini.
%>%)Sebelum kita mulai, kita akan membahas terlebih dahulu sebuah operator yang sangat berguna dan banyak digunakan oleh pengguna R yang menggunakan tidyverse. Operator ini adalah Pipes (%>%). Perhatikan contoh di bawah ini.
mean(iris$Sepal.Length)
[1] 5.843333
atau
iris$Sepal.Length %>% mean()
[1] 5.843333
Kedua script tersebut melakukan hal yang sama dan menghasilkan nilai yang sama.
Misalkan ada rangkaian dari beberapa fungsi seperti ini, fun1(), fun2() dan fun3() adalah fungsi di R.
output <- fun3(fun2(fun1(dataframe, arg1), arg2), arg3)
Jika Anda diminta untuk mempelajari script seperti ini saya cukup yakin bahwa Anda akan merasa kesulitan untuk mengetahui proses yang akan dilakukan oleh script tersebut. Anda harus meperhatikan argumen yang digunakan untuk fungsi tertentu. Script di atas masih sederhana, hanya ada tiga fungsi. Bayangkan jika banyak fungsi yang digunakan secara berurutan, bentuk di atas akan menjadi:
output <- fun_n(fun_(n-1)(...(fun3(fun2(fun1(dataframe, arg1), arg2), arg3), ...), arg_(n-1)), arg_n)
Dengan konsep tidyverse, kita dapat menggunakan operator %>% agar lebih mudah dalam memahami script karena script tersebut menunjukkan urutan.
%>%Saya akan coba menjelaskan lebih dalam untuk lebih memahami oprator %>%.
Misalkan f(a, x) adalah sebuah fungsi di R dengan argumen a dan x. kemudian fungsi g(b, z) adalah fungsi lain di R dengan argumen b dan z. Dengan menggunakan operator %>% kita dapat menuliskannya sebagai berikut.
# fungsi f(a, x)
f(a, x) # atau
a %>% f(x)
# fungsi g(b, z)
g(b, z) # atau
b %>% g(z)
Dari kedua contoh di atas, dapat dilihat bahwa a adalah argumen pertama untuk fungsi f() dan b adalah argumen pertama untuk fungsi g(). Operator %>% “menyampaikan” objek a sebagai nilai untuk mengisi argumen pertama pada fungsi f(). Perhatikan ilustrasi di bawah ini.
Ilustrasi Pipes 1
Misalkan objek a menjadi argumen pertama fungsi f() dengan a %>% f(x). Kemudia hasil dari a %>% f(x) dijadikan argumen pertama dari fungsi g(). Dengan kata lain b <- a %>% f(x) sehingga b %>% g(z). Hal ini dapat dilakukan secara berurutan dengan operator %>% sebagai berikut.
a %>%
f(x) %>%
g(z)
Ilustrasi Pipes 2
“Fungsi
f()diterapkan terhadap objekasebagai argumen pertama danxsebagai argumen kedua dari fungsif()yang kemudian hasilnya digunakan sebagai argumen pertama pada fungsig()denganzsebagai argumen kedua.”
Selanjutnya kita akan gunakan operator %>% dalam tutorial ini.
Untuk data yang tersedia di database, Anda dapat membuat koneksi ke database dengan perintah berikut ini.
srv <- "localhost" # ganti dengan IP yang akan diberikan oleh pembicara
port <- 3306
dbn <- "nycflights"
usr <- "user1"
pwd <- "P@ssw0rd"
# Membuat koneksi ke database MySQL
mycon <- dbConnect(MySQL(),
host = srv,
dbname = dbn,
user = usr,
password = pwd,
port = port)
# List tabel yang ada di dalam database
dbListTables(mycon)
[1] "airlines" "airports" "flights" "planes" "weather"
Untuk impor data dari datbase ke R dapat menggunakan fungsi dbReadTable().
flights <- mycon %>% dbReadTable("flights")
airlines <- mycon %>% dbReadTable("airlines")
airports <- mycon %>% dbReadTable("airports")
weather <- mycon %>% dbReadTable("weather")
planes <- mycon %>% dbReadTable("planes")
Penting untuk menutup koneksi ke database setelah selesai mengakses dan tidak menggunakan koneksi tersebut. Memutuskan koneksi dapat menggunakan fungsi dbDisconnect().
# jangan menajalankan fungsi di bawah ini jika Anda masih memerlukan/menggunakan koneksi di atas!
dbDisconnect(mycon)
[1] TRUE
Untuk data CSV yang akan digunakan dapat Anda unduh terlebih dahulu dan simpan di sebuah folder working directory, misalnya di dalam folder D:/aephidayatuloh/R/learning/Rdb dengan nama prices.csv. Untuk mengaktifkan working directory pada folder tersebut Anda dapat gunakan fungsi setwd().
setwd("D:/aephidayatuloh/R/learning/Rdb") # ganti sesuai dengan lokasi folder yang Anda gunakan
download.file(url = "https://raw.githubusercontent.com/aephidayatuloh/manipulasi-data/master/prices.csv", destfile = "prices.csv")
download.file(url = "https://raw.githubusercontent.com/aephidayatuloh/manipulasi-data/master/specialdays.csv", destfile = "specialdays.csv")
Perhatikan bahwa pada file prices.csv pemisah antar kolomnya menggunakan tanda titik koma (;) dan tanda koma (,) sebagai pemisah desimal.
# Import data dari CSV tersebut ke R
prices <- read_delim("prices.csv", delim = ";", escape_double = FALSE, trim_ws = TRUE)
specialdays <- read_csv("specialdays.csv")
Dengan fungsi yang ada pada readr, setelah selesai import data akan muncul tipe atau spesifikasi dari variabel yang dibaca.
Atau dengan cara langsung import tanpa unduh terlebih dahulu.
prices <- read_delim("https://raw.githubusercontent.com/aephidayatuloh/manipulasi-data/master/prices.csv", delim = ";", escape_double = FALSE, trim_ws = TRUE)
specialdays <- read_csv("https://raw.githubusercontent.com/aephidayatuloh/manipulasi-data/master/specialdays.csv")
File prices.csv dibaca menggunakan fungsi read_delim() karena pemisah antar variablenya adalah titik-koma (:), maka dari itu disebutkan juga delim = ";". Untuk file specialdays.csv dibaca menggunakan fungsi read_csv() karena menggunakan tanda koma (,) sebagai pemisah antar variable.
flights: semua penerbangan yang berangkat dari NYC di tahun 2013.weather: data meteorologi per jam untuk masing-masing bandara (airports).planes: information tentang konstruksi masing-masing pesawat.airports: nama dan lokasi bandara.airlines: translasi antara dua huruf kode carrier dan namanya.prices: daftar harga tiket (ticket) dan biaya (cost) per penumpang untuk masing-masing penerbangan.specialdays: daftar hari “istimewa” di Amerika.Keterangan variable:
flights
| Variable | Keterangan |
|---|---|
year,month,day |
Date of departure |
dep_time, arr_time |
Actual departure and arrival times (format HHMM or HMM), local tz. |
sched_dep_time, sched_arr_time |
Scheduled departure and arrival times (format HHMM or HMM), local tz. |
dep_delay, arr_delay |
Departure and arrival delays, in minutes. Negative times represent early departures/arrivals. |
hour, minute |
Time of scheduled departure broken into hour and minutes. |
carrier |
Two letter carrier abbreviation. See ?airlines to get name. |
tailnum |
Plane tail number |
flight |
Flight number |
origin, dest |
Origin and destination. See ?airports for additional metadata. |
air_time |
Amount of time spent in the air, in minutes. |
distance |
Distance between airports, in miles. |
time_hour |
Scheduled date and hour of the flight as a POSIXct date. Along with origin, can be used to join flights data to weather data. |
airlines
| Variable | Keterangan |
|---|---|
carrier |
Two letter abbreviation |
name |
Full name |
planes
| Variable | Keterangan |
|---|---|
tailnum |
Tail number |
year |
Year manufactured |
type |
Type of plane |
manufacturer,model |
Manufacturer and model |
engines,seats |
Number of engines and seats |
speed |
Average cruising speed in mph |
engine |
Type of engine |
weather
| Variable | Keterangan |
|---|---|
origin |
Weather station. Named origin to faciliate merging with flights data. |
year,month,day,hour |
Time of recording. |
temp,dewp |
Temperature and dewpoint in Fahrenheit. |
humid |
Relative humidity. |
wind_dir,wind_speed,wind_gust |
Wind direction (in degrees), speed and gust speed (in mph). |
precip |
Precipitation, in inches. |
pressure |
Sea level pressure in millibars. |
visib |
Visibility in miles |
time_hour |
Date and hour of the recording as a POSIXct date. |
airports
| Variable | Keterangan |
|---|---|
faa |
FAA airport code. |
name |
Usual name of the aiport. |
lat,lon |
Location of airport. |
alt |
Altitude, in feet. |
tz |
Timezone offset from GMT. |
dst |
Daylight savings time zone. A = Standard US DST: starts on the second Sunday of March, ends on the first Sunday of November. U = unknown. N = no dst. |
tzone |
IANA time zone, as determined by GeoNames webservice |
prices
| Variable | Keterangan |
|---|---|
year,month,day |
Date of departure |
origin,dest |
Origin and destination. See ?airports for additional metadata. |
sched_dep_time |
Scheduled departure and arrival times (format HHMM or HMM), local tz. |
tailnum |
Plane tail number |
ticket |
Average ticket price per person for a flight |
cost |
Average operating costs per person for a flight |
specialdays
| Variable | Keterangan |
|---|---|
year,month,day |
Date of departure |
holiday |
Name of special day in United States |
Setelah berhasil import data dari MySQL dan CSV, selanjutnya kita akan mengeksplorasi data tersebut.
dim(flights)
[1] 336776 19
glimpse(flights)
Observations: 336,776
Variables: 19
$ year [3m[38;5;246m<dbl>[39m[23m 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 201...
$ month [3m[38;5;246m<dbl>[39m[23m 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ day [3m[38;5;246m<dbl>[39m[23m 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ dep_time [3m[38;5;246m<dbl>[39m[23m 517, 533, 542, 544, 554, 554, 555, 557, 557, 558, 558, 55...
$ sched_dep_time [3m[38;5;246m<dbl>[39m[23m 515, 529, 540, 545, 600, 558, 600, 600, 600, 600, 600, 60...
$ dep_delay [3m[38;5;246m<dbl>[39m[23m 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1, ...
$ arr_time [3m[38;5;246m<dbl>[39m[23m 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849, 8...
$ sched_arr_time [3m[38;5;246m<dbl>[39m[23m 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851, 8...
$ arr_delay [3m[38;5;246m<dbl>[39m[23m 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14,...
$ carrier [3m[38;5;246m<chr>[39m[23m "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", "AA...
$ flight [3m[38;5;246m<dbl>[39m[23m 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79, 301, 49,...
$ tailnum [3m[38;5;246m<chr>[39m[23m "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N39463...
$ origin [3m[38;5;246m<chr>[39m[23m "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR", "LGA", "...
$ dest [3m[38;5;246m<chr>[39m[23m "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL", "IAD", "...
$ air_time [3m[38;5;246m<dbl>[39m[23m 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, 158...
$ distance [3m[38;5;246m<dbl>[39m[23m 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733, 10...
$ hour [3m[38;5;246m<dbl>[39m[23m 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, ...
$ minute [3m[38;5;246m<dbl>[39m[23m 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, ...
$ time_hour [3m[38;5;246m<chr>[39m[23m "2013-01-01 05:00:00", "2013-01-01 05:00:00", "2013-01-01...
head(flights)
summary(flights)
year month day dep_time sched_dep_time
Min. :2013 Min. : 1.000 Min. : 1.00 Min. : 1 Min. : 106
1st Qu.:2013 1st Qu.: 4.000 1st Qu.: 8.00 1st Qu.: 907 1st Qu.: 906
Median :2013 Median : 7.000 Median :16.00 Median :1401 Median :1359
Mean :2013 Mean : 6.549 Mean :15.71 Mean :1349 Mean :1344
3rd Qu.:2013 3rd Qu.:10.000 3rd Qu.:23.00 3rd Qu.:1744 3rd Qu.:1729
Max. :2013 Max. :12.000 Max. :31.00 Max. :2400 Max. :2359
NA's :8255
dep_delay arr_time sched_arr_time arr_delay
Min. : -43.00 Min. : 1 Min. : 1 Min. : -86.000
1st Qu.: -5.00 1st Qu.:1104 1st Qu.:1124 1st Qu.: -17.000
Median : -2.00 Median :1535 Median :1556 Median : -5.000
Mean : 12.64 Mean :1502 Mean :1536 Mean : 6.895
3rd Qu.: 11.00 3rd Qu.:1940 3rd Qu.:1945 3rd Qu.: 14.000
Max. :1301.00 Max. :2400 Max. :2359 Max. :1272.000
NA's :8255 NA's :8713 NA's :9430
carrier flight tailnum origin
Length:336776 Min. : 1 Length:336776 Length:336776
Class :character 1st Qu.: 553 Class :character Class :character
Mode :character Median :1496 Mode :character Mode :character
Mean :1972
3rd Qu.:3465
Max. :8500
dest air_time distance hour minute
Length:336776 Min. : 20.0 Min. : 17 Min. : 1.00 Min. : 0.00
Class :character 1st Qu.: 82.0 1st Qu.: 502 1st Qu.: 9.00 1st Qu.: 8.00
Mode :character Median :129.0 Median : 872 Median :13.00 Median :29.00
Mean :150.7 Mean :1040 Mean :13.18 Mean :26.23
3rd Qu.:192.0 3rd Qu.:1389 3rd Qu.:17.00 3rd Qu.:44.00
Max. :695.0 Max. :4983 Max. :23.00 Max. :59.00
NA's :9430
time_hour
Length:336776
Class :character
Mode :character
dim() menampilkan banyaknya baris dan variable dari suatu data frame.
glimpse() serupa dengan str() dari base-R, bertujuan untuk melihat tipe dan struktur objek. Jika objek tersebut adalah data frame, maka akan menghasilkan banyaknya baris (observations) dan variable (variables). Fungsi ini juga menampilkan nama variabel, tipe variabel, dan beberapa baris pertama dari data.
head() berguna untuk melihat atau menampilkan beberapa baris pertama dari data frame. Secara default head() menggunakan n = 6 untuk menentukan banyaknya baris yang akan ditampilkan. Jika Anda ingin melihat 10 baris pertama, maka cukup mennggantinya menjadi head(flights, n = 10). Namun jika yang ingin Anda tampilkan ada beberapa baris terakhir dari data frame, gunakan tail().
summary() menghasilkan beberapa nilai statistik deskriptif untuk masing-masing variabel jika yang dimasukan sebagai argumen adalah data frame. Untuk variabel numerik maka akan menhasilkan nilai minimum (Min.), quantil pertama (1st Qu.), median (Median), rata-rata (Mean), quantil ketiga (3rd Qu.), maksimum (Max.) dan banyaknya missing value (NA's) jika ada. Untuk variabel kategorik (character atau factor) makan akan menghasilkan banyaknya data (Length), kelas (Class) dan mode (Mode).
Hal ini sama seperti melakukan remove duplicate di Ms Excel untuk satu variabel.
distinct(flights, year)
distinct(flights, origin)
distinct(flights, dest)
NA
Untuk mendapatkan nilai unik dari semua baris berdasarkan variabel tertentu tambahkan opsi .keep_all = TRUE setelah nama variable dalam fungsi distinct().
distinct(flights, dest, .keep_all = TRUE)
distinct(flights)
Untuk membuat data frame dari hasil select() Anda dapat menuliskan namadataframe <- select(...). Argumen pertama dari select() adalah data frame yang ingin kita subset variabel tertentu saja. Selanjutnya tuliskan nama variable yang Anda inginkan ada di data frame yang baru. Anda dapat menuliskan nama masing-masing variable atau dapat juga dengan menuliskan urutan (indeks) variabel.
select(flights, month, day, dep_time, dep_delay, arr_time, arr_delay, origin, dest)
select(flights, c(2:4, 6:7, 9, 13:14))
Jika variabel yang ingin Anda pilih cukup banyak sedangkan variabel yang ingin Anda buang lebih sedikit, Anda dapat menuliskan nama variabel dengan menambahkan tanda negatif (-) di depan nama atau indeks masing-masing variabel.
select(flights, -year)
select(flights, -1)
Ketika Anda ingin memilih sebagian baris saja dari data frame, Anda dapat menggunakan fungsi slice() atau filter().
slice() berfungsi untuk mensubset baris data berdasarkan indeks barisnya. Misalkan, slice(flights, 1:100) berarti Anda memilih data pada posisi baris ke-1 s/d ke-100. Posisi baris 1:100 adalah vector numerik integer yang ingin dipilih.
# memilih baris ke-1 s/d 1000
slice(flights, 1:1000)
# memilih baris ke-1,3,5,6, dan 10
slice(flights, c(1,3,5,6,10))
filter() berfungsi untuk memilih sebagian data berdasarkan nilai dari satu atau lebih variabel.
filter(flights, dep_delay >= 10)
filter(flights, dep_delay >= 10 & origin == "JFK")
filter(flights, month == 1 & day == 1 & origin == "JFK" & dest == "ATL")
filter(flights, is.na(dep_time))
Mengurutkan data frame menggunakan fungsi arrange() sangat mudah.
# Urutkan data frame flights berdasarkan variabel `origin`
arrange(flights, origin)
# Urutkan data frame flights berdasarkan variabel `origin` dan `dest`
arrange(flights, origin, dest)
# Urutkan data frame flights berdasarkan variabel `origin` secara ascending dan `dest` secara descending
arrange(flights, origin, desc(dest))
Fungsi desc() dalam penggunaan arrange() digunakan jika Anda ingin mengurutkan data secara descending.
Untuk kebutuhan ilustrasi pada bagian ini dengan fungsi na_if(), Anda akan mengganti nilai NA (missing value) menjadi sebuah nilai tertentu, misalnya jika air_time missing akan diganti menjadi nilai -999.
# Banyaknya NA
sum(is.na(flights["air_time"]))
[1] 9430
flights_na999 <- flights
# Merubah NA dengan -999
flights_na999$air_time <- if_else(is.na(flights$air_time), -999, flights$air_time)
# Banyaknya NA
sum(is.na(flights_na999["air_time"]))
[1] 0
# Banyaknya NA yang sudah diganti -999
sum(flights_na999["air_time"] == -999)
[1] 9430
Selanjutanya, misalkan dari raw data Anda, nilai -999 menunjukkan missingg value dan akan diganti jadi NA.
# Ganti nilai NA menjadi -999
flights_na999$air_time <- na_if(flights_na999$air_time, -999)
# Banyaknya -999
filter(flights_na999, air_time == -999)
# Banyaknya NA
sum(is.na(flights_na999$air_time))
[1] 9430
# Membuang semua baris yang mengandung NA
flights_dropNA <- drop_na(flights)
# Mengganti NA pada masing-masing variabel dengan nilai tertentu
replace_na(flights, list(dep_time = 0, dep_delay = 0, arr_time = mean(flights$arr_time, na.rm = TRUE), arr_delay = median(flights$arr_delay, na.rm = TRUE)))
Fungsi replace_na() menggunakan argumen sebuah list untuk menentukan nilai pengganti NA pada sebuah variabel. Dari contoh di atas, NA pada dep_time dan dep_delay diganti menjadi 0 (nol), NA di arr_time diganti dengan rata-rata arr_time, sedangkan NA di arr_delay diganti dengan nilai median dari arr_delay.
%>%Seringkali proses data preparation membutuhkan banyak proses atau tahapan. Sekarang jika kita ingin melakukan beberapa proses sekaligus, salah satunya kita akan membuat script kurang lebih seperti ini.
selected <- select(flights, dep_delay, arr_time, arr_delay, origin, dest, air_time)
filtered <- filter(selected, dep_delay >= 10 & origin == "JFK")
hasil <- arrange(filtered, origin)
hasil
Atau ada juga yang menuliskan seperti berikut ini.
hasil <- arrange(filter(select(flights, dep_delay, arr_time, arr_delay, origin, dest, air_time), dep_delay >= 10 & origin == "JFK"), origin)
hasil
Jika Anda diminta untuk mempelajari script seperti ini saya cukup yakin bahwa Anda akan merasa kesulitan untuk mengetahui proses yang akan dilakukan oleh script tersebut. Script di atas masih sederhana, hanya ada tiga fungsi. Bayangkan jika banyak fungsi yang digunakan secara berurutan, bentuk di atas akan menjadi:
output <- fun_n(...(fun3(fun2(fun1(dataframe, arg1), arg2), arg3), ...), arg_n)
Jika diperhatikan, argumen pertama dari masing-masing fungsi select(), filter(), arrange() dan beberapa fungsi yang lain di dplyr yang sering digunakan untuk transformasi dan eksplorasi data adalah data frame/tibble atau hasil dari proses sebelumnya. Misalnya, hasil dari fungsi select() adalah data frame yang kemudian diproses dengan fungsi filter() untuk memilih baris data tertentu dan hasilnya diteruskan lagi ke fungsi arrange() untuk diurutkan berdasarkan variabel tertentu.
Dengan konsep tidyverse, kita dapat menggunakan operator Pipes %>% agar lebih mudah dalam memahami script karena script tersebut menunjukkan urutan. Perhatikan contoh di bawah ini.
flights %>%
select(dep_delay, arr_time, arr_delay, origin, dest, time_hour) %>%
filter(origin == "JFK" & between(dep_delay, -10, 100)) %>%
arrange(origin, desc(dest))
Jika dibuat ke dalam kalimat:
“Ambil data penerbangan dari data frame
flightskemudian pilih variabel-variable tertentu saja. Selanjutnya filter yangorigin-nya dari”JFK" dan waktu keberangkatan antara yang lebih awal 10 menit dan yang delay hingga 100 menit. Kemudian urutkan hasil tersebut berdasarkanoriginsecara ascending dan berdasarkandestsecara descending."
flights %>%
select(dep_delay, arr_time, arr_delay, origin, dest, time_hour) %>%
filter(origin == "JFK" & between(dep_delay, -10, 100)) %>%
arrange(origin, desc(dest)) %>%
mutate(is_delay = if_else(dep_delay > 0, 1, 0),
time_hour = as.POSIXct(time_hour))
NA
Jika dibuat ke dalam kalimat:
“Ambil data penerbangan dari data frame
flightskemudian pilih variabel-variable tertentu saja. Selanjutnya filter yangorigin-nya dari”JFK" dan waktu keberangkatan antara yang lebih awal 10 menit dan yang delay hingga 100 menit. Kemudian urutkan hasil tersebut berdasarkanoriginsecara ascending dan berdasarkandestsecara descending. Setelah itu membuat variabel baru bernamais_delayyang menunjukkan apakah suatu penerbangan terjadi delay atau tidak. Kemudian konversi variabletime_houryang masih bertipecharactermenjadidatetimeatau<dttm>dengan nama variabel yang sama, yaitutime_hour."
Membuat tabel frekuensi berdasarkan origin dan dest. Gunakan fungsi count() untuk mengetahui banyaknya baris.
flights %>%
count()
jadwal penerbangan.
Untuk membuat tabel frekuensi berdasarkan kategori suatu variabel, perhatikan contoh di bawah ini.
flights %>%
filter(dest %in% c("ABQ", "ACK", "ALB", "ANC", "ATL")) %>%
count(origin, dest)
Script di atas menghitung banyaknya jadwal penerbangan (count()) berdasarkan masing-masing kategori pada origin dan dest.
Untuk membuat tabel frekuensi dua-arah (two-way frequency), dapat menggunakan fungsi spread() dari package tidyr. Dari contoh hasil di atas kita akan membuat kategori pada variabel origin sebagai nama varaibel.
flights %>%
filter(dest %in% c("ABQ", "ACK", "ALB", "ANC", "ATL")) %>%
count(origin, dest) %>%
spread(key = origin, value = n, fill = 0)
Argumen fill = 0 digunakan untuk mengisi cell yang kosong setelah ditansformasi dengan nilai nol (0).
Seringkali menghitung nilai statistik/summary diperlukan dalam melakukan eksplorasi data.
drop_na() dan menghitung rata-rata delay.flights %>%
drop_na() %>%
summarise(rata2_delay = mean(dep_delay))
dep_delay berdasarkan origin, dest dan month. Jika ada nilai NA pada variabel dep_delay maka dikelaurkan dari perhitungan.flights %>%
group_by(origin, dest, month) %>%
summarise(rata2_delay = mean(dep_delay, na.rm = TRUE)) %>%
arrange(rata2_delay)
NA
group_by() dan summarise() digunakan untuk menghitung statistik berdasarkan grup yg disebutkan pada fungi group_by().
flights %>%
group_by(origin, dest) %>%
summarise(rata2_delay = mean(dep_delay, na.rm = TRUE))
Hasil dari summarise() adalah sebuah data frame/tibble. Maka dari itu, sebaiknya berikan nama pada hasil summarise(). rata2_delay adalah nama variabel hasil dari mean().
flights %>%
group_by(origin, dest) %>%
summarise(rata2_delay = mean(dep_delay, na.rm = TRUE)) %>%
spread(key = origin, value = rata2_delay) # soon spread() will be replaced with pivot_wider()
spread() membuat variabel baru dari isi sebuah variabel yang disebutkan pada argumen key = sebagai nama variabel, dan nilai dari variabel-variabel baru tersebut adalah nilai dari variabel yang disebutkan di argumen value =.
Note: pada saat tutorial ini dibuat, package tidyr masih menggunakan fungsi spread() dan gather() untuk transformasi data frame. Namun pembuat package tidyr sudah berencana untuk menggantinya dengan nama fungsi baru, yaitu pivot_wider() dan pivot_longer().
flights %>%
group_by(origin, dest) %>%
summarise(rata2_delay = mean(dep_delay, na.rm = TRUE)) %>%
spread(key = origin, value = rata2_delay) %>% # soon replaced with pivot_wider()
gather(key = origin, value = rata2_delay, -dest) # soon replaced with pivot_longer()
tb <- flights %>%
group_by(month) %>%
count()
plot(tb$month, tb$n, "l")
tb <- flights %>%
group_by(day) %>%
count()
plot(tb$day, tb$n, "l")
tb <- flights %>%
mutate(dates = as.Date(paste(year, month, day, sep = "-"), format = "%Y-%m-%d")) %>%
group_by(dates) %>%
count()
plot(tb$dates, tb$n, "l")
Fungsi paste berfungsi untuk menggabungkan (concate) dua buah nilai atau vector menjadi character dengan pemisah default antar nilai tersebut adalah
paste("nilai ini", 9)
[1] "nilai ini 9"
Untuk mengganti pemisahnya Anda dapat menyebutkannya pada argumen sep =. Misalnya Anda ingin menggunakan pemisah tanda -, maka
paste("nilai ini", 9, sep = "-")
[1] "nilai ini-9"
Fungsi as.Date() melakukan konversi dari sebuah character menjadi nilai tanggal (date-value) di R. Format tanggal default di R adalah yyyy-mm-dd, namun di R menggunakan format %Y-%m-%d untuk 2019-05-10. Selebihnya Anda dapat melihatnya dengan ?as.Date.
Dalam dunia nyata, terutama di dunia kerja dan perusahaan, jarang sekali data yang digunakan hanya berasal dari satu tabel atau file. Biasanya ada tabel-tabel lain yang harus digunakan untuk mendukung analisis data. Misalnya di bank, di database minimal ada tabel master_customer yang berisi data demografi (nama, tempat & tanggal lahir, alamat, dst), dan transaction yang berisi data transaksi nasabah.
Pada bagian tutorial ini, akan membahas penggunaan beberapa tabel yang sudah dijelaskan di bagian awal mengenai data. Ada 7 dataset yang dapat digunakan. Mungkin untuk melakukan analisis dan mendapatkan hasilnya Anda tidak membutuhkan semuanya.
Dari ketujuh tabel, relasinya digambarkan seperti gambar di bawah ini.
Diagram Relasi Tabel
flights dihubungkan dengan planes via satu variabel, tailnum.
flights dihubungkan dengan airlines melaui variabel carrier.
flights dihubungkan dengan airports dengan dua cara: via variabel origin dengan variabel faa dan dest dengan variabel faa.
flights dihubungkan dengan weather via origin (lokasi), dan year, month, day dan hour.
flights dihubungkan dengan prices via year, month, day, hour, flight, origin, dest, sched_dep_time, dan tailnum.
flights dihubungkan dengan specialdays via variabel year, month, dan day.
Berikut fungsi untuk merge/join menggunakan package dplyr dan perbandingannya dengan SQL.
| dplyr | SQL |
|---|---|
inner_join(x, y, by = c("a" = "b") |
SELECT * FROM x INNER JOIN y ON x.a = y.b |
left_join(x, y, by = c("a" = "b")) |
SELECT * FROM x LEFT OUTER JOIN y ON x.a = y.b |
right_join(x, y, by = c("a" = "b")) |
SELECT * FROM x RIGHT OUTER JOIN y ON x.a = y.b |
full_join(x, y, by = c("a" = "b")) |
SELECT * FROM x FULL OUTER JOIN y ON x.a = y.b |
Catatan: “INNER” dan “OUTER” pada SQL adalah opsional, dan lebih sering tidak dituliskan.
Berikut ilustrasi untuk menjelaskan merge/join.
Misalkan ada dua buah tabel, x dan y yang masing-masing mempunyai 2 variabel seperti pada gambar di bawah ini. Variabel pertama adalah key dan variabel kedua adalah val.
Tabel x dan y
x <- data.frame(key = c(1, 2, 3), val = c("x1", "x2", "x3"))
y <- data.frame(key = c(1, 2, 4), val = c("y1", "y2", "y3"))
Ketika melakukan proses inner_join maka akan diambil nilai yang sama dari key yang digunakan dari kedua tabel tersebut. Pada ilustrasi di bawah ini, digunakan inner_join untuk menggabungkan tabel x dan y. Dari kedua tabel tersebut, nilai key yang ada di tabel x dan y adalah 1 dan 2. Maka hasilnya adalah diambil baris data yang sama di kedua tabel tersebut, yaitu nilai key 1 dan 2.
x %>%
inner_join(y, by = "key")
Jika ada variabel lain selain key yang namanya sama, maka dibelakang masing-masing nama variabel tersebut akan ditambahkan suffix. suffix secara default adalah suffix = c(".x", ".y"). Artinya karena di masing-masing tabel ada variabel yang sama dan variabel ini bukan sebuah key pada saat join, yaitu val, maka setelah proses join nama val akan diganti menjadi val.x untuk variabel yang berasal dari tabel x dan val.y yang berasal dari tabel y.
Jika ingin mengganti suffix, Anda dapat menggunakan argumen suffix pada fungsi join.
x %>%
inner_join(y, by = "key", suffix = c("_x", "_y"))
Ilustrasi Inner Join
tbl1 <- flights %>%
inner_join(weather, by = c("year", "month", "day", "hour", "origin", "time_hour"))
glimpse(tbl1)
Observations: 335,220
Variables: 28
$ year [3m[38;5;246m<dbl>[39m[23m 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 201...
$ month [3m[38;5;246m<dbl>[39m[23m 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ day [3m[38;5;246m<dbl>[39m[23m 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ dep_time [3m[38;5;246m<dbl>[39m[23m 517, 533, 542, 544, 554, 554, 555, 557, 557, 558, 558, 55...
$ sched_dep_time [3m[38;5;246m<dbl>[39m[23m 515, 529, 540, 545, 600, 558, 600, 600, 600, 600, 600, 60...
$ dep_delay [3m[38;5;246m<dbl>[39m[23m 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1, ...
$ arr_time [3m[38;5;246m<dbl>[39m[23m 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849, 8...
$ sched_arr_time [3m[38;5;246m<dbl>[39m[23m 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851, 8...
$ arr_delay [3m[38;5;246m<dbl>[39m[23m 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14,...
$ carrier [3m[38;5;246m<chr>[39m[23m "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", "AA...
$ flight [3m[38;5;246m<dbl>[39m[23m 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79, 301, 49,...
$ tailnum [3m[38;5;246m<chr>[39m[23m "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N39463...
$ origin [3m[38;5;246m<chr>[39m[23m "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR", "LGA", "...
$ dest [3m[38;5;246m<chr>[39m[23m "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL", "IAD", "...
$ air_time [3m[38;5;246m<dbl>[39m[23m 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, 158...
$ distance [3m[38;5;246m<dbl>[39m[23m 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733, 10...
$ hour [3m[38;5;246m<dbl>[39m[23m 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, ...
$ minute [3m[38;5;246m<dbl>[39m[23m 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, ...
$ time_hour [3m[38;5;246m<chr>[39m[23m "2013-01-01 05:00:00", "2013-01-01 05:00:00", "2013-01-01...
$ temp [3m[38;5;246m<dbl>[39m[23m 39.02, 39.92, 39.02, 39.02, 39.92, 39.02, 37.94, 39.92, 3...
$ dewp [3m[38;5;246m<dbl>[39m[23m 28.04, 24.98, 26.96, 26.96, 24.98, 28.04, 28.04, 24.98, 2...
$ humid [3m[38;5;246m<dbl>[39m[23m 64.43, 54.81, 61.63, 61.63, 54.81, 64.43, 67.21, 54.81, 6...
$ wind_dir [3m[38;5;246m<dbl>[39m[23m 260, 250, 260, 260, 260, 260, 240, 260, 260, 260, 260, 26...
$ wind_speed [3m[38;5;246m<dbl>[39m[23m 12.65858, 14.96014, 14.96014, 14.96014, 16.11092, 12.6585...
$ wind_gust [3m[38;5;246m<dbl>[39m[23m NA, 21.86482, NA, NA, 23.01560, NA, NA, 23.01560, NA, 23....
$ precip [3m[38;5;246m<dbl>[39m[23m 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ pressure [3m[38;5;246m<dbl>[39m[23m 1011.9, 1011.4, 1012.1, 1012.1, 1011.7, 1011.9, 1012.4, 1...
$ visib [3m[38;5;246m<dbl>[39m[23m 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1...
head(tbl1)
Karena semua variabel yang namanya sama di data frame flights dan weather digunakan sebagai key maka tidak ada variabel yang ditambahkan suffix.
Perhatikan ilustrasi untuk left, right, dan full outer join.
Ilustrasi Left, Right dan Full Outer Join
Pada kesempatan ini hanya akan dibahas mengenai left join. Pada dasarnya left_join() mengambil semua baris yang ada di tabel sebelah kiri (LHS), dalam ilustrasi di atas adalah tabel x, dan mencari nilai yang ada pasangannya di tabel sebelah kanan (RHS), yaitu tabel y.
Jika nilai dari variabel key di tabel x tidak ada pasangannya di tabel y maka nilai val untuk baris tersebut akan menjadi missing value atau NA.
tbl2 <- flights %>%
left_join(airports, by = c("origin" = "faa")) %>%
left_join(airports, by = c("dest" = "faa"), suffix = c("_origin", "_dest"))
glimpse(tbl2)
Observations: 336,776
Variables: 33
$ year [3m[38;5;246m<dbl>[39m[23m 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 201...
$ month [3m[38;5;246m<dbl>[39m[23m 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ day [3m[38;5;246m<dbl>[39m[23m 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ dep_time [3m[38;5;246m<dbl>[39m[23m 517, 533, 542, 544, 554, 554, 555, 557, 557, 558, 558, 55...
$ sched_dep_time [3m[38;5;246m<dbl>[39m[23m 515, 529, 540, 545, 600, 558, 600, 600, 600, 600, 600, 60...
$ dep_delay [3m[38;5;246m<dbl>[39m[23m 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1, ...
$ arr_time [3m[38;5;246m<dbl>[39m[23m 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849, 8...
$ sched_arr_time [3m[38;5;246m<dbl>[39m[23m 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851, 8...
$ arr_delay [3m[38;5;246m<dbl>[39m[23m 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14,...
$ carrier [3m[38;5;246m<chr>[39m[23m "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", "AA...
$ flight [3m[38;5;246m<dbl>[39m[23m 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79, 301, 49,...
$ tailnum [3m[38;5;246m<chr>[39m[23m "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N39463...
$ origin [3m[38;5;246m<chr>[39m[23m "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR", "LGA", "...
$ dest [3m[38;5;246m<chr>[39m[23m "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL", "IAD", "...
$ air_time [3m[38;5;246m<dbl>[39m[23m 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, 158...
$ distance [3m[38;5;246m<dbl>[39m[23m 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733, 10...
$ hour [3m[38;5;246m<dbl>[39m[23m 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, ...
$ minute [3m[38;5;246m<dbl>[39m[23m 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, ...
$ time_hour [3m[38;5;246m<chr>[39m[23m "2013-01-01 05:00:00", "2013-01-01 05:00:00", "2013-01-01...
$ name_origin [3m[38;5;246m<chr>[39m[23m "Newark Liberty Intl", "La Guardia", "John F Kennedy Intl...
$ lat_origin [3m[38;5;246m<dbl>[39m[23m 40.69250, 40.77725, 40.63975, 40.63975, 40.77725, 40.6925...
$ lon_origin [3m[38;5;246m<dbl>[39m[23m -74.16867, -73.87261, -73.77893, -73.77893, -73.87261, -7...
$ alt_origin [3m[38;5;246m<dbl>[39m[23m 18, 22, 13, 13, 22, 18, 18, 22, 13, 22, 13, 13, 13, 18, 2...
$ tz_origin [3m[38;5;246m<dbl>[39m[23m -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -...
$ dst_origin [3m[38;5;246m<chr>[39m[23m "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A...
$ tzone_origin [3m[38;5;246m<chr>[39m[23m "America/New_York", "America/New_York", "America/New_York...
$ name_dest [3m[38;5;246m<chr>[39m[23m "George Bush Intercontinental", "George Bush Intercontine...
$ lat_dest [3m[38;5;246m<dbl>[39m[23m 29.98443, 29.98443, 25.79325, NA, 33.63672, 41.97860, 26....
$ lon_dest [3m[38;5;246m<dbl>[39m[23m -95.34144, -95.34144, -80.29056, NA, -84.42807, -87.90484...
$ alt_dest [3m[38;5;246m<dbl>[39m[23m 97, 97, 8, NA, 1026, 668, 9, 313, 96, 668, 19, 26, 126, 1...
$ tz_dest [3m[38;5;246m<dbl>[39m[23m -6, -6, -5, NA, -5, -6, -5, -5, -5, -6, -5, -5, -8, -8, -...
$ dst_dest [3m[38;5;246m<chr>[39m[23m "A", "A", "A", NA, "A", "A", "A", "A", "A", "A", "A", "A"...
$ tzone_dest [3m[38;5;246m<chr>[39m[23m "America/Chicago", "America/Chicago", "America/New_York",...
head(tbl2)
Jika diperhatikan, ada beberapa variabel dari tbl2 yang namanya menggunakan _origin dan _dest. Hal ini menunjukkan ada variabel yang namanya sama dari hasil left_join() pertama dan kedua, yaitu nama variabel dari data frame airports. Karena dua kali join maka akan ada nama variabel yang sama sehingga namanya ditambahkan suffix.
Buatlah analisis data untuk kebutuhan berikut!
IAH atau HOU) berdasarkan bandara asalnya per bulan. Hint: Anda dapat gunakan operator %in%.%in%.between().tailnum-nya missing? Apa maksud dari baris-baris data ini?dep_time-nya missing? Variable apalagi selain itu yang missing? Apa maksud dari baris-baris data ini?———————– Semoga Bermanfaat ———————–
Contact me: Aep Hidayatuloh
Email: aephidayatuloh.mail@gmail.com GitHub: https://github.com/aephidayatuloh