8.數(shù)據(jù)關(guān)系

1 簡(jiǎn)介

在數(shù)據(jù)分析過程中,基本上都要涉及多個(gè)數(shù)據(jù)表年叮。那當(dāng)我們對(duì)多個(gè)數(shù)據(jù)表感興趣時(shí)哈扮,此時(shí)需要將它們組合起來(lái)才能解決我們相應(yīng)的問題纬纪。我們將多個(gè)數(shù)據(jù)表統(tǒng)稱為數(shù)據(jù)間的關(guān)系

關(guān)系總是在一對(duì)表之間定義滑肉。其他所有的關(guān)系都是從這個(gè)簡(jiǎn)單的想法建立起來(lái)的:三個(gè)或更多表的關(guān)系總是每對(duì)之間關(guān)系的一個(gè)屬性包各。有時(shí)一對(duì)關(guān)系的兩個(gè)元素可以是同一個(gè)表!例如靶庙,如果您有一張人員表问畅,并且每個(gè)人都有對(duì)其父母的引用。

要處理關(guān)系數(shù)據(jù),您需要學(xué)會(huì)處理表的一些操作按声。用于處理數(shù)據(jù)間關(guān)系的操作有以下三類:

  • 變異連接膳犹,從另一個(gè)數(shù)據(jù)幀的匹配觀察結(jié)果中添加新的變量。

  • 過濾連接签则,根據(jù)一個(gè)數(shù)據(jù)幀中的觀察結(jié)果是否與另一個(gè)表中的觀察結(jié)果相匹配须床,哪個(gè)數(shù)據(jù)幀對(duì)其中的觀察結(jié)果進(jìn)行過濾。

  • 集合操作渐裂,它們把觀察結(jié)果看作是集合元素豺旬。

1.1 加載包

我們將使用dplyr中的兩個(gè)表來(lái)研究來(lái)自nycflights13的關(guān)系數(shù)據(jù)。

library(tidyverse)
library(nycflights13)

2 nycflights13包中的數(shù)據(jù)集

我們將使用 nycflights13 包來(lái)了解關(guān)系數(shù)據(jù)柒凉。nycflights13 包含與flights使用的表相關(guān)的四個(gè)小標(biāo)題:

  • airlines 可以從其縮寫代碼中查找完整的運(yùn)營(yíng)商名稱:

    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.
    #> # … with 10 more rows
    
  • airports提供有關(guān)每個(gè)機(jī)場(chǎng)的信息族阅,由機(jī)場(chǎng)代碼faa 標(biāo)識(shí):

    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_Y…
    #> 2 06A   Moton Field Municipal Airp…  32.5 -85.7   264    -6 A     America/Chica…
    #> 3 06C   Schaumburg Regional          42.0 -88.1   801    -6 A     America/Chica…
    #> 4 06N   Randall Airport              41.4 -74.4   523    -5 A     America/New_Y…
    #> 5 09J   Jekyll Island Airport        31.1 -81.4    11    -5 A     America/New_Y…
    #> 6 0A9   Elizabethton Municipal Air…  36.4 -82.2  1593    -5 A     America/New_Y…
    #> # … with 1,452 more rows
    
  • planes給出關(guān)于每個(gè)飛機(jī)的信息,由tailnum標(biāo)識(shí):

    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 mu… EMBRAER        EMB-1…       2    55    NA Turbo-…
    #> 2 N102UW   1998 Fixed wing mu… AIRBUS INDUST… A320-…       2   182    NA Turbo-…
    #> 3 N103US   1999 Fixed wing mu… AIRBUS INDUST… A320-…       2   182    NA Turbo-…
    #> 4 N104UW   1999 Fixed wing mu… AIRBUS INDUST… A320-…       2   182    NA Turbo-…
    #> 5 N10575   2002 Fixed wing mu… EMBRAER        EMB-1…       2    55    NA Turbo-…
    #> 6 N105UW   1999 Fixed wing mu… AIRBUS INDUST… A320-…       2   182    NA Turbo-…
    #> # … with 3,316 more rows
    
  • weather 提供紐約市各機(jī)場(chǎng)每小時(shí)的天氣情況:

    weather
    #> # A tibble: 26,115 x 15
    #>   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
    #> 6 EWR     2013     1     1     6  37.9  28.0  67.2      240      11.5         NA
    #> # … with 26,109 more rows, and 4 more variables: precip <dbl>, pressure <dbl>,
    #> #   visib <dbl>, time_hour <dttm>
    

