Relational Data

Seperti biasa, untuk persoalan menata dan manipulasi data, jangan lupa awali dengan load library ‘Tidyverse’.

Oke, masih ingat dengan ini?

table4a
## # A tibble: 3 x 3
##   country     `1999` `2000`
## * <chr>        <int>  <int>
## 1 Afghanistan    745   2666
## 2 Brazil       37737  80488
## 3 China       212258 213766
table4b
## # A tibble: 3 x 3
##   country         `1999`     `2000`
## * <chr>            <int>      <int>
## 1 Afghanistan   19987071   20595360
## 2 Brazil       172006362  174504898
## 3 China       1272915272 1280428583

Ini adalh sample data set yg sama di tunjukan pada wrangle pertama; dimana ‘table4a’ menunjukkan tabel dengan variabel negara berisi tiga value, dua kolom tahun berisi jumlah case. Sedangkan table4b memiliki struktur yg sama, namun value kolom tahunnya merupakan nilai populasi dari case.

Seperti pada pembahasan sebelumnya (yg tidak dibahas sama sekali), kita melihat bagaimana cara untuk menggabungkan dua table tersebut dengan syntax ‘join_left()’. Pada realita data, kita tidak akan hanya berususan dengan satu file data, namun mungkin 2, 3, bahkan 10 file data yg berbeda dalam satu project. Menjadi hal penting bagi kita untuk mengolah hubungan antar file data tersebut, untuk kemudian membuat satu database relevan yg handal.

Lanjut kembali pada kedua data di atas.

# tifying kedua data.
tidy4a <- table4a %>% pivot_longer(c(`1999`,`2000`), names_to = "year",
                                   values_to = "case")
tidy4b <- table4b %>% pivot_longer(c(`1999`,`2000`), names_to = "year", 
                                   values_to = "population")
left_join(tidy4a,tidy4b)
## Joining, by = c("country", "year")
## # A tibble: 6 x 4
##   country     year    case population
##   <chr>       <chr>  <int>      <int>
## 1 Afghanistan 1999     745   19987071
## 2 Afghanistan 2000    2666   20595360
## 3 Brazil      1999   37737  172006362
## 4 Brazil      2000   80488  174504898
## 5 China       1999  212258 1272915272
## 6 China       2000  213766 1280428583

Satu prinsip mendasar tentang relasi data : “Seluruh hubungan antar tiga atau lebih tabel merupakan pengembangan dari karakteristik relasi antar sepasang tabel.”

Ada beberapa istilah atau ide baru dalam topik relasi data. * Mutating join; penambahan variabel baru pada satu dataframe berdasarkan kecocokan observasi pada tabel lainnya. * Filtering join; memilah observasi berdasarkan pengamatan pada tabel lain. * Set operation; memperlakukan observasi seperti layaknya anggota himpunan (baca : set)

Pembelajaran ini akan membawa kita pada topik yg lebih jauh pada database management system (DBMS) yg populer menggunakan bahasa SQL.

Pembahasan

Keperluan data Untuk pembahasan ini, kita akan menggunakan library data ‘nycflights13’.

library(nycflights13)
## Warning: package 'nycflights13' was built under R version 4.1.2

Paket data nycflights13 memiliki 4 tibble (4 tabel) yg berguna untuk pembelajaran relasi tabel.

Kita urai dulu satu persatu tabelnya (airlines, airports, planes, weather)

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.
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/~
##  2 06A   Moton Field Municipal Airport   32.5  -85.7   264    -6 A     America/~
##  3 06C   Schaumburg Regional             42.0  -88.1   801    -6 A     America/~
##  4 06N   Randall Airport                 41.4  -74.4   523    -5 A     America/~
##  5 09J   Jekyll Island Airport           31.1  -81.4    11    -5 A     America/~
##  6 0A9   Elizabethton Municipal Airport  36.4  -82.2  1593    -5 A     America/~
##  7 0G6   Williams County Airport         41.5  -84.5   730    -5 A     America/~
##  8 0G7   Finger Lakes Regional Airport   42.9  -76.8   492    -5 A     America/~
##  9 0P2   Shoestring Aviation Airfield    39.8  -76.6  1000    -5 U     America/~
## 10 0S9   Jefferson County Intl           48.1 -123.    108    -8 A     America/~
## # ... with 1,448 more rows
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
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>

