這邊的資料合併,指的是利用兩個資料表當中具相同名稱,且內容可以互相對應的欄位,來合併兩個資料表。
舉個例子,
我們手上有兩個表,其中一個是 survey,包含外出調查時記錄到的鳥種英文俗名 (Common Name) 以及調查到的隻數 (Count)。
Common Name | Count |
---|---|
Kentish Plover | 150 |
Common Teal | 300 |
Little Egret | 20 |
Common Teal | 200 |
另外一個表是 waterbird,包含水鳥的分類資訊,英文俗名 (Common Name) 以及科名 (Family)。
Common Name | Family |
---|---|
Common Teal | Anatidae |
Little Egret | Ardeidae |
Kentish Plover | Charadriidae |
這邊說的資料合併就是像下面這樣,依據兩個表都有的 Common Name,把第二個表 (waterbird) 的 Family 資訊加到第一個表 (survey) 相對應的物種上。在做資料合併時,提供額外資訊的表 不可以 有重複項目在內,像這邊的例子,在 waterbird 這個表格中 Common Name 的欄位內就不可有重複的物種。
Common Name | Count | Family |
---|---|---|
Kentish Plover | 150 | Charadriidae |
Common Teal | 300 | Anatidae |
Little Egret | 20 | Ardeidae |
Common Teal | 200 | Anatidae |
Excel 內,可以透過 VLOOKUP 來做,那在 R 裡面也有許多的 package 提供相同的功能。
以下就來介紹幾個在資料合併中常見的 package~
位在 R 內建的 base 裡面,在使用時有幾個參數的設定要注意。
分別放兩個要合併表格
用來指定兩個表格中相同的欄位名稱,也就是合併的依據,如果沒有特別指定,merge 也會自己去找相同的欄位來合併資料。另外如果兩個表格中要用來合併的欄位名稱不同的時候,可以分別用by.x = “欄位A”以及by.y = “欄位B”,來告訴 merge 合併的依據分別是表格 x 的 A 欄位以及表格 y 的 B 欄位。指定欄位的時候記得都要用“”來包住欄位名稱。
這三個分別用來指定回傳資料的內容,當 all = TRUE 的時候,R 會回傳兩個表格中所有的資料,包含沒有互相對應到的內容。反之如果 all = FALSE,就只會回傳兩個表格中都有對應到的內容。而 all.x = TRUE 指的則是保留所有表格 x 的值,不管有沒有對應到 y 表格。
先創造範例會用到的兩個 data.frame,survey 跟 waterbird。
library(data.table)
survey <-
data.table(`Common Name` =
c("Kentish Plover", "Common Teal", "Little Egret",
"Common Teal", "Light-vented Bulbul"),
`Count` =
c(150, 300, 20, 200, 5))
survey
## Common Name Count
## 1: Kentish Plover 150
## 2: Common Teal 300
## 3: Little Egret 20
## 4: Common Teal 200
## 5: Light-vented Bulbul 5
waterbird <-
data.table(`Common Name` =
c("Kentish Plover", "Common Teal",
"Little Egret", "Pacific Golden Plover"),
Family =
c("Charadriidae", "Anatidae",
"Ardeidae", "Charadriidae"))
waterbird
## Common Name Family
## 1: Kentish Plover Charadriidae
## 2: Common Teal Anatidae
## 3: Little Egret Ardeidae
## 4: Pacific Golden Plover Charadriidae
merge(survey, waterbird)
## Common Name Count Family
## 1: Common Teal 300 Anatidae
## 2: Common Teal 200 Anatidae
## 3: Kentish Plover 150 Charadriidae
## 4: Little Egret 20 Ardeidae
在merge()當中,all 的預設為 FALSE,所以survey 裡面的 Light-vented Bulbul,跟 waterbird裡面的 Pacific Golden Plover 因為在另一個表單中沒有,所以不會出現在合併的表格中。
merge(survey, waterbird, all = TRUE)
## Common Name Count Family
## 1: Common Teal 300 Anatidae
## 2: Common Teal 200 Anatidae
## 3: Kentish Plover 150 Charadriidae
## 4: Light-vented Bulbul 5 NA
## 5: Little Egret 20 Ardeidae
## 6: Pacific Golden Plover NA Charadriidae
如果改成 all = TRUE 的話,就會回傳所有的資料,並且沒有對應到的部分會是 NA。
merge(survey, waterbird, all.x = TRUE)
## Common Name Count Family
## 1: Common Teal 300 Anatidae
## 2: Common Teal 200 Anatidae
## 3: Kentish Plover 150 Charadriidae
## 4: Light-vented Bulbul 5 NA
## 5: Little Egret 20 Ardeidae
如果寫成 all.x = TRUE,則只會回傳 survey 當中,在 waterbird 內有資料的物種,在 waterbird 沒有對應到的 survey 物種資料不會保留下來。
在package dplyr也有一系列跟資料合併有關的函數,不過跟merge不同的是,在dplyr中是直接用不同的函數來指定回傳的內容。
資料合併後,回傳 df1 與 df2 在對應欄位中,互相有對應到的內容,等同於 merge(df1, df2, all = FALSE)
資料合併後,回傳在左邊 df1 的對應欄位中有的內容,不管有沒有對應到 df2,等同於 merge(df1, df2, all.x = TRUE)
。
資料合併後,回傳在右邊 df2 的對應欄位中有的內容,不管有沒有對應到 df1,等同於 merge(df1, df2, all.y = TRUE)
。
回傳 df1 與 df2 合併後的所有內容,等同於 merge(df1, df2, all = TRUE)
。
只回傳 df1 當中與 df2 在對應欄位中有對應到的 df1 內容。
回傳 df1 當中 沒有 對應到 df2 對應欄位的內容。
semi_join 跟 anti_join 在資料合併時相對比較少使用,但我覺得在除錯或是檢查資料的時候還蠻好用的,可以很快速地幫你找到沒有對應到的資料。
library(dplyr)
這邊只看 anti_join 跟 semi_join,其他跟 merge 功能重複的就不列入示範了,另外 by 參數的設定跟 merge 一樣,用來指定欄位名稱,若沒有指定的話,R 也會自己去找兩個資料中相同名稱的欄位。
anti_join(survey, waterbird)
## Joining, by = "Common Name"
## Common Name Count
## 1 Light-vented Bulbul 5
回傳有在 survey 的物種名稱欄位中,但沒有在 waterbird 裡面的 survey 資料。
semi_join(survey, waterbird)
## Joining, by = "Common Name"
## Common Name Count
## 1 Kentish Plover 150
## 2 Common Teal 300
## 3 Little Egret 20
## 4 Common Teal 200
回傳有在 waterbird 物種名稱欄位中的 survey 資料,沒有合併上 waterbird 的欄位。
在 data.table 中,也可以做資料合併,不過功能上沒有 dplyr 的 join 系列來的多元,只有 inner_join 與 left_join / right_join。在data.table中,放在 [ ] 內的 DT2 為主要的資料,用nomatch =
來告訴 R 在 DT1 的資料中,沒有對應到 DT2 的部分要不要保留下來,另外是在這邊指定欄位的 on =
不能省略。
waterbird[survey, on = "Common Name"]
## Common Name Family Count
## 1: Kentish Plover Charadriidae 150
## 2: Common Teal Anatidae 300
## 3: Little Egret Ardeidae 20
## 4: Common Teal Anatidae 200
## 5: Light-vented Bulbul NA 5
沒有在 waterbird 裡面的物種,Family 會是 NA
survey[waterbird, on = "Common Name", nomatch = 0]
## Common Name Count Family
## 1: Kentish Plover 150 Charadriidae
## 2: Common Teal 300 Anatidae
## 3: Common Teal 200 Anatidae
## 4: Little Egret 20 Ardeidae
用 nomatch = 0
表示兩個表當中沒有對應到的內容不會回傳,等同於 inner_join()
另外還有一種資料合併,不是利用相同的欄位名稱做對應,而是直接接上其他資料的欄或著是列
假設今天除了 survey 之外,還有一份 survey.2 的調查資料。
survey.2 <-
data.table(`Common Name` =
c("Black-faced Spoonbill", "Black-headed Gull", "Kentish Plover"),
`Count` =
c(20, 500, 100))
survey.2
## Common Name Count
## 1: Black-faced Spoonbill 20
## 2: Black-headed Gull 500
## 3: Kentish Plover 100
因為兩個資料具有相同的欄位名稱,所以就可以用 rbind()
來合併兩個資料。合併完後 survey.2 會接在 survey 的下方。
rbind(survey, survey.2)
## Common Name Count
## 1: Kentish Plover 150
## 2: Common Teal 300
## 3: Little Egret 20
## 4: Common Teal 200
## 5: Light-vented Bulbul 5
## 6: Black-faced Spoonbill 20
## 7: Black-headed Gull 500
## 8: Kentish Plover 100
在 waterbird 資料中,原本只有俗名跟科名,當我們手上有屬名 Genus 的資料,如果確定每一筆資料的順序跟 waterbird 是一樣的時候,就可以用 cbind 來合併。合併完後 waterbird 會接在 Genus 的左側。
Genus <- data.table(Genus = c("Charadrius", "Anas", "Egretta", "Pluvialis"))
cbind(waterbird, Genus)
## Common Name Family Genus
## 1: Kentish Plover Charadriidae Charadrius
## 2: Common Teal Anatidae Anas
## 3: Little Egret Ardeidae Egretta
## 4: Pacific Golden Plover Charadriidae Pluvialis
我沒有比較過這些函數之間的效率誰高誰低,不過因為在處理大量資料的時候,都是用data.table,所以資料合併上也習慣用data.table的方法來寫。不過抓錯的話 dplyr::anti_join()
不錯用~ 另外如果覺得資料對應上可能會需要某種程度的 工人智慧,我也是會跳回excel用vlookup來處理的XD“。