顯示不同表之間關(guān)系的一種方法是使用繪圖:

image

理解這樣的圖的關(guān)鍵是記住每個(gè)關(guān)系總是與一對(duì)表有關(guān)膝捞。你不需要了解整個(gè)事情坦刀;您只需要了解您感興趣的表之間的關(guān)系鏈。

對(duì)于 nycflights13:

  • flights連接到planes蔬咬,通過單個(gè)變量tailnum鲤遥。

  • flights連接到airlines,通過carrier變量林艘。

  • flights連接到airports盖奈,通過兩個(gè)origindest變量。

  • flights連接到weather的變量有origin(位置)和 year狐援、month钢坦、dayhour(時(shí)間)。

3 通過key連接

用于連接每對(duì)表的變量稱為啥酱。對(duì)于觀察的變量(或變量集)鍵是唯一標(biāo)識(shí)符爹凹。在簡(jiǎn)單的情況下,單個(gè)變量足以識(shí)別出觀察值镶殷。例如逛万,每個(gè)飛機(jī)都有唯一標(biāo)識(shí)tailnum。在其他情況下批钠,可能需要多個(gè)變量宇植。例如,在確定的觀察weather埋心,你需要五個(gè)變量:year指郁,monthday拷呆,hour闲坎,和origin疫粥。

有兩種類型的鍵:

  • 主鍵唯一地標(biāo)識(shí)一個(gè)觀察結(jié)果。例如腰懂,planes$tailnum是主鍵梗逮,因?yàn)樗ㄒ粯?biāo)識(shí)了planes表中的每個(gè)飛機(jī)。

  • 外鍵唯一標(biāo)識(shí)另一個(gè)表的觀察結(jié)果绣溜。例如慷彤,flights$tailnum是外鍵,因?yàn)樗霈F(xiàn)在 flights表中怖喻,它將每個(gè)航班與飛機(jī)一對(duì)一匹配底哗。

變量既可以是主鍵也可以是外鍵锚沸。例如跋选,originweather表中是主鍵的一部分,在airports表中是外鍵哗蜈。

一旦確定了表中的主鍵前标,最好驗(yàn)證它們唯一對(duì)應(yīng)每個(gè)觀察結(jié)果。一種方法是使用count()查找住建數(shù)量n大于 1 的條目:

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

有時(shí)一個(gè)表沒有明確的主鍵:每一行都是一個(gè)觀察值距潘,但沒有任何變量組合能夠單獨(dú)的標(biāo)識(shí)炼列。例如,flights表中的主鍵是什么绽昼?您可能認(rèn)為它是日期加上航班號(hào)或尾號(hào),但它們都不是唯一的:

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
#> # … with 29,762 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
#> # … with 64,922 more rows

在開始處理這些數(shù)據(jù)時(shí)须蜗,我們可能會(huì)認(rèn)為每個(gè)航班號(hào)每天只使用一次硅确,然而事實(shí)并非如此!如果表缺乏一個(gè)主鍵明肮,它有時(shí)根據(jù)需要增加一個(gè)mutate()row_number()菱农。如果您已經(jīng)進(jìn)行了一些過濾并想要重新檢查原始數(shù)據(jù),則可以更輕松地匹配觀察結(jié)果柿估。這稱為代理鍵循未。