Pembahasan :

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>

Keempat tabel sebelumnya memiliki keterkaitan atau relasi dengan tabel flights dalam paket data nycflights13. Seperti variabel origin dan dest yg terhubung dengan data ‘faa’ dalam tabel airports, data ‘tailnum’ yg terbubung dengan variabel bernama sama dalam tabel ‘planes’, juga data tanggal penerbangan yg terhubungan data soal cuaca.

Kuncinya adalah ‘kunci’

Satu poin yang mendasari seluruh hubungan antar data adalah ‘key’. ‘Key’ adalah sebuah variabel yang mengidentifikasikan secara unik masing-masing observasi. Sebuah variabel bisa dianggap sebagai key apabila valuenya berbeda di tiap observasi poin (tidak ada perulangan sama sekali).

Ada dua jenis key di sini : * Primary key : Sebuah variabel yg mengidentifikasi secara unik observasi dalama tabelnya itu sendiri. ex : planes$tailnum * Foreign key : Sebuah variabel yg mengidentifikasi secara unik observasi di tabel lain. Seluruh hubungan antar tabel ini dibangun atas dasar relasi primary dan foreign key tersebut.

Praktiknya, untuk menguji apakah sebuah variabel layak disebut sebagai primary key, kita perlu mengujinya terlebih dahulu dengan menghitung jumlah (countnya).

planes %>% count(tailnum) %>%
  filter(n > 1)
## # A tibble: 0 x 2
## # ... with 2 variables: tailnum <chr>, n <int>

Jika tidak ada, maka variabel tersebut layak mencadi senjata terbaik. Sebaliknya, jika ada satu saja count variabel lebih dari satu. Maka dia tidak layak dijadikan primary key.

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

Seperti di atas.

Ada kalanya sebuah tabel sama sekali tidak memiliki variabel yg layak dijadikan prumary key. Untuk mengatasi hal ini, kita perlu membuat satu variabel baru yg biasanya didasarkan pada row_number(). Ini disebut sebagai Surrogate key.

Membuat Surrogate key

Karena dataset ‘flights’ tidak memiliki primary key, maka kita perlu membuat surrogate key. Biasanya, cara paling mudah adalah membuat row_number().

flights2 <- flights %>% mutate(No = row_number()) %>% relocate(No,everything())
flights2
## # A tibble: 336,776 x 20
##       No  year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1     1  2013     1     1      517            515         2      830
##  2     2  2013     1     1      533            529         4      850
##  3     3  2013     1     1      542            540         2      923
##  4     4  2013     1     1      544            545        -1     1004
##  5     5  2013     1     1      554            600        -6      812
##  6     6  2013     1     1      554            558        -4      740
##  7     7  2013     1     1      555            600        -5      913
##  8     8  2013     1     1      557            600        -3      709
##  9     9  2013     1     1      557            600        -3      838
## 10    10  2013     1     1      558            600        -2      753
## # ... with 336,766 more rows, and 12 more variables: sched_arr_time <int>,
## #   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>

Mencari primary key

library(babynames)
## Warning: package 'babynames' was built under R version 4.1.2
babynames
## # A tibble: 1,924,665 x 5
##     year sex   name          n   prop
##    <dbl> <chr> <chr>     <int>  <dbl>
##  1  1880 F     Mary       7065 0.0724
##  2  1880 F     Anna       2604 0.0267
##  3  1880 F     Emma       2003 0.0205
##  4  1880 F     Elizabeth  1939 0.0199
##  5  1880 F     Minnie     1746 0.0179
##  6  1880 F     Margaret   1578 0.0162
##  7  1880 F     Ida        1472 0.0151
##  8  1880 F     Alice      1414 0.0145
##  9  1880 F     Bertha     1320 0.0135
## 10  1880 F     Sarah      1288 0.0132
## # ... with 1,924,655 more rows

