Relational data
Pendahuluan
Pada proses analisis data, kita jarang melibatkan hanya satu tabel data. Biasanya kita memiliki banyak tabel data untuk kita proses sesuai dengan tujuan kita, dan kita harus menggabungkannya dua atau tiga atau lebih untuk menjawab pertanyaan yang kita miliki. Secara kolektif, secara umum beberapa tabel data yang tergabung pada satu kesatuan disebut sebagai data relasional karena relasinya, bukan hanya kumpulan data individual, yang dianggap penting.
Relasi selalu ditentukan antara sepasang tabel / dua tabel. Semua relasi lainnya dibangun dari ide sederhana ini: relasi dari tiga tabel atau lebih selalu merupakan properti relasi antara setiap pasangan. Terkadang kedua elemen pasangan bisa menjadi tabel yang sama! Ini diperlukan jika, misalnya, jika kita memilki suatu data yang teridiri dari beberapa tabel, dan setiap tabel memiliki referensi ke parent nya.
Perintah dalam dplyr (dibandingkan dengan perintah pada SQL) adalah sebagai berikut :
| select() |
SELECT |
Menyeleksi kolom variabel |
| filter() |
WHERE |
Menyaring (filter) baris |
| group_by() |
GROUP_BY |
Mengelompokkan data |
| summarise() |
tidak ada |
Merangkum data |
| arrange() |
ORDER_BY |
Mengurutkan data |
| mutate() |
COLUMN ALIAS |
Membuat kolom baru |
| join() |
JOIN |
Menggabungkan data frame |
|
|
|
Untuk bekerja dengan data relasional, kita memerlukan kata kerja yang bekerja dengan pasangan tabel. Ada tiga kelompok kata kerja yang dirancang untuk bekerja dengan data relasional:
1. Mutasi gabungan, yang menambahkan variabel baru ke satu bingkai data dari pengamatan yang cocok di yang lain.
2. Gabungan pemfilteran, yang memfilter pengamatan dari satu bingkai data berdasarkan apakah mereka cocok atau tidak dengan pengamatan di tabel lain.
3. Operasi set, yang memperlakukan observasi seolah-olah itu adalah elemen yang ditetapkan.
Tempat paling umum untuk menemukan data relasional adalah di sistem manajemen basis data relasional (atau RDBMS), istilah yang mencakup hampir semua basis data modern. Jika Anda pernah menggunakan database sebelumnya, Anda hampir pasti pernah menggunakan SQL. Jika demikian, Anda akan menemukan konsep dalam bab ini sudah tidak asing lagi, meskipun ekspresi mereka dalam dplyr sedikit berbeda. Secara umum, dplyr sedikit lebih mudah digunakan daripada SQL karena dplyr dikhususkan untuk melakukan analisis data: dplyr membuat operasi analisis data umum menjadi lebih mudah, maka kita bisa mempermudah untuk melakukan hal-hal lain yang biasanya diperlukan untuk analisis data pada seorang data sains.
Prasyarat
Kami akan mengeksplorasi data relasional dari nycflights13 menggunakan library dplyr.
Operator pipe: %>%
Pipe operator: %>% dalam dplyr diimport dari package magrittr. Pipe digunakan untuk menyalurkan output dari suatu fungsi ke input fungsi lain. Alih-alih menggunakan fungsi tersarang, digunakanlah pipe yang dibaca dari kiri ke kanan. Contoh:
Lagkah 2
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.2 ✓ purrr 0.3.4
## ✓ tibble 3.0.4 ✓ stringr 1.4.0
## ✓ tidyr 1.1.2 ✓ forcats 0.5.0
## ✓ readr 1.4.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(nycflights13)
library(ggplot2)
library(maps)
##
## Attaching package: 'maps'
## The following object is masked from 'package:purrr':
##
## map
Maskapai penerbangan di ambil dari data set airlines, kita memungkinkan untuk mencari nama lengkap maskapai dan fungsi str() kita bisa mengetahui struktur dari data set airlines.
Lagkah 3
str(airlines)
## tibble [16 × 2] (S3: tbl_df/tbl/data.frame)
## $ carrier: chr [1:16] "9E" "AA" "AS" "B6" ...
## $ name : chr [1:16] "Endeavor Air Inc." "American Airlines Inc." "Alaska Airlines Inc." "JetBlue Airways" ...
airlines
## # A tibble: 16 x 2
## carrier name
## <chr> <chr>
## 1 9E Endeavor Air Inc.
## 2 AA American Airlines Inc.
## 3 AS Alaska Airlines Inc.
## 4 B6 JetBlue Airways
## 5 DL Delta Air Lines Inc.
## 6 EV ExpressJet Airlines Inc.
## 7 F9 Frontier Airlines Inc.
## 8 FL AirTran Airways Corporation
## 9 HA Hawaiian Airlines Inc.
## 10 MQ Envoy Air
## 11 OO SkyWest Airlines Inc.
## 12 UA United Air Lines Inc.
## 13 US US Airways Inc.
## 14 VX Virgin America
## 15 WN Southwest Airlines Co.
## 16 YV Mesa Airlines Inc.
Bandara di ambil dari data set airports, kita memungkinkan untuk mencari nama lengkap bandara dan fungsi str() kita bisa mengetahui struktur dari data set bandara.
Lagkah 4
str(airports)
## tibble [1,458 × 8] (S3: tbl_df/tbl/data.frame)
## $ faa : chr [1:1458] "04G" "06A" "06C" "06N" ...
## $ name : chr [1:1458] "Lansdowne Airport" "Moton Field Municipal Airport" "Schaumburg Regional" "Randall Airport" ...
## $ lat : num [1:1458] 41.1 32.5 42 41.4 31.1 ...
## $ lon : num [1:1458] -80.6 -85.7 -88.1 -74.4 -81.4 ...
## $ alt : num [1:1458] 1044 264 801 523 11 ...
## $ tz : num [1:1458] -5 -6 -6 -5 -5 -5 -5 -5 -5 -8 ...
## $ dst : chr [1:1458] "A" "A" "A" "A" ...
## $ tzone: chr [1:1458] "America/New_York" "America/Chicago" "America/Chicago" "America/New_York" ...
## - attr(*, "spec")=
## .. cols(
## .. id = col_double(),
## .. name = col_character(),
## .. city = col_character(),
## .. country = col_character(),
## .. faa = col_character(),
## .. icao = col_character(),
## .. lat = col_double(),
## .. lon = col_double(),
## .. alt = col_double(),
## .. tz = col_double(),
## .. dst = col_character(),
## .. tzone = col_character()
## .. )
airports
## # A tibble: 1,458 x 8
## faa name lat lon alt tz dst tzone
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
## 1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A America/New_Yo…
## 2 06A Moton Field Municipal A… 32.5 -85.7 264 -6 A America/Chicago
## 3 06C Schaumburg Regional 42.0 -88.1 801 -6 A America/Chicago
## 4 06N Randall Airport 41.4 -74.4 523 -5 A America/New_Yo…
## 5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A America/New_Yo…
## 6 0A9 Elizabethton Municipal … 36.4 -82.2 1593 -5 A America/New_Yo…
## 7 0G6 Williams County Airport 41.5 -84.5 730 -5 A America/New_Yo…
## 8 0G7 Finger Lakes Regional A… 42.9 -76.8 492 -5 A America/New_Yo…
## 9 0P2 Shoestring Aviation Air… 39.8 -76.6 1000 -5 U America/New_Yo…
## 10 0S9 Jefferson County Intl 48.1 -123. 108 -8 A America/Los_An…
## # … with 1,448 more rows
Pesawat terbang di ambil dari data set planes, kita memungkinkan untuk mencari nama lengkap planes dan fungsi str() kita bisa mengetahui struktur dari data set planes.
Lagkah 5
str(planes)
## tibble [3,322 × 9] (S3: tbl_df/tbl/data.frame)
## $ tailnum : chr [1:3322] "N10156" "N102UW" "N103US" "N104UW" ...
## $ year : int [1:3322] 2004 1998 1999 1999 2002 1999 1999 1999 1999 1999 ...
## $ type : chr [1:3322] "Fixed wing multi engine" "Fixed wing multi engine" "Fixed wing multi engine" "Fixed wing multi engine" ...
## $ manufacturer: chr [1:3322] "EMBRAER" "AIRBUS INDUSTRIE" "AIRBUS INDUSTRIE" "AIRBUS INDUSTRIE" ...
## $ model : chr [1:3322] "EMB-145XR" "A320-214" "A320-214" "A320-214" ...
## $ engines : int [1:3322] 2 2 2 2 2 2 2 2 2 2 ...
## $ seats : int [1:3322] 55 182 182 182 55 182 182 182 182 182 ...
## $ speed : int [1:3322] NA NA NA NA NA NA NA NA NA NA ...
## $ engine : chr [1:3322] "Turbo-fan" "Turbo-fan" "Turbo-fan" "Turbo-fan" ...
planes
## # A tibble: 3,322 x 9
## tailnum year type manufacturer model engines seats speed engine
## <chr> <int> <chr> <chr> <chr> <int> <int> <int> <chr>
## 1 N10156 2004 Fixed wing m… EMBRAER EMB-1… 2 55 NA Turbo-…
## 2 N102UW 1998 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 3 N103US 1999 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 4 N104UW 1999 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 5 N10575 2002 Fixed wing m… EMBRAER EMB-1… 2 55 NA Turbo-…
## 6 N105UW 1999 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 7 N107US 1999 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 8 N108UW 1999 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 9 N109UW 1999 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 10 N110UW 1999 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## # … with 3,312 more rows
Menggunakan select()
Lakukan seleksi terhadap kolom dengan sintak: select(data, …), isikan … dengan nama variabel yang ingin dipilih.
Lagkah 6
planes.se <- dplyr::select(planes, tailnum:manufacturer)
head(planes.se,n=5)
## # A tibble: 5 x 4
## tailnum year type manufacturer
## <chr> <int> <chr> <chr>
## 1 N10156 2004 Fixed wing multi engine EMBRAER
## 2 N102UW 1998 Fixed wing multi engine AIRBUS INDUSTRIE
## 3 N103US 1999 Fixed wing multi engine AIRBUS INDUSTRIE
## 4 N104UW 1999 Fixed wing multi engine AIRBUS INDUSTRIE
## 5 N10575 2002 Fixed wing multi engine EMBRAER
Beberapa fungsi yang dapat digunakan dalam select():
1. ends_with() : menyeleksi kolom dengan akhiran suatu karakter string
2. contains() : menyeleksi kolom yang mengandung suatu karakter string
3. matches() : menyeleksi kolom yang cocok dengan ekspresi
4. one_of() : menyeleksi nama kolom dari sekelompok/grup nama
Kondisi cuaca di ambil dari data set weather, kita memungkinkan untuk mencari kondisi lengkap cuaca dan fungsi str() kita bisa mengetahui struktur dari data set weather.
Lagkah 7
str(weather)
## tibble [26,115 × 15] (S3: tbl_df/tbl/data.frame)
## $ origin : chr [1:26115] "EWR" "EWR" "EWR" "EWR" ...
## $ year : int [1:26115] 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
## $ month : int [1:26115] 1 1 1 1 1 1 1 1 1 1 ...
## $ day : int [1:26115] 1 1 1 1 1 1 1 1 1 1 ...
## $ hour : int [1:26115] 1 2 3 4 5 6 7 8 9 10 ...
## $ temp : num [1:26115] 39 39 39 39.9 39 ...
## $ dewp : num [1:26115] 26.1 27 28 28 28 ...
## $ humid : num [1:26115] 59.4 61.6 64.4 62.2 64.4 ...
## $ wind_dir : num [1:26115] 270 250 240 250 260 240 240 250 260 260 ...
## $ wind_speed: num [1:26115] 10.36 8.06 11.51 12.66 12.66 ...
## $ wind_gust : num [1:26115] NA NA NA NA NA NA NA NA NA NA ...
## $ precip : num [1:26115] 0 0 0 0 0 0 0 0 0 0 ...
## $ pressure : num [1:26115] 1012 1012 1012 1012 1012 ...
## $ visib : num [1:26115] 10 10 10 10 10 10 10 10 10 10 ...
## $ time_hour : POSIXct[1:26115], format: "2013-01-01 01:00:00" "2013-01-01 02:00:00" ...
weather
## # A tibble: 26,115 x 15
## origin year month day hour temp dewp humid wind_dir wind_speed
## <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 EWR 2013 1 1 1 39.0 26.1 59.4 270 10.4
## 2 EWR 2013 1 1 2 39.0 27.0 61.6 250 8.06
## 3 EWR 2013 1 1 3 39.0 28.0 64.4 240 11.5
## 4 EWR 2013 1 1 4 39.9 28.0 62.2 250 12.7
## 5 EWR 2013 1 1 5 39.0 28.0 64.4 260 12.7
## 6 EWR 2013 1 1 6 37.9 28.0 67.2 240 11.5
## 7 EWR 2013 1 1 7 39.0 28.0 64.4 240 15.0
## 8 EWR 2013 1 1 8 39.9 28.0 62.2 250 10.4
## 9 EWR 2013 1 1 9 39.9 28.0 62.2 260 15.0
## 10 EWR 2013 1 1 10 41 28.0 59.6 260 13.8
## # … with 26,105 more rows, and 5 more variables: wind_gust <dbl>, precip <dbl>,
## # pressure <dbl>, visib <dbl>, time_hour <dttm>
Menyeleksi baris dengan filter()
Lakukan seleksi weather yang temperaturnya lebir dari sama dengan 40 :
Lagkah 8
weather.se <- dplyr::filter(weather, temp >= 40)
print(weather.se)
## # A tibble: 19,401 x 15
## origin year month day hour temp dewp humid wind_dir wind_speed
## <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 EWR 2013 1 1 10 41 28.0 59.6 260 13.8
## 2 EWR 2013 1 1 11 41 27.0 57.1 260 15.0
## 3 EWR 2013 1 5 10 41 21.0 44.5 310 10.4
## 4 EWR 2013 1 5 11 42.1 19.9 40.8 320 15.0
## 5 EWR 2013 1 5 12 43.0 19.9 39.4 310 13.8
## 6 EWR 2013 1 5 13 44.1 19.9 37.8 290 11.5
## 7 EWR 2013 1 5 14 44.1 19.9 37.8 310 9.21
## 8 EWR 2013 1 5 15 43.0 19.0 37.9 310 8.06
## 9 EWR 2013 1 5 16 41 19.9 42.5 310 4.60
## 10 EWR 2013 1 6 11 43.0 30.0 59.9 240 10.4
## # … with 19,391 more rows, and 5 more variables: wind_gust <dbl>, precip <dbl>,
## # pressure <dbl>, visib <dbl>, time_hour <dttm>
Dapat pula digunakan operasi logika: < (kurang dari), > (lebih dari), <= (kurang dari sama dengan), >= (lebih dari sama dengan), == (sama dengan), != (tidak sama dengan), %in% (dalam).
Operator pipe: %>%
Pipe operator: %>% dalam dplyr diimport dari package magrittr. Pipe digunakan untuk menyalurkan output dari suatu fungsi ke input fungsi lain. Alih-alih menggunakan fungsi tersarang, digunakanlah pipe yang dibaca dari kiri ke kanan. Contoh:
Lagkah 9
head(select(weather, origin, year, temp), n = 5)
## # A tibble: 5 x 3
## origin year temp
## <chr> <int> <dbl>
## 1 EWR 2013 39.0
## 2 EWR 2013 39.0
## 3 EWR 2013 39.0
## 4 EWR 2013 39.9
## 5 EWR 2013 39.0
dengan menggunakan pipe, dapat dituliskan sebagai berikut :
weather %>%
select(origin, year, temp) %>%
head(n = 5)
## # A tibble: 5 x 3
## origin year temp
## <chr> <int> <dbl>
## 1 EWR 2013 39.0
## 2 EWR 2013 39.0
## 3 EWR 2013 39.0
## 4 EWR 2013 39.9
## 5 EWR 2013 39.0
Menyusun menggunakan arrage()
Untuk mengurutkan suatu kolom, gunakan arrange(). Urutkan data weather, berdasarkan variabel temperature :
Lagkah 10
weather.ar <- arrange(weather, temp)
head(weather.ar , n = 10)
## # A tibble: 10 x 15
## origin year month day hour temp dewp humid wind_dir wind_speed
## <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 EWR 2013 1 23 5 10.9 -4 50.2 270 10.4
## 2 EWR 2013 1 23 6 10.9 -4 50.2 270 11.5
## 3 EWR 2013 1 23 2 12.0 -7.06 41.3 270 10.4
## 4 EWR 2013 1 23 3 12.0 -5.98 43.5 270 8.06
## 5 EWR 2013 1 23 4 12.0 -5.08 45.4 270 9.21
## 6 EWR 2013 1 23 7 12.0 -2.92 50.4 270 11.5
## 7 EWR 2013 1 24 3 12.0 1.94 63.3 30 4.60
## 8 JFK 2013 1 23 4 12.0 -7.06 41.3 280 12.7
## 9 JFK 2013 1 23 5 12.0 -5.08 45.4 280 15.0
## 10 JFK 2013 1 23 6 12.0 -5.08 45.4 290 13.8
## # … with 5 more variables: wind_gust <dbl>, precip <dbl>, pressure <dbl>,
## # visib <dbl>, time_hour <dttm>
Gunakan desc() untuk mengurutkan dari yang terbesar ke yang terkecil:
Lagkah 11
weather.ab <- arrange(weather, desc(temp))
head(weather.ab , n = 10)
## # A tibble: 10 x 15
## origin year month day hour temp dewp humid wind_dir wind_speed
## <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 EWR 2013 7 18 15 100. 66.0 33.2 300 9.21
## 2 EWR 2013 7 19 16 100. 71.1 39.5 230 20.7
## 3 EWR 2013 7 19 13 99.0 72.0 42.1 260 18.4
## 4 EWR 2013 7 19 14 99.0 71.1 40.8 250 20.7
## 5 EWR 2013 7 19 15 99.0 72.0 42.1 240 16.1
## 6 LGA 2013 7 18 15 99.0 64.0 32.0 250 12.7
## 7 LGA 2013 7 19 15 99.0 69.1 38.2 240 16.1
## 8 LGA 2013 7 19 16 99.0 69.1 38.2 230 15.0
## 9 EWR 2013 7 18 12 98.1 69.1 39.2 300 9.21
## 10 EWR 2013 7 18 13 98.1 66.9 36.4 300 11.5
## # … with 5 more variables: wind_gust <dbl>, precip <dbl>, pressure <dbl>,
## # visib <dbl>, time_hour <dttm>
Membuat kolom dengan mutate()
Buat kolom weather_proportion yang merupakan rasio temp terhadap dewp :
Lagkah 12
weather %>%
mutate(weather_proportion = temp/dewp) %>%
head(5)
## # A tibble: 5 x 16
## origin year month day hour temp dewp humid wind_dir wind_speed wind_gust
## <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 EWR 2013 1 1 1 39.0 26.1 59.4 270 10.4 NA
## 2 EWR 2013 1 1 2 39.0 27.0 61.6 250 8.06 NA
## 3 EWR 2013 1 1 3 39.0 28.0 64.4 240 11.5 NA
## 4 EWR 2013 1 1 4 39.9 28.0 62.2 250 12.7 NA
## 5 EWR 2013 1 1 5 39.0 28.0 64.4 260 12.7 NA
## # … with 5 more variables: precip <dbl>, pressure <dbl>, visib <dbl>,
## # time_hour <dttm>, weather_proportion <dbl>
Membuat rangkuman data frame menggunakan summarise()
Untuk melakukan perhitungan statistika dalam suatu kolom, gunakan summarise(). Beberapa fungsi statistika sederhana yang dapat digunakan adalah mean(), median(), sd(), min(), max(), n() untuk mengetahui panjang dari vektor, n_distinct() untuk mengetahui jumlah nilai yang berbeda dalam suatu vektor, first() mengetahui nilai pertama suatu vektor, dan last() mengetahui nilai terakhir suatu vektor.
Tampilkan nilai rata-rata, median, minimum, dan maximum dari variabel temp :
Lagkah 13
weather %>%
summarise(rata2 = mean(dewp), median = median(dewp),
minimum = min(dewp), maximum = max(dewp))
## # A tibble: 1 x 4
## rata2 median minimum maximum
## <dbl> <dbl> <dbl> <dbl>
## 1 NA NA NA NA
Mengelompokkan operasi dengan group_by()
Fungsi group_by() berhubungan dengan konsep “split-apply-combine”. Misalkan, kita menginginkan untuk memisah (split) data frame menggunakan suatu variabel (contoh order taksonomi), mengaplikasikan (apply) fungsi secara individual dalam data frame, dan mengkombinasi (combine) outputnya.
Pisahkan (split) data frame berdasarkan variabel order, kemudian tampilan ringkasan statistika seperti sebelumnya:
Lagkah 14
weather %>%
group_by(month) %>%
summarise(rata2 = mean(dewp), median = median(dewp),
minimum = min(dewp), maximum = max(dewp))
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 12 x 5
## month rata2 median minimum maximum
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 22.3 24.1 -9.94 59
## 2 2 21.6 23 -2.92 46.9
## 3 3 24.8 25.0 1.04 57.2
## 4 4 34.3 37.0 1.04 63.0
## 5 5 48.5 48.9 12.0 69.8
## 6 6 59.5 61.0 34.0 73.9
## 7 7 67.0 69.1 43.0 78.1
## 8 8 NA NA NA NA
## 9 9 53.2 52.0 32 75.0
## 10 10 46.6 48.0 19.0 72.0
## 11 11 28.8 26.1 -7.96 63.0
## 12 12 27.7 27.0 -0.04 62.6
Diagram pada gambar realitional tabel seperti diatas, tetapi sederhana dibandingkan dengan diagram yang akan kita lihat di pada kenyataan yang kita hadapi, untuk memahami diagram seperti diatas dengan mengingat setiap relasi selalu menyangkut sepasang tabel. Kita tidak perlu memahami semuanya; kita hanya perlu memahami rantai hubungan antar tabel yang kita miliki.
Untuk tabel nycflights13 :
1. flights terhubung dengan planes melalui satu variable, tailnum.
2. flights terhubung dengan airlines melalui variable pembawa.
3. flights terhubung dengan airports pada dua cara : yaitu melalui the origin and dest variables.
4. flights terhubung dengan weather melalui origin (the location), dan year, month, day dan hour (the time).
Kunci
Variabel yang digunakan untuk menghubungkan setiap pasangan tabel dikatakan sebagai kunci. Kunci adalah variabel (atau kumpulan variabel) yang secara unik mengidentifikasi observasi. Dalam kasus sederhana, satu variabel sudah cukup untuk mengidentifikasi observasi. Misalnya, setiap bidang diidentifikasi secara unik oleh tailnumnya. Dalam kasus lain, beberapa variabel mungkin diperlukan. Misalnya, untuk mengidentifikasi pengamatan cuaca, kita memerlukan lima variabel: tahun, bulan, hari, jam, dan asal.
Ada dua jenis kunci:
1. A primary key / Kunci utama adalah variabel yang unik untuk mengidentifikasi observasi di tabelnya sendiri. Misalnya, planes$tailnum adalah kunci utama karena kunci ini secara unik mengidentifikasi setiap bidang di tabel plane.
2. A foreign key / Kunci asing adalah variabel yang unik untuk mengidentifikasi observasi di tabel lain. Misalnya, flight$tailnum adalah kunci asing karena muncul di tabel flight yang mencocokkan setiap flight dengan plane.
Sebuah variabel dapat berupa kunci utama dan kunci asing. Misalnya, origin adalah bagian dari kunci utama weather, dan juga kunci asing untuk tabel airport.
Setelah kita mengidentifikasi kunci utama di tabel, praktik yang baik adalah memverifikasi bahwa kunci tersebut memang mengidentifikasi setiap pengamatan secara unik. Salah satu cara untuk melakukannya adalah dengan fungsi count() pada kunci utama dan mencari entri di mana n lebih besar dari satu:
Lagkah 15
planes %>%
count(tailnum) %>%
filter(n > 1)
## # A tibble: 0 x 2
## # … with 2 variables: tailnum <chr>, n <int>
weather %>%
count(year, month, day, hour, origin) %>%
filter(n > 1)
## # A tibble: 3 x 6
## year month day hour origin n
## <int> <int> <int> <int> <chr> <int>
## 1 2013 11 3 1 EWR 2
## 2 2013 11 3 1 JFK 2
## 3 2013 11 3 1 LGA 2
Terkadang tabel tidak memiliki kunci utama secara eksplisit: dimana setiap baris dapat dikatakan sebagai pengamatan, tetapi tidak ada kombinasi variabel yang dapat diandalkan untuk mengidentifikasi sebagai kunci utama. Misalnya, apa kunci utama di tabel flights ? Kita mungkin dapat mengira bahwa kata kunci adalah date dan tailnum , tetapi tidak ada yang unik:
Lagkah 16
flights
## # A tibble: 336,776 x 19
## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
## <int> <int> <int> <int> <int> <dbl> <int> <int>
## 1 2013 1 1 517 515 2 830 819
## 2 2013 1 1 533 529 4 850 830
## 3 2013 1 1 542 540 2 923 850
## 4 2013 1 1 544 545 -1 1004 1022
## 5 2013 1 1 554 600 -6 812 837
## 6 2013 1 1 554 558 -4 740 728
## 7 2013 1 1 555 600 -5 913 854
## 8 2013 1 1 557 600 -3 709 723
## 9 2013 1 1 557 600 -3 838 846
## 10 2013 1 1 558 600 -2 753 745
## # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
Lagkah 17
flights %>%
count(year, month, day, flight) %>%
filter(n > 1)
## # A tibble: 29,768 x 5
## year month day flight n
## <int> <int> <int> <int> <int>
## 1 2013 1 1 1 2
## 2 2013 1 1 3 2
## 3 2013 1 1 4 2
## 4 2013 1 1 11 3
## 5 2013 1 1 15 2
## 6 2013 1 1 21 2
## 7 2013 1 1 27 4
## 8 2013 1 1 31 2
## 9 2013 1 1 32 2
## 10 2013 1 1 35 2
## # … with 29,758 more rows
flights %>%
count(year, month, day, tailnum) %>%
filter(n > 1)
## # A tibble: 64,928 x 5
## year month day tailnum n
## <int> <int> <int> <chr> <int>
## 1 2013 1 1 N0EGMQ 2
## 2 2013 1 1 N11189 2
## 3 2013 1 1 N11536 2
## 4 2013 1 1 N11544 3
## 5 2013 1 1 N11551 2
## 6 2013 1 1 N12540 2
## 7 2013 1 1 N12567 2
## 8 2013 1 1 N13123 2
## 9 2013 1 1 N13538 3
## 10 2013 1 1 N13566 3
## # … with 64,918 more rows
Saat mulai bekerja dengan data set ini, kita bisa berasumsi bahwa setiap flight number hanya akan digunakan sekali per hari: itu akan membuatnya lebih mudah untuk mengkomunikasikan masalah dengan flight tertentu. Sayangnya, itu bukan masalahnya! Jika tabel tidak memiliki kunci utama, terkadang berguna untuk menambahkannya dengan fungsi mutate() dan fungsi row_number(). Itu membuatnya lebih mudah untuk mencocokkan pengamatan jika kita telah melakukan beberapa pemfilteran dan ingin memeriksa kembali dengan data asli. Ini dapat disebut sebagai kunci pengganti.
Kunci utama dan kunci asing terkait di tabel lain akan membentuk relasi. Hubungan biasanya satu-ke-banyak. Misalnya setiap penerbangan memiliki satu pesawat, tetapi setiap pesawat memiliki banyak penerbangan. Di data lain, kita terkadang akan melihat hubungan 1-dengan-1. Kita dapat menganggap ini sebagai kasus khusus yaitu 1-ke-banyak. Kita dapat memodelkan relasi banyak-ke-banyak dengan relasi banyak-ke-1 ditambah relasi 1-ke-banyak. Misalnya, dalam data ini ada hubungan banyak ke banyak antara airlines dan airports: setiap airline ke banyak airports; setiap airport menampung banyak airlines.
Mutating joins
Alat pertama yang akan kita lihat untuk menggabungkan sepasang tabel adalah mutating join. Mutating join memungkinkan kita menggabungkan variabel dari dua tabel. Ini pertama kali mencocokkan observasi dengan kuncinya, kemudian menyalin seluruh variabel dari satu tabel ke tabel lainnya.
Seperti fungsi mutate(), fungsi gabungan menambahkan variabel ke kanan, jadi jika kita sudah memiliki banyak variabel, variabel baru tidak akan dicetak. Untuk contohnya seperti ini, kami akan mempermudah untuk melihat apa yang terjadi di contoh dengan membuat kumpulan data yang lebih sempit:
Lagkah 18
flights2 <- flights %>%
select(year:day, hour, origin, dest, tailnum, carrier)
flights2
## # A tibble: 336,776 x 8
## year month day hour origin dest tailnum carrier
## <int> <int> <int> <dbl> <chr> <chr> <chr> <chr>
## 1 2013 1 1 5 EWR IAH N14228 UA
## 2 2013 1 1 5 LGA IAH N24211 UA
## 3 2013 1 1 5 JFK MIA N619AA AA
## 4 2013 1 1 5 JFK BQN N804JB B6
## 5 2013 1 1 6 LGA ATL N668DN DL
## 6 2013 1 1 5 EWR ORD N39463 UA
## 7 2013 1 1 6 EWR FLL N516JB B6
## 8 2013 1 1 6 LGA IAD N829AS EV
## 9 2013 1 1 6 JFK MCO N593JB B6
## 10 2013 1 1 6 LGA ORD N3ALAA AA
## # … with 336,766 more rows
(Ingat, saat kita berada di RStudio, kita juga dapat menggunakan fyngsi View() untuk menghindari masalah ini.)
Bayangkan kita ingin menambahkan nama lengkap maskapai penerbangan ke data flights2. Kita dapat menggabungkan bingkai data maskapai dan penerbangan2 dengan left_join ():
Lagkah 20
flights2 %>%
select(-origin, -dest) %>%
left_join(airlines, by = "carrier")
## # A tibble: 336,776 x 7
## year month day hour tailnum carrier name
## <int> <int> <int> <dbl> <chr> <chr> <chr>
## 1 2013 1 1 5 N14228 UA United Air Lines Inc.
## 2 2013 1 1 5 N24211 UA United Air Lines Inc.
## 3 2013 1 1 5 N619AA AA American Airlines Inc.
## 4 2013 1 1 5 N804JB B6 JetBlue Airways
## 5 2013 1 1 6 N668DN DL Delta Air Lines Inc.
## 6 2013 1 1 5 N39463 UA United Air Lines Inc.
## 7 2013 1 1 6 N516JB B6 JetBlue Airways
## 8 2013 1 1 6 N829AS EV ExpressJet Airlines Inc.
## 9 2013 1 1 6 N593JB B6 JetBlue Airways
## 10 2013 1 1 6 N3ALAA AA American Airlines Inc.
## # … with 336,766 more rows
Hasil dari bergabungnya airlines ke flights2 adalah variabel tambahan: name. Inilah mengapa kita menyebut jenis join ini sebagai mutating join. Dalam kasus ini, kita bisa mendapatkan tempat yang sama menggunakan mutate() dan subset dasar R.
Lagkah 21
flights2 %>%
select(-origin, -dest) %>%
mutate(name = airlines$name[match(carrier, airlines$carrier)])
## # A tibble: 336,776 x 7
## year month day hour tailnum carrier name
## <int> <int> <int> <dbl> <chr> <chr> <chr>
## 1 2013 1 1 5 N14228 UA United Air Lines Inc.
## 2 2013 1 1 5 N24211 UA United Air Lines Inc.
## 3 2013 1 1 5 N619AA AA American Airlines Inc.
## 4 2013 1 1 5 N804JB B6 JetBlue Airways
## 5 2013 1 1 6 N668DN DL Delta Air Lines Inc.
## 6 2013 1 1 5 N39463 UA United Air Lines Inc.
## 7 2013 1 1 6 N516JB B6 JetBlue Airways
## 8 2013 1 1 6 N829AS EV ExpressJet Airlines Inc.
## 9 2013 1 1 6 N593JB B6 JetBlue Airways
## 10 2013 1 1 6 N3ALAA AA American Airlines Inc.
## # … with 336,766 more rows
Tetapi ini sulit untuk digeneralisasi ketika kita perlu mencocokkan beberapa variabel, dan membutuhkan pembacaan yang cermat untuk mengetahui maksud keseluruhan.
Bagian berikut menjelaskan, secara rinci, cara kerja mutating joins. Kita akan mulai dengan mempelajari representasi visual yang berguna dari gabungan. Kita kemudian akan menggunakannya untuk menjelaskan empat mutating join functions : inner join, dan tiga outer joins. Saat bekerja dengan data nyata, kunci tidak selalu mengidentifikasi pengamatan secara unik, jadi selanjutnya kita akan membicarakan tentang apa yang terjadi jika tidak ada kecocokan unik. Terakhir, Anda akan mempelajari cara memberi tahu fungsi dplyr tentang variabel mana yang merupakan kunci untuk gabungan tertentu.
Mendefinisikan kolom kunci
Selama ini, pasangan tabel selalu digabungkan dengan satu variabel, dan variabel tersebut memiliki nama yang sama di kedua tabel. Batasan itu dikodekan oleh = “key”. Kita dapat menggunakan nilai lain untuk oleh untuk menyambungkan tabel dengan cara lain:
1. Defaultnya, by = NULL, menggunakan semua variabel yang muncul di kedua tabel, yang disebut natural join. Misalnya, tabel flights dan weather cocok dengan variabel umumnya: year, month, day, hour dan origin.
Lagkah 22
flights2 %>%
left_join(weather)
## Joining, by = c("year", "month", "day", "hour", "origin")
## # A tibble: 336,776 x 18
## year month day hour origin dest tailnum carrier temp dewp humid
## <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 2013 1 1 5 EWR IAH N14228 UA 39.0 28.0 64.4
## 2 2013 1 1 5 LGA IAH N24211 UA 39.9 25.0 54.8
## 3 2013 1 1 5 JFK MIA N619AA AA 39.0 27.0 61.6
## 4 2013 1 1 5 JFK BQN N804JB B6 39.0 27.0 61.6
## 5 2013 1 1 6 LGA ATL N668DN DL 39.9 25.0 54.8
## 6 2013 1 1 5 EWR ORD N39463 UA 39.0 28.0 64.4
## 7 2013 1 1 6 EWR FLL N516JB B6 37.9 28.0 67.2
## 8 2013 1 1 6 LGA IAD N829AS EV 39.9 25.0 54.8
## 9 2013 1 1 6 JFK MCO N593JB B6 37.9 27.0 64.3
## 10 2013 1 1 6 LGA ORD N3ALAA AA 39.9 25.0 54.8
## # … with 336,766 more rows, and 7 more variables: wind_dir <dbl>,
## # wind_speed <dbl>, wind_gust <dbl>, precip <dbl>, pressure <dbl>,
## # visib <dbl>, time_hour <dttm>
2. Vektor karakter, dengan = “x”. Ini seperti gabungan alami, tetapi hanya menggunakan beberapa variabel umum. Misalnya, flights dan planes memiliki variabel year, tetapi artinya berbeda, jadi kami hanya ingin menggabungkan berdasarkan tailnum.
Lagkah 23
flights2 %>%
left_join(planes, by = "tailnum")
## # A tibble: 336,776 x 16
## year.x month day hour origin dest tailnum carrier year.y type
## <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <int> <chr>
## 1 2013 1 1 5 EWR IAH N14228 UA 1999 Fixe…
## 2 2013 1 1 5 LGA IAH N24211 UA 1998 Fixe…
## 3 2013 1 1 5 JFK MIA N619AA AA 1990 Fixe…
## 4 2013 1 1 5 JFK BQN N804JB B6 2012 Fixe…
## 5 2013 1 1 6 LGA ATL N668DN DL 1991 Fixe…
## 6 2013 1 1 5 EWR ORD N39463 UA 2012 Fixe…
## 7 2013 1 1 6 EWR FLL N516JB B6 2000 Fixe…
## 8 2013 1 1 6 LGA IAD N829AS EV 1998 Fixe…
## 9 2013 1 1 6 JFK MCO N593JB B6 2004 Fixe…
## 10 2013 1 1 6 LGA ORD N3ALAA AA NA <NA>
## # … with 336,766 more rows, and 6 more variables: manufacturer <chr>,
## # model <chr>, engines <int>, seats <int>, speed <int>, engine <chr>
Perhatikan bahwa variabel year (yang muncul di kedua bingkai data masukan, tetapi tidak dibatasi agar sama) tidak ambigu dalam keluaran dengan sufiks.
3. Vektor karakter bernama: oleh = c (“a” = “b”). Ini akan mencocokkan variabel a di tabel x dengan variabel b di tabel y. Variabel dari x akan digunakan dalam output.
Misalnya jika kita ingin menggambar peta kita perlu menggabungkan data flights dengan data airports yang berisi lokasi (lat dan lon) dari setiap bandara. Setiap flight memiliki airport asal dan tujuan, jadi kita perlu menentukan mana yang ingin kami ikuti:
Lagkah 24
flights2 %>%
left_join(airports, c("dest" = "faa"))
## # A tibble: 336,776 x 15
## year month day hour origin dest tailnum carrier name lat lon alt
## <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 2013 1 1 5 EWR IAH N14228 UA Geor… 30.0 -95.3 97
## 2 2013 1 1 5 LGA IAH N24211 UA Geor… 30.0 -95.3 97
## 3 2013 1 1 5 JFK MIA N619AA AA Miam… 25.8 -80.3 8
## 4 2013 1 1 5 JFK BQN N804JB B6 <NA> NA NA NA
## 5 2013 1 1 6 LGA ATL N668DN DL Hart… 33.6 -84.4 1026
## 6 2013 1 1 5 EWR ORD N39463 UA Chic… 42.0 -87.9 668
## 7 2013 1 1 6 EWR FLL N516JB B6 Fort… 26.1 -80.2 9
## 8 2013 1 1 6 LGA IAD N829AS EV Wash… 38.9 -77.5 313
## 9 2013 1 1 6 JFK MCO N593JB B6 Orla… 28.4 -81.3 96
## 10 2013 1 1 6 LGA ORD N3ALAA AA Chic… 42.0 -87.9 668
## # … with 336,766 more rows, and 3 more variables: tz <dbl>, dst <chr>,
## # tzone <chr>
flights2 %>%
left_join(airports, c("origin" = "faa"))
## # A tibble: 336,776 x 15
## year month day hour origin dest tailnum carrier name lat lon alt
## <int> <int> <int> <dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 2013 1 1 5 EWR IAH N14228 UA Newa… 40.7 -74.2 18
## 2 2013 1 1 5 LGA IAH N24211 UA La G… 40.8 -73.9 22
## 3 2013 1 1 5 JFK MIA N619AA AA John… 40.6 -73.8 13
## 4 2013 1 1 5 JFK BQN N804JB B6 John… 40.6 -73.8 13
## 5 2013 1 1 6 LGA ATL N668DN DL La G… 40.8 -73.9 22
## 6 2013 1 1 5 EWR ORD N39463 UA Newa… 40.7 -74.2 18
## 7 2013 1 1 6 EWR FLL N516JB B6 Newa… 40.7 -74.2 18
## 8 2013 1 1 6 LGA IAD N829AS EV La G… 40.8 -73.9 22
## 9 2013 1 1 6 JFK MCO N593JB B6 John… 40.6 -73.8 13
## 10 2013 1 1 6 LGA ORD N3ALAA AA La G… 40.8 -73.9 22
## # … with 336,766 more rows, and 3 more variables: tz <dbl>, dst <chr>,
## # tzone <chr>
Filtering joins
Memfilter gabungan pengamatan cocok dengan cara yang sama seperti mutating joins, tapi mempengaruhi pengamatan, bukan variabel. Ada dua jenis:
1. semi_join (x, y) menyimpan semua observasi di x yang memiliki kecocokan di y.
2. anti_join (x, y) menghapus semua observasi di x yang memiliki kecocokan di y.
Semi_join berguna untuk mencocokkan tabel ringkasan yang difilter kembali ke baris asli. Misalnya, bayangkan kita telah menemukan sepuluh tujuan terpopuler:
Lagkah 25
top_dest <- flights %>%
count(dest, sort = TRUE) %>%
head(10)
top_dest
## # A tibble: 10 x 2
## dest n
## <chr> <int>
## 1 ORD 17283
## 2 ATL 17215
## 3 LAX 16174
## 4 BOS 15508
## 5 MCO 14082
## 6 CLT 14064
## 7 SFO 13331
## 8 FLL 12055
## 9 MIA 11728
## 10 DCA 9705
Lagkah 26
flights %>%
filter(dest %in% top_dest$dest)
## # A tibble: 141,145 x 19
## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
## <int> <int> <int> <int> <int> <dbl> <int> <int>
## 1 2013 1 1 542 540 2 923 850
## 2 2013 1 1 554 600 -6 812 837
## 3 2013 1 1 554 558 -4 740 728
## 4 2013 1 1 555 600 -5 913 854
## 5 2013 1 1 557 600 -3 838 846
## 6 2013 1 1 558 600 -2 753 745
## 7 2013 1 1 558 600 -2 924 917
## 8 2013 1 1 558 600 -2 923 937
## 9 2013 1 1 559 559 0 702 706
## 10 2013 1 1 600 600 0 851 858
## # … with 141,135 more rows, and 11 more variables: arr_delay <dbl>,
## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
Tetapi sulit untuk memperluas pendekatan itu ke banyak variabel. Misalnya, bayangkan kita menemukan 10 hari dengan rata-rata penundaan tertinggi. Bagaimana Anda membuat pernyataan filter yang menggunakan tahun, bulan, dan hari untuk mencocokkannya kembali ke penerbangan?
Sebagai gantinya kita dapat menggunakan semi-join, yang menghubungkan dua tabel seperti mutating join, tetapi alih-alih menambahkan kolom baru, hanya pertahankan baris dalam x yang memiliki kecocokan di y:
Lagkah 27
flights %>%
semi_join(top_dest)
## Joining, by = "dest"
## # A tibble: 141,145 x 19
## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
## <int> <int> <int> <int> <int> <dbl> <int> <int>
## 1 2013 1 1 542 540 2 923 850
## 2 2013 1 1 554 600 -6 812 837
## 3 2013 1 1 554 558 -4 740 728
## 4 2013 1 1 555 600 -5 913 854
## 5 2013 1 1 557 600 -3 838 846
## 6 2013 1 1 558 600 -2 753 745
## 7 2013 1 1 558 600 -2 924 917
## 8 2013 1 1 558 600 -2 923 937
## 9 2013 1 1 559 559 0 702 706
## 10 2013 1 1 600 600 0 851 858
## # … with 141,135 more rows, and 11 more variables: arr_delay <dbl>,
## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
Anti-gabungan berguna untuk mendiagnosis ketidakcocokan gabungan. Misalnya, saat menghubungkan penerbangan dan pesawat, Anda mungkin tertarik untuk mengetahui bahwa ada banyak penerbangan yang tidak memiliki kecocokan dalam pesawat:
Lagkah 28
flights %>%
anti_join(planes, by = "tailnum") %>%
count(tailnum, sort = TRUE)
## # A tibble: 722 x 2
## tailnum n
## <chr> <int>
## 1 <NA> 2512
## 2 N725MQ 575
## 3 N722MQ 513
## 4 N723MQ 507
## 5 N713MQ 483
## 6 N735MQ 396
## 7 N0EGMQ 371
## 8 N534MQ 364
## 9 N542MQ 363
## 10 N531MQ 349
## # … with 712 more rows
Tugas untuk mendapatkan sertifikat kelulusan, hasil di upload di Facebook