另一個(gè)表中的主鍵和相應(yīng)的外鍵形成關(guān)系。關(guān)系通常是一對(duì)多的秫舌。例如的妖,每個(gè)航班都有一架飛機(jī),但每架飛機(jī)都有許多航班足陨。在其他數(shù)據(jù)中嫂粟,您偶爾會(huì)看到一對(duì)一的關(guān)系。您可以將其視為一對(duì)多的特殊情況墨缘。您可以使用多對(duì)一關(guān)系和一對(duì)多關(guān)系來(lái)建模多對(duì)多關(guān)系星虹。例如零抬,在此數(shù)據(jù)中,航空公司和機(jī)場(chǎng)之間存在多對(duì)多關(guān)系:每家航空公司飛往多個(gè)機(jī)場(chǎng)宽涌;每個(gè)機(jī)場(chǎng)都有許多航空公司平夜。

4 變異連接

我們組合一對(duì)表的第一個(gè)工具是mutating join。變異連接允許您組合來(lái)自兩個(gè)表的變量卸亮。它首先通過鍵匹配觀察值忽妒,然后將變量從一個(gè)表復(fù)制到另一個(gè)表。

如同mutate()嫡良,連接函數(shù)在右邊添加變量锰扶,所以如果你已經(jīng)有很多變量,新的變量不會(huì)被打印出來(lái)寝受。

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     
#> # … with 336,770 more rows

假設(shè)您想將完整的航空公司名稱添加到flights2數(shù)據(jù)中坷牛。您可以將airlinesflights2通過left_join()進(jìn)行組合:

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. 
#> # … with 336,770 more rows

將airlines的航空公司名稱name加入到flight2的結(jié)果。將這種類型的連接稱為變異連接很澄。在這種情況下京闰,也可以使用mutate()和 R 的base包達(dá)到同樣的效果:

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. 
#> # … with 336,770 more rows

但是當(dāng)您需要匹配多個(gè)變量時(shí),這就非常的麻煩甩苛,而且需要仔細(xì)理解才能弄清楚整體意圖蹂楣,達(dá)到期望的結(jié)果。

下面將詳細(xì)解釋變異連接的原理讯蒲。首先學(xué)習(xí)一種有用的連接可視化表示痊土。然后我們將使用它來(lái)解釋四個(gè)變異連接函數(shù):內(nèi)連接和三個(gè)外連接。
在處理真實(shí)數(shù)據(jù)時(shí)墨林,鍵并不總是唯一標(biāo)識(shí)觀察結(jié)果赁酝,因此接下來(lái)我們將討論沒有唯一匹配時(shí)會(huì)發(fā)生什么。最后旭等,您將學(xué)習(xí)如何告訴 dplyr 哪些變量是給定連接的鍵酌呆。

4.1 理解連接原理

為了幫助您了解連接的工作原理,通過圖形展示:

image
x <- tribble(
  ~key, ~val_x,
     1, "x1",
     2, "x2",
     3, "x3"
)
y <- tribble(
  ~key, ~val_y,
     1, "y1",
     2, "y2",
     4, "y3"
)

彩色列代表“key”變量:它們用于匹配表之間的行搔耕∠对灰色列表示對(duì)應(yīng)的“value”列。在這些示例中弃榨,通過展示單個(gè)鍵變量菩收,但該想法以一種直接的方式概括為多個(gè)鍵和多個(gè)值。
連接是將x中的每一行連接到y中的0行鲸睛、1行或多行的一種方法坛梁。下圖顯示了作為一對(duì)直線的交點(diǎn)的每個(gè)潛在匹配。

image

(如果您仔細(xì)觀察腊凶,您可能會(huì)注意到我們已經(jīng)切換了x中的鍵和值列的順序划咐。這是為了強(qiáng)調(diào)連接基于進(jìn)行匹配拴念;該只是在過程中被攜帶。)

在實(shí)際的連接中褐缠,匹配將用點(diǎn)表示政鼠。點(diǎn)的數(shù)量=匹配的數(shù)量=輸出中的行數(shù)。


image

4.2 內(nèi)連接

最簡(jiǎn)單的連接類型是內(nèi)連接队魏。只要它們的鍵相等公般,內(nèi)連接就會(huì)匹配觀察值對(duì):

image