Kita coba cek mana di antara kelima variabel di atas yg menjadi primary key.

babynames %>% count(name) %>% filter(n > 1)
## # A tibble: 76,467 x 2
##    name          n
##    <chr>     <int>
##  1 Aaban        10
##  2 Aabha         5
##  3 Aabid         2
##  4 Aabriella     5
##  5 Aadam        26
##  6 Aadan        11
##  7 Aadarsh      17
##  8 Aaden        18
##  9 Aadesh        4
## 10 Aadhav       11
## # ... with 76,457 more rows

Tidak ada primary key, berarti haru buat sorrugate key lagi.

library(fueleconomy)
## Warning: package 'fueleconomy' was built under R version 4.1.2
vehicles
## # A tibble: 33,442 x 12
##       id make  model        year class trans drive   cyl displ fuel    hwy   cty
##    <dbl> <chr> <chr>       <dbl> <chr> <chr> <chr> <dbl> <dbl> <chr> <dbl> <dbl>
##  1 13309 Acura 2.2CL/3.0CL  1997 Subc~ Auto~ Fron~     4   2.2 Regu~    26    20
##  2 13310 Acura 2.2CL/3.0CL  1997 Subc~ Manu~ Fron~     4   2.2 Regu~    28    22
##  3 13311 Acura 2.2CL/3.0CL  1997 Subc~ Auto~ Fron~     6   3   Regu~    26    18
##  4 14038 Acura 2.3CL/3.0CL  1998 Subc~ Auto~ Fron~     4   2.3 Regu~    27    19
##  5 14039 Acura 2.3CL/3.0CL  1998 Subc~ Manu~ Fron~     4   2.3 Regu~    29    21
##  6 14040 Acura 2.3CL/3.0CL  1998 Subc~ Auto~ Fron~     6   3   Regu~    26    17
##  7 14834 Acura 2.3CL/3.0CL  1999 Subc~ Auto~ Fron~     4   2.3 Regu~    27    20
##  8 14835 Acura 2.3CL/3.0CL  1999 Subc~ Manu~ Fron~     4   2.3 Regu~    29    21
##  9 14836 Acura 2.3CL/3.0CL  1999 Subc~ Auto~ Fron~     6   3   Regu~    26    17
## 10 11789 Acura 2.5TL        1995 Comp~ Auto~ Fron~     5   2.5 Prem~    23    18
## # ... with 33,432 more rows

Kita coba pada id

vehicles %>% count(id) %>% filter(n > 1)
## # A tibble: 0 x 2
## # ... with 2 variables: id <dbl>, n <int>

yep. Benar variabel id bisa dijadikan primary key.

Mutating joins

Tool pertama yg kita pelajari untuk mengombinasikan sepasang tabel adalah ‘mutating join’. Tool ini memiliki fungsi utama untuk mengombinasikan variabel dari dua tabel. Pertama, komputer akan mencocokan poin observasi dengan kuncinya, dan lalu menggandakan variabel dari satu tabel ke tabel lainnya. Sama seperti fungsi mutate() yang menempatkan variabel baru di sebelah kanan, mutating join juga akan menempatkan variabel hasil kombinasi ke sisi kanan tabel, dan membuat variabel baru ini tidak terlihat.

flightsNew <- flights %>% select(year:day, hour, origin, dest,tailnum,
                                 carrier)
flightsNew
## # 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

Nah, kemudian, anggaplah kita ingin menggabungkan data flightsNew dengan nama lengkap maskapai dari ‘airlines’, maka kita perlu mencari tahu dulu apa primary key dari ‘airlines’.

