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)系的一種方法是使用繪圖:
理解這樣的圖的關(guān)鍵是記住每個(gè)關(guān)系總是與一對(duì)表有關(guān)膝捞。你不需要了解整個(gè)事情坦刀;您只需要了解您感興趣的表之間的關(guān)系鏈。
對(duì)于 nycflights13:
flights
連接到planes
蔬咬,通過單個(gè)變量tailnum
鲤遥。flights
連接到airlines
,通過carrier
變量林艘。flights
連接到airports
盖奈,通過兩個(gè)origin
和dest
變量。flights
連接到weather
的變量有origin
(位置)和year
狐援、month
钢坦、day
和hour
(時(shí)間)。
3 通過key連接
用于連接每對(duì)表的變量稱為鍵啥酱。對(duì)于觀察的變量(或變量集)鍵是唯一標(biāo)識(shí)符爹凹。在簡(jiǎn)單的情況下,單個(gè)變量足以識(shí)別出觀察值镶殷。例如逛万,每個(gè)飛機(jī)都有唯一標(biāo)識(shí)tailnum
。在其他情況下批钠,可能需要多個(gè)變量宇植。例如,在確定的觀察weather
埋心,你需要五個(gè)變量:year
指郁,month
,day
拷呆,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ì)一匹配底哗。
變量既可以是主鍵,也可以是外鍵锚沸。例如跋选,origin
在weather
表中是主鍵的一部分,在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ù)中坷牛。您可以將airlines
和flights2
通過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 理解連接原理
為了幫助您了解連接的工作原理,通過圖形展示:
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è)潛在匹配。
(如果您仔細(xì)觀察腊凶,您可能會(huì)注意到我們已經(jīng)切換了x
中的鍵和值列的順序划咐。這是為了強(qiáng)調(diào)連接基于鍵進(jìn)行匹配拴念;該值只是在過程中被攜帶。)
在實(shí)際的連接中褐缠,匹配將用點(diǎn)表示政鼠。點(diǎn)的數(shù)量=匹配的數(shù)量=輸出中的行數(shù)。
4.2 內(nèi)連接
最簡(jiǎn)單的連接類型是內(nèi)連接队魏。只要它們的鍵相等公般,內(nèi)連接就會(huì)匹配觀察值對(duì):
(準(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è)值狗唉。 -
全連接:保留
x
和y
所有觀測(cè)值初烘。
這些連接通過向每個(gè)表添加額外的“虛擬”觀察值。這個(gè)觀察值有一個(gè)總是匹配的鍵(如果沒有其他鍵匹配)分俯,則填充NA
肾筐。
下面通過圖形來(lái)解釋具體原理:
最常用的連接是左連接:每當(dāng)您從另一個(gè)表中查找附加數(shù)據(jù)時(shí)都可以使用它,因?yàn)榧词箾]有匹配澳迫,它也會(huì)保留原始觀察結(jié)果局齿。左連接應(yīng)該是默認(rèn)連接方式剧劝。
描述不同連接類型的另一種方法是使用維恩圖:
但是維恩圖有個(gè)限制:維恩圖無(wú)法顯示當(dāng)鍵不能唯一標(biāo)識(shí)觀察時(shí)會(huì)發(fā)生什么橄登。
4.4 重復(fù)的鍵
前面我們遇到的數(shù)據(jù)中鍵都是唯一的,但是我們?cè)谔幚頂?shù)據(jù)時(shí)往往會(huì)碰到鍵不唯一讥此,有下面兩種情況:
-
一張數(shù)據(jù)表有重復(fù)的鍵拢锹。這在您想要添加附加信息時(shí)很有用,因?yàn)橥ǔ4嬖谝粚?duì)多關(guān)系萄喳。
注意卒稳,我將鍵列放在了輸出中稍微不同的位置。這反映了該鍵在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
```
-
兩個(gè)表都有重復(fù)的鍵减江。這通常是一個(gè)錯(cuò)誤,因?yàn)樵谶@兩個(gè)表中捻爷,鍵都不能唯一地標(biāo)識(shí)觀察辈灼。當(dāng)你加入重復(fù)的鍵時(shí),將使用笛卡爾積來(lái)展示:
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
腰根,month
,day
邮辽,hour
和origin
唠雕。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)位置 (
lat
和lon
)的機(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()
如下所示:
只有匹配的存在行才是重要的谴古;匹配哪個(gè)觀察并不重要质涛。這意味著過濾連接永遠(yuǎn)不會(huì)像變異連接那樣重復(fù)行:
semi_join()
的反向操作是 anti_join()
。 anti_join()
保留沒有匹配的行:
anti_join()
對(duì)于解決不匹配的連接很有用掰担。例如汇陆,在連接flights
和planes
,您可能想知道在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è)變量的值执庐。它們期望x
和y
輸入具有相同的變量酪耕,并將觀察結(jié)果視為集合:
-
intersect(x, y)
: 只返回x
和y
中都有的觀察值。 -
union(x, y)
: 返回x
和y
中合并的觀察結(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