(準(zhǔn)確地說,這是一個(gè)內(nèi)部等值聯(lián)接胡桨,因?yàn)殒I是使用=運(yùn)算符匹配的官帘。由于大多數(shù)連接是等值聯(lián)接,我們通常不采用該連接方法昧谊。)

內(nèi)連接的輸出是一個(gè)包含鍵刽虹、x 值和 y 值的新數(shù)據(jù)框。我們用by來(lái)告訴 dplyr 哪個(gè)變量是鍵:

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

內(nèi)連接最重要的特性是結(jié)果中只包含匹配的行呢诬。這意味著通常內(nèi)部連接通常不適合用于分析涌哲,因?yàn)樗鼤?huì)丟失很多的觀察值。

4.3 外連接

內(nèi)連接保留出現(xiàn)在兩個(gè)表中的觀察結(jié)果尚镰。外連接保存至少出現(xiàn)在其中一個(gè)表中的觀察結(jié)果阀圾。外連接有三種類型:

  • 左連接:保留x所有觀察值。
  • 右連接:保留y所有觀測(cè)值狗唉。
  • 全連接:保留xy所有觀測(cè)值初烘。

這些連接通過向每個(gè)表添加額外的“虛擬”觀察值。這個(gè)觀察值有一個(gè)總是匹配的鍵(如果沒有其他鍵匹配)分俯,則填充NA肾筐。

下面通過圖形來(lái)解釋具體原理:

image

最常用的連接是左連接:每當(dāng)您從另一個(gè)表中查找附加數(shù)據(jù)時(shí)都可以使用它,因?yàn)榧词箾]有匹配澳迫,它也會(huì)保留原始觀察結(jié)果局齿。左連接應(yīng)該是默認(rèn)連接方式剧劝。

描述不同連接類型的另一種方法是使用維恩圖:

image

但是維恩圖有個(gè)限制:維恩圖無(wú)法顯示當(dāng)鍵不能唯一標(biāo)識(shí)觀察時(shí)會(huì)發(fā)生什么橄登。

4.4 重復(fù)的鍵

前面我們遇到的數(shù)據(jù)中鍵都是唯一的,但是我們?cè)谔幚頂?shù)據(jù)時(shí)往往會(huì)碰到鍵不唯一讥此,有下面兩種情況:

  1. 一張數(shù)據(jù)表有重復(fù)的鍵拢锹。這在您想要添加附加信息時(shí)很有用,因?yàn)橥ǔ4嬖谝粚?duì)多關(guān)系萄喳。

    image

注意卒稳,我將鍵列放在了輸出中稍微不同的位置。這反映了該鍵在y中是主鍵他巨,在x中是外鍵充坑。

```
x <- tribble(
  ~key, ~val_x,
     1, "x1",
     2, "x2",
     2, "x3",
     1, "x4"
)
y <- tribble(
  ~key, ~val_y,
     1, "y1",
     2, "y2"
)
left_join(x, 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     2 x3    y2   
#> 4     1 x4    y1
```
  1. 兩個(gè)表都有重復(fù)的鍵减江。這通常是一個(gè)錯(cuò)誤,因?yàn)樵谶@兩個(gè)表中捻爷,鍵都不能唯一地標(biāo)識(shí)觀察辈灼。當(dāng)你加入重復(fù)的鍵時(shí),將使用笛卡爾積來(lái)展示:

    image
    x <- tribble(
      ~key, ~val_x,
         1, "x1",
         2, "x2",
         2, "x3",
         3, "x4"
    )
    y <- tribble(
      ~key, ~val_y,
         1, "y1",
         2, "y2",
         2, "y3",
         3, "y4"
    )
    left_join(x, y, by = "key")
    #> # A tibble: 6 x 3
    #>     key val_x val_y
    #>   <dbl> <chr> <chr>
    #> 1     1 x1    y1   
    #> 2     2 x2    y2   
    #> 3     2 x2    y3   
    #> 4     2 x3    y2   
    #> 5     2 x3    y3   
    #> 6     3 x4    y4
    

4.5 定義關(guān)鍵列