Kenapa airlines? Karena dalam kasus ini, tabel flightsNew merupakan tabel yg ‘menerima’ hasil gabungan, dengan kata lain, tempat mencocokkan kunci. Sementara tabel ‘airplanes’ di sini adalah tabel sumber di mana variabel nama maskapai dicopy ke tabel penerima. Jadi, di sini dari tabel ‘airlines’ lah primary key yang diapakai.

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.
airlines %>% count(carrier) %>% filter(n >1)
## # A tibble: 0 x 2
## # ... with 2 variables: carrier <chr>, n <int>

Baik, dari data di atas, kita tahu bahwa ‘airlines’ primary key adalah ‘carrier’. Dari sini, kita tinggal menggabungkannya saja.

flightsNew %>% left_join(airlines, by = "carrier")
## # A tibble: 336,776 x 9
##     year month   day  hour origin dest  tailnum carrier name                    
##    <int> <int> <int> <dbl> <chr>  <chr> <chr>   <chr>   <chr>                   
##  1  2013     1     1     5 EWR    IAH   N14228  UA      United Air Lines Inc.   
##  2  2013     1     1     5 LGA    IAH   N24211  UA      United Air Lines Inc.   
##  3  2013     1     1     5 JFK    MIA   N619AA  AA      American Airlines Inc.  
##  4  2013     1     1     5 JFK    BQN   N804JB  B6      JetBlue Airways         
##  5  2013     1     1     6 LGA    ATL   N668DN  DL      Delta Air Lines Inc.    
##  6  2013     1     1     5 EWR    ORD   N39463  UA      United Air Lines Inc.   
##  7  2013     1     1     6 EWR    FLL   N516JB  B6      JetBlue Airways         
##  8  2013     1     1     6 LGA    IAD   N829AS  EV      ExpressJet Airlines Inc.
##  9  2013     1     1     6 JFK    MCO   N593JB  B6      JetBlue Airways         
## 10  2013     1     1     6 LGA    ORD   N3ALAA  AA      American Airlines Inc.  
## # ... with 336,766 more rows

Memahami ‘Joins’

Kita sempat membahas soal bagaimana jika data tidak memiliki primary key, dan kita bisa menangani nya dengan membuat surrogate key. Contoh simpel dari ini adalah dengan membuat variabel baru berisi row_number(). Tapi apa hanya ini yang bisa kita lakukan?

Untuk menjawab pertanyaan tersebut. Kita perlu memahami lebih dalam tentang prinsip dari penggabungan atau join.

Prinsip dasar dari penggabungan atau join adalah variabel yang menjadi key. Seluruh variabel lain akan mengikuti key. Ada beberapa tipe join di sini : * Inner join Ini adalah tipe join paling sederhana, di mana fungsi inner_join() akan menghasilkan data frame baru yang berisi seluruh dan hanya value dengan key yang cocok diantara dua atau lebih tabel.

x <- tribble(
  ~key, ~val_x,
  1, "x1",
  2, "x2",
  3, "x3"
)

y <- tribble(
  ~key, ~val_y,
  1, "y1",
  2, "y2",
  4, "y3"
)

Kita akan menggunakan contoh data di atas untuk mengilustrasikan bagaimana tipe-tipe join bekerja.

x %>% inner_join(y, by = "key")
## # A tibble: 2 x 3
##     key val_x val_y
##   <dbl> <chr> <chr>
## 1     1 x1    y1   
## 2     2 x2    y2

Perhatikan bahwa key 3 dari variabel x dan key 4 dari variabel y tidak muncul. Inilah yg dimaksud dari inner_join(). Kedua key tersebut tidak muncul karena tidak ada yg cocok di antara mereka. Dalam inner_join(), baris yg tidak cocok, tidak akan ditampilkan

  • Outer Join Berbeda dengan inner_join yang hanya menampilkan baris observasi yg memiliki key cocok pada kedua tabel, outer_join akan menampilkan baris observasi yang key nya muncul paling tidak di salah satu tabel. Outer join terbagi dalam tiga jenis :
    • Left Join : yg tetap menampilkan seluruh observ dari tabel x (kiri)
    • Right Join : yg tetap menampilkan seluruh obs dari tabel y (right)
    • Full Join : yg tetap menampilkan seluruh obs dari kedua tabel.