到目前為止也榄,這對(duì)表總是由一個(gè)變量連接巡莹,并且該變量在兩個(gè)表中具有相同的名稱。通過by = "key"來(lái)約定甜紫。你可以使用by指定其他鍵值來(lái)連接表:

  • 默認(rèn)情況下by = NULL將使用出現(xiàn)在兩個(gè)表中的所有變量降宅,即所謂的自然連接。例如囚霸,航班和天氣表格匹配他們共同的變量:year腰根,monthday邮辽,hourorigin唠雕。

    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
    #> # … with 336,770 more rows, and 7 more variables: wind_dir <dbl>,
    #> #   wind_speed <dbl>, wind_gust <dbl>, precip <dbl>, pressure <dbl>,
    #> #   visib <dbl>, time_hour <dttm>
    
  • 通過字符向量,by = "x"吨述。例如岩睁,航班和飛機(jī)有年份變量,但它們有不同的含義揣云,所以我們只想通過tailnum連接捕儒。

    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…
    #> # … with 336,770 more rows, and 6 more variables: manufacturer <chr>,
    #> #   model <chr>, engines <int>, seats <int>, speed <int>, engine <chr>
    

    請(qǐng)注意,year變量(出現(xiàn)在兩個(gè)輸入數(shù)據(jù)框中邓夕,但不限于相等)在輸出中通過后綴消除歧義刘莹。

  • 通過字符向量連接:by = c("a" = "b"). 這將匹配表x中變量a和表y中的變量b

    例如焚刚,如果我們要繪制地圖点弯,我們需要將航班數(shù)據(jù)與每個(gè)機(jī)場(chǎng)位置 (latlon)的機(jī)場(chǎng)數(shù)據(jù)結(jié)合起來(lái)。每個(gè)航班都有一個(gè)出發(fā)地和目的地機(jī)場(chǎng)矿咕,因此我們需要指定要加入哪個(gè)機(jī)場(chǎng):

    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
    #> # … with 336,770 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
    #> # … with 336,770 more rows, and 3 more variables: tz <dbl>, dst <chr>,
    #> #   tzone <chr>
    

4.7 其他實(shí)現(xiàn)方式

base::merge() 可以執(zhí)行所有四種變異連接類型:

dplyr包 base::merge()
inner_join(x, y) merge(x, y)
left_join(x, y) merge(x, y, all.x = TRUE)
right_join(x, y) merge(x, y, all.y = TRUE),
full_join(x, y) merge(x, y, all.x = TRUE, all.y = TRUE)

使用dplyr 包優(yōu)點(diǎn)是它們更清楚地傳達(dá)出代碼的意圖抢肛,dplyr 的連接速度要快得多,而且不會(huì)弄亂行的順序碳柱。

dplyr 是根據(jù)SQL 語(yǔ)法來(lái)編譯的:

dplyr SQL
inner_join(x, y, by = "z") SELECT * FROM x INNER JOIN y USING (z)
left_join(x, y, by = "z") SELECT * FROM x LEFT OUTER JOIN y USING (z)
right_join(x, y, by = "z") SELECT * FROM x RIGHT OUTER JOIN y USING (z)
full_join(x, y, by = "z") SELECT * FROM x FULL OUTER JOIN y USING (z)

請(qǐng)注意捡絮,“INNER”和“OUTER”是可選的,經(jīng)常被省略莲镣。

5 連接過濾

過濾連接與變異連接通過相同的方式匹配觀察值福稳,有兩種類型:

  • semi_join(x, y)將所有與y匹配的觀測(cè)值保存在x中。
  • anti_join(x, y) 去掉x中與y匹配的所有觀察值瑞侮。

semi_join對(duì)于將過濾后的匯總表與原始行進(jìn)行匹配非常有用的圆。如flights數(shù)據(jù)中鼓拧,你需要找到了十大最受歡迎的目的地:

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
#> # … with 4 more rows

現(xiàn)在,您要查找飛往這些目的地中的每個(gè)航班越妈。通過filter過濾:

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
#> # … with 141,139 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>

如果有多個(gè)變量時(shí)毁枯,這種方法就很復(fù)雜了。例如叮称,假設(shè)你找到了平均延遲最高的10天种玛。如何構(gòu)造使用年、月瓤檐、日將其匹配回航班的過濾器語(yǔ)句?

相反赂韵,您可以使用semi_join,它像變異連接一樣連接兩個(gè)表挠蛉,但不是添加新列祭示,而是只保留其中x匹配的行y

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
#> # … with 141,139 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>

從圖形上看,semi_join()如下所示:

image

只有匹配的存在行才是重要的谴古;匹配哪個(gè)觀察并不重要质涛。這意味著過濾連接永遠(yuǎn)不會(huì)像變異連接那樣重復(fù)行:

image

semi_join()的反向操作是 anti_join()anti_join()保留沒有匹配的行:

image

anti_join()對(duì)于解決不匹配的連接很有用掰担。例如汇陆,在連接flightsplanes,您可能想知道在planes中沒有匹配到flights項(xiàng):

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
#> # … with 716 more rows

6 集合操作

二個(gè)數(shù)據(jù)表的最后一種操作類型是集合操作带饱。一般來(lái)說毡代,我很少使用這些方法,但是當(dāng)您想要將單個(gè)復(fù)雜的過濾器分解成更簡(jiǎn)單的部分時(shí)勺疼,它們偶爾會(huì)很有用教寂。所有這些操作都與一個(gè)完整的行一起工作,比較每個(gè)變量的值执庐。它們期望xy輸入具有相同的變量酪耕,并將觀察結(jié)果視為集合:

  • intersect(x, y): 只返回xy中都有的觀察值。
  • union(x, y): 返回xy中合并的觀察結(jié)果轨淌。
  • setdiff(x, y): 返回觀察結(jié)果在x中迂烁,但不在y中。

下面通過簡(jiǎn)單的數(shù)據(jù)來(lái)說明:

df1 <- tribble(
  ~x, ~y,
   1,  1,
   2,  1
)
df2 <- tribble(
  ~x, ~y,
   1,  1,
   1,  2
)

四種可能結(jié)果:

intersect(df1, df2)
#> # A tibble: 1 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     1

# Note that we get 3 rows, not 4
union(df1, df2)
#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     1
#> 2     2     1
#> 3     1     2

setdiff(df1, df2)
#> # A tibble: 1 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     2     1

setdiff(df2, df1)
#> # A tibble: 1 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     2
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末猿诸,一起剝皮案震驚了整個(gè)濱河市婚被,隨后出現(xiàn)的幾起案子狡忙,更是在濱河造成了極大的恐慌梳虽,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灾茁,死亡現(xiàn)場(chǎng)離奇詭異窜觉,居然都是意外死亡谷炸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門禀挫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)旬陡,“玉大人,你說我怎么就攤上這事语婴∶杳希” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵砰左,是天一觀的道長(zhǎng)匿醒。 經(jīng)常有香客問我,道長(zhǎng)缠导,這世上最難降的妖魔是什么廉羔? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮僻造,結(jié)果婚禮上憋他,老公的妹妹穿的比我還像新娘。我一直安慰自己髓削,他們只是感情好竹挡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著立膛,像睡著了一般此迅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旧巾,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天耸序,我揣著相機(jī)與錄音,去河邊找鬼鲁猩。 笑死坎怪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的廓握。 我是一名探鬼主播搅窿,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼隙券!你這毒婦竟也來(lái)了男应?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤娱仔,失蹤者是張志新(化名)和其女友劉穎沐飘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耐朴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年借卧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筛峭。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铐刘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出影晓,到底是詐尸還是另有隱情镰吵,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布挂签,位于F島的核電站捡遍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏竹握。R本人自食惡果不足惜画株,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望啦辐。 院中可真熱鬧谓传,春花似錦、人聲如沸芹关。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)侥衬。三九已至诗祸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轴总,已是汗流浹背直颅。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怀樟,地道東北人功偿。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像往堡,于是被迫代替她去往敵國(guó)和親械荷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容