Dampak dari join adalah, pada obs point yang tidak memiliki key pasangan pada tabel lain, ia akan tampil dengan nilai NA sebagai ‘rekannya’.

Diantara ketiga tipe outer_join yg paling sering diapakai adalah left_join, karena ini mempertahankan isi data tabel orisinal.

x %>% left_join(y, by = "key")
## # A tibble: 3 x 3
##     key val_x val_y
##   <dbl> <chr> <chr>
## 1     1 x1    y1   
## 2     2 x2    y2   
## 3     3 x3    <NA>
x %>% right_join(y, by = "key")
## # A tibble: 3 x 3
##     key val_x val_y
##   <dbl> <chr> <chr>
## 1     1 x1    y1   
## 2     2 x2    y2   
## 3     4 <NA>  y3
x %>% full_join(y, by = "key")
## # A tibble: 4 x 3
##     key val_x val_y
##   <dbl> <chr> <chr>
## 1     1 x1    y1   
## 2     2 x2    y2   
## 3     3 x3    <NA> 
## 4     4 <NA>  y3

Duplicate Key

Oke. Kembali pada pertanyaan, “bagaimana kalau dalam suatu tabel, tidak ada satupun variabel yg unik untuk dijadikan key?”

menambahkan variabel berisi row_number() bukan sellau opsi yang bijak, karena bisa jadi banyak nilai yg dipasangkan secara tidak pantas. Opsi lainnya adalah… biarkan saja.

Duplicate key atau kasus di mana tabel tidak memiliki key unik, biasanya terjadi dalam dua situasi : * Hanya salah satu tabel yg memiliki key unik. Dalam kasus ini, tabel yg memiliki key unik yang akan menjadi tabel pemiliki primary key. Sementara, tabel lainnya dianggap foreign key.

Contoh :

c <- tribble(
  ~key, ~val_c,
  1, "c1",
  2, "c2",
  2, "c3",
  1, "c4"
)

d <- tribble(
  ~key, ~val_d,
  1, "d1",
  2, "d2"
)

c
## # A tibble: 4 x 2
##     key val_c
##   <dbl> <chr>
## 1     1 c1   
## 2     2 c2   
## 3     2 c3   
## 4     1 c4
d
## # A tibble: 2 x 2
##     key val_d
##   <dbl> <chr>
## 1     1 d1   
## 2     2 d2
c %>% left_join(d, by = "key")
## # A tibble: 4 x 3
##     key val_c val_d
##   <dbl> <chr> <chr>
## 1     1 c1    d1   
## 2     2 c2    d2   
## 3     2 c3    d2   
## 4     1 c4    d1

Pada situasi pertama, variabel d sebagai pemiliki primary key akan mengikuti keberadaan foreign key pasangannya, meski dia sendiri harus terduplikasi valuenya.

  • Situasi 2 : Kedua tabel tidak memiliki primary key yg unik. Pada dasarnya sama saja. Pada kasus ini, tabel baru akan menampilkan seluruh kemungkinan kombinasi key yang cocok.
e <- tribble(
  ~key, ~val_e,
  1, "e1",
  2, "e2",
  2, "e3",
  3, "e4"
)

f <- tribble(
  ~key, ~val_f,
  1, "f1",
  2, "f2",
  2, "f3",
  3, "f4"
)
e %>% left_join(f, by = "key")
## # A tibble: 6 x 3
##     key val_e val_f
##   <dbl> <chr> <chr>
## 1     1 e1    f1   
## 2     2 e2    f2   
## 3     2 e2    f3   
## 4     2 e3    f2   
## 5     2 e3    f3   
## 6     3 e4    f4

Mendefinisikan key

Dari pembahasan sebelumnya kita tahu bahwa sepasang tabel selalu digabungkan dengan mencocokan sebuah variabel yang unik dan bernama sama sebagai key. Namun apakah harus selalu seperti itu kasusnya?

Rupanya dengan sedikit penyesuaian pada argumen ‘by =’, kita bisa dengan leluasa mengatur variabel yg dijadikan key join.

  • by = NULL jika kita menyetting ‘by = NULL’, maka fungsi join secara otomatis akan menggunakan seluruh variabel yang eksis di kedua tabel sebagai key.
flights2 %>% left_join(weather)
## Joining, by = c("year", "month", "day", "origin", "hour", "time_hour")
## # A tibble: 336,776 x 29
##       No  year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1     1  2013     1     1      517            515         2      830
##  2     2  2013     1     1      533            529         4      850
##  3     3  2013     1     1      542            540         2      923
##  4     4  2013     1     1      544            545        -1     1004
##  5     5  2013     1     1      554            600        -6      812
##  6     6  2013     1     1      554            558        -4      740
##  7     7  2013     1     1      555            600        -5      913
##  8     8  2013     1     1      557            600        -3      709
##  9     9  2013     1     1      557            600        -3      838
## 10    10  2013     1     1      558            600        -2      753
## # ... with 336,766 more rows, and 21 more variables: sched_arr_time <int>,
## #   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>, temp <dbl>, dewp <dbl>, humid <dbl>, wind_dir <dbl>,
## #   wind_speed <dbl>, wind_gust <dbl>, precip <dbl>, pressure <dbl>,
## #   visib <dbl>

Perhatikan bahwa akan muncul pesan bertuliskan :

Joining, by = c("year","month","day","origin","hour","time_hour")

Apa artinya? Maksud dari pesan ini adalah bahwa tabel hasil join di atas di hasilkan dengan menggunakan keenam variabel tersebut sebagai key nya. Alasannya? karena keenam variabel itu ada, dan sama-sama eksis di tabel flights2 dan weather. Penggabungan seperti ini (by = NULL), juga bisa disebut natural join.

  • by = c(“x”,“y”,…) Kita juga bisa menggunakan vector karakter untuk menentukan variabel mana saja yg dijadikan sebagai key. Contohnya bisa sama persis seperti pada natural join di atas; bedanya, kita menentukan sendiri mana variabel sama yg kita gunakan.

  • by = c(“a” = “b”) Pengaturan ini kita gunakan saat pada kedua tabel, terdapat dua kolom yg konten valuenya sama, atau memiliki makna data yg sama, namun nama variabelnya berbeda.

flights2 %>% left_join(airports, by = c("dest" = "faa"))
## # A tibble: 336,776 x 27
##       No  year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1     1  2013     1     1      517            515         2      830
##  2     2  2013     1     1      533            529         4      850
##  3     3  2013     1     1      542            540         2      923
##  4     4  2013     1     1      544            545        -1     1004
##  5     5  2013     1     1      554            600        -6      812
##  6     6  2013     1     1      554            558        -4      740
##  7     7  2013     1     1      555            600        -5      913
##  8     8  2013     1     1      557            600        -3      709
##  9     9  2013     1     1      557            600        -3      838
## 10    10  2013     1     1      558            600        -2      753
## # ... with 336,766 more rows, and 19 more variables: sched_arr_time <int>,
## #   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>, name <chr>, lat <dbl>, lon <dbl>, alt <dbl>, tz <dbl>,
## #   dst <chr>, tzone <chr>

Exercise

  1. Hitung rerata delay berdasarkan destinasi, lalu gabungkan dengan tabel airports untuk mengetahui distribusi spasial keterlambatan.
airports %>% semi_join(flights, by = c("faa" = "dest")) %>%
  ggplot(aes(lon, lat)) +
  borders("state") +
  geom_point() +
  coord_quickmap()

## Cara lain untuk menggabungkan.

Sebenarnya, tanpa perlu menginstall tidyverse, fungsi dasar R telah memiliki fungsi generic yg mampu melakukan penggabungan seperti join_*(). Fungsi itu adalah merge().

Filtering join

Keempat tipe join (inner, left_join, right_join, full_join) adalah bagian dari mutating join. Disebut mutate karena mempengaruhi kolom dan membuat variabel ‘baru’ pada tabel pertama (yg berasal dari tabel sumber). Lawan dari mutating join adalah filtering join, yg mempengaruhi baris tabel dan tidak akan menciptakan kolom variabel tambahan.

Ada dua jenis yg termasuk dalam filtering join, yaitu : * semi_join() :fungsi yg menampilkan seluruh baris obs yg key nya match dengan key pada tabel lain.

airports %>% semi_join(flights, by = c("faa" = "dest"))
## # A tibble: 101 x 8
##    faa   name                                lat    lon   alt    tz dst   tzone 
##    <chr> <chr>                             <dbl>  <dbl> <dbl> <dbl> <chr> <chr> 
##  1 ABQ   Albuquerque International Sunport  35.0 -107.   5355    -7 A     Ameri~
##  2 ACK   Nantucket Mem                      41.3  -70.1    48    -5 A     Ameri~
##  3 ALB   Albany Intl                        42.7  -73.8   285    -5 A     Ameri~
##  4 ANC   Ted Stevens Anchorage Intl         61.2 -150.    152    -9 A     Ameri~
##  5 ATL   Hartsfield Jackson Atlanta Intl    33.6  -84.4  1026    -5 A     Ameri~
##  6 AUS   Austin Bergstrom Intl              30.2  -97.7   542    -6 A     Ameri~
##  7 AVL   Asheville Regional Airport         35.4  -82.5  2165    -5 A     Ameri~
##  8 BDL   Bradley Intl                       41.9  -72.7   173    -5 A     Ameri~
##  9 BGR   Bangor Intl                        44.8  -68.8   192    -5 A     Ameri~
## 10 BHM   Birmingham Intl                    33.6  -86.8   644    -6 A     Ameri~
## # ... with 91 more rows
  • anti_join() : lawan dari semi_join. Fungsi ini akan menampilkan seluruh obs poin yang tidak cocok key nya pada kedua tabel.
airports %>% anti_join(flights, by = c("faa"="dest"))
## # A tibble: 1,357 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/~
##  2 06A   Moton Field Municipal Airport   32.5  -85.7   264    -6 A     America/~
##  3 06C   Schaumburg Regional             42.0  -88.1   801    -6 A     America/~
##  4 06N   Randall Airport                 41.4  -74.4   523    -5 A     America/~
##  5 09J   Jekyll Island Airport           31.1  -81.4    11    -5 A     America/~
##  6 0A9   Elizabethton Municipal Airport  36.4  -82.2  1593    -5 A     America/~
##  7 0G6   Williams County Airport         41.5  -84.5   730    -5 A     America/~
##  8 0G7   Finger Lakes Regional Airport   42.9  -76.8   492    -5 A     America/~
##  9 0P2   Shoestring Aviation Airfield    39.8  -76.6  1000    -5 U     America/~
## 10 0S9   Jefferson County Intl           48.1 -123.    108    -8 A     America/~
## # ... with 1,347 more rows

Apa beda semi_join dengan inner_join? Bedanya, inner_join akan tetap menampilkan obs poin tabel pertama, meski dia muncul berulang kali, asalkan masih tetap sama. Tapi semi_join, tidak; dia hanya akan memunculkannya sekali.

Set operation

Selain fungsi join_* dan segala tipenya, ada fungsi yg bisa digunakan untuk menggabungkan atau memfilter data dua tabel bernama ‘set operation’. Berbeda dengan join yg berpegang pada key. Seluruh operator ini akan memperhatikan seluruh nilai dari seluruh variabel dan observasi.

Ada beberapa jenis set operation :

  • interset(x,y) : berguna untuk menghasilkan output di mana hanya muncul value yg eksis pada tabel x dan tabel y

  • union(x,y) : Menampilkan tabel baru yg berupa gabungan seluruh nilai unik dari tabel x dan y

  • setdiff(x,y) : Menampilkan tabel baru yg berisi value yg hanya menjadi milik tabel x. (Tidak ada nilai yg sama dengan tabel y)