left join 不重复_R语言ETL工程:连接(join)
作者:黃天元,復旦大學博士在讀,目前研究涉及文本挖掘、社交網絡分析和機器學習等。希望與大家分享學習經驗,推廣并加深R語言在業界的應用。
郵箱:huang.tian-yuan@qq.com
本章將會介紹如何在R中完成數據表的連接操作。首先要明確一個問題:為什么要進行連接?本質上來說,連接就是按照一定的對應規則,把兩個表格合并為一個表格的操作。舉個例子:比如我們一張表格中有樂隊的歌手名字和他們所屬的樂隊,另一張表格有歌手的名字和他們擅長的樂器類型。因為兩張表格都含有歌手的名字,而歌手的名字也是唯一的(在數據庫理論框架中,這個屬性被稱為主鍵),即不存在一張表格會重復出現同一個歌手的名字。這個時候,我們就希望把兩張表格合并起來,做一張包含歌手名字、所屬樂隊、擅長樂器的大表格。通過連接,我們能夠把眾多表格的數據合并起來,從而讓孤立的數據能夠聯系在一起。
本章會采用較為簡單的數據集進行實現,下面我們會參考dplyr的幫助文檔舉例,前期準備如下:
1library(tidyverse) 2band_members 3 4##?#?A?tibble:?3?x?2 5##?name?band? 6##??? 7##?1?Mick?Stones? 8##?2?John?Beatles 9##?3?Paul?Beatles1011band_instruments1213##?#?A?tibble:?3?x?214##?name?plays?15##???16##?1?John?guitar17##?2?Paul?bass?18##?3?Keith?guitar1920band_instruments22122##?#?A?tibble:?3?x?223##?artist?plays?24##???25##?1?John?guitar26##?2?Paul?bass?27##?3?Keith?guitar
觀察表格,我們可以知道,band_members包含了歌手名稱和樂隊信息,band_instruments包含歌手名稱和樂器信息,band_instruments2與band_instrument包含的信息一樣,但是歌手名稱的列名稱由name變化為artist。
基本概念連接分為很多種,包括內連接、全鏈接、左連接、右連接等。我們先介紹一些基礎的邏輯,先看下面這張圖:
下面我們逐個講解這些連接的概念。 首先我們來講內連接,又叫做自然連接。還是歌手、樂隊、樂器的例子,比如我們的A表格中有歌手名稱和樂隊的信息,B表格中有歌手名稱和擅長樂器的信息。另外,我們發現兩張表格中,A表格包含的歌手信息和B表格不同,有的歌手只有A表格有,B表格就沒有;有的歌手只有B表格有,但是A表格沒有。但是我們還是希望把A表格和B表格連接起來,形成一個大表格C。采用內連接的話,就會把A表格和B表格都有的歌手提取出來(也就是取了一個交集),然后對兩個表格的列進行連接。
下面介紹左連接和右連接。如果是A表格左連接B表格的話,那么就是A表格的歌手肯定全部保留,如果在A里面有的歌手,在B中找不到,那么就需要填充缺失值,一切以A表格為主。理解了左連接,右連接就非常簡單了,它其實就是左連接的逆運算,也就是說A右連接B,實際就是B左連接A。就是這么簡單。 最后我們講一下全連接。全連接就是A表格B表格的歌手我們統統都保留,但是如果A表格有的歌手B表格沒有,那么在B表格的列中就需要填充缺失值;同理,如果B表格的歌手A沒有,那么A表格帶來的列也需要填充缺失值。
如果還是不理解,可以看一下下面這一張圖片。
內
連接
1band_members?%>% 2inner_join(band_instruments) 3 4##?Joining,?by?=?"name" 5 6##?#?A?tibble:?2?x?3 7##?name?band?plays? 8##???? 9##?1?John?Beatles?guitar10##?2?Paul?Beatles?bass
SQL代碼如下:
1?SELECT?`TBL_LEFT`.`name`?AS?`name`,?`TBL_LEFT`.`band`?AS?`band`,?`TBL_RIGHT`.`plays`?AS?`plays`2FROM?`band_members`?AS?`TBL_LEFT`3INNER?JOIN?`band_instruments`?AS?`TBL_RIGHT`4ON?(`TBL_LEFT`.`name`?=?`TBL_RIGHT`.`name`)
需要注意的是,如果沒有指定根據哪個列(主鍵)進行合并,那么在連接的時候,函數會自動默認用兩個表格都包含的列進行連接。在我們的例子中,因為兩個表格都包含名為name的列,因此會根據name來進行連接。如果需要指定用哪些列進行連接,可以更改by參數,例子如下:
1band_members?%>%?2inner_join(band_instruments2,?by?=?c("name"?=?"artist"))34##?#?A?tibble:?2?x?35##?name?band?plays?6##????7##?1?John?Beatles?guitar8##?2?Paul?Beatles?bass
這樣一來,我們就用band_members的name列與band_instrument2的artist進行了連接。
另外一點需要明確的是,合并之后,兩個表合并的鍵只會保留其中一個,也就是第一個表。如果兩者的鍵的名稱不一樣,也只會保留第一個,比如上面的例子中,我們合并的表格已經沒有出現artist這一列,而是統一合并到name這一列中。
左
連接
1band_members?%>%? 2left_join(band_instruments) 3 4##?Joining,?by?=?"name" 5 6##?#?A?tibble:?3?x?3 7##?name?band?plays? 8##???? 9##?1?Mick?Stones??10##?2?John?Beatles?guitar11##?3?Paul?Beatles?bass
SQL代碼如下:
1?SELECT?`TBL_LEFT`.`name`?AS?`name`,?`TBL_LEFT`.`band`?AS?`band`,?`TBL_RIGHT`.`plays`?AS?`plays`2FROM?`band_members`?AS?`TBL_LEFT`3LEFT?JOIN?`band_instruments`?AS?`TBL_RIGHT`4ON?(`TBL_LEFT`.`name`?=?`TBL_RIGHT`.`name`)
右
連接
1band_members?%>%? 2right_join(band_instruments) 3 4##?Joining,?by?=?"name" 5 6##?#?A?tibble:?3?x?3 7##?name?band?plays? 8##???? 9##?1?John?Beatles?guitar10##?2?Paul?Beatles?bass?11##?3?Keith??guitar
SQL代碼如下:
1?SELECT?`TBL_RIGHT`.`name`?AS?`name`,?`TBL_LEFT`.`band`?AS?`band`,?`TBL_RIGHT`.`plays`?AS?`plays`2FROM?`band_members`?AS?`TBL_LEFT`3RIGHT?JOIN?`band_instruments`?AS?`TBL_RIGHT`4ON?(`TBL_LEFT`.`name`?=?`TBL_RIGHT`.`name`)
全
連接
1band_members?%>%? 2full_join(band_instruments) 3 4##?Joining,?by?=?"name" 5 6##?#?A?tibble:?4?x?3 7##?name?band?plays? 8##???? 9##?1?Mick?Stones??10##?2?John?Beatles?guitar11##?3?Paul?Beatles?bass?12##?4?Keith??guitar
SQL代碼如下:
1?SELECT?coalesce(`TBL_LEFT`.`name`,?`TBL_RIGHT`.`name`)?AS?`name`,?`TBL_LEFT`.`band`?AS?`band`,?`TBL_RIGHT`.`plays`?AS?`plays`2FROM?`band_members`?AS?`TBL_LEFT`3FULL?JOIN?`band_instruments`?AS?`TBL_RIGHT`4ON?(`TBL_LEFT`.`name`?=?`TBL_RIGHT`.`name`)
大家可以通過觀察結果來體會不同連接的效果。
如果兩個表格中用相同名字的列怎么辦?連接函數會自動給同名列加入后綴,比如A表格和B表格都有一列名為same,那么合并之后,會出現兩列,名字分別為same.x和same.y。后綴名是可以變更的,你可以通過suffix參數對后綴名進行設置。
基
于多個列進行連接
有時候我們不僅僅需要基于單列連接,而且要用到基于多個列的連接。比如我們遇到這么一個問題:我們兩個表格都有年、月、日的數據,我們需要把兩個表格按照日期對應起來,那么就需要年月日都對的上號才能夠進行連接。下面我們來舉個例子,我們先構造兩個表:
1d1? 2x?=?letters[4:6], 3y?=?LETTERS[4:6], 4a?=?rnorm(3) 5) 6 7d2? 8x2?=?letters[6:4], 9y2?=?LETTERS[6:4],10b?=?rnorm(3)11)1213d11415##?#?A?tibble:?3?x?316##?x?y?a17##???18##?1?d?D?0.140?19##?2?e?E?0.074620##?3?f?F?-0.5492122d22324##?#?A?tibble:?3?x?325##?x2?y2?b26##???27##?1?f?F?-0.35528##?2?e?E?-1.47?29##?3?d?D?-0.490
下面我們要把d1和d2連接起來,根據它們的前兩列:
1left_join(d1,?d2,?by?=?c("x"?=?"x2",?"y"?=?"y2"))23##?#?A?tibble:?3?x?44##?x?y?a?b5##????6##?1?d?D?0.140?-0.4907##?2?e?E?0.0746?-1.47?8##?3?f?F?-0.549?-0.355
如果不能夠確定兩個表格中是否有以及有多少相同的列名稱,在連接的時候應該總是指定by參數,來決定兩個表格究竟基于什么鍵進行連接。
事實上,兩個表格的連接可以基于無窮多的列,比如年月日就涉及了3列,如果再加上地理位置等信息,就更多了。這也充分告訴我們,連接能夠給我們連接數據帶來巨大的便利。
半
連接(semi_join)與反連接(anti_join)
半連接與反連接在實際工作中相對比較少用,但是這也取決于你的工作內容是什么。首先需要聲明的是,半連接和反連接都只會返回“左表”的內容,也就是A表格與B表格進行半連接或反連接的時候,只會返回A表格的信息,不會返回B表格的信息。其中,半連接其實相當于進行了一次內連接,不過,它不會保留B表格的任何內容(也就是沒有保留B表格的列)。反連接則與半連接相反,它會匹配在A表格出現而B表格沒有出現的鍵值,比如A表格x列出現了a,b,c,B表格x列出現了b,c,d,那么半連接會保留A表格x列出現b,c的記錄,反連接則會保留A表格x列出現a的記錄。
紙上得來終覺淺,我們來進行實際操作:
1band_members?%>%? 2semi_join(band_instruments) 3 4##?Joining,?by?=?"name" 5 6##?#?A?tibble:?2?x?2 7##?name?band? 8##??? 9##?1?John?Beatles10##?2?Paul?Beatles1112band_members?%>%?13anti_join(band_instruments)1415##?Joining,?by?=?"name"1617##?#?A?tibble:?1?x?218##?name?band?19##???20##?1?Mick?Stones
SQL代碼如下:
1?SELECT?*?FROM?`band_members`?AS?`TBL_LEFT` 2 3WHERE?EXISTS?( 4SELECT?1?FROM?`band_instruments`?AS?`TBL_RIGHT` 5WHERE?(`TBL_LEFT`.`name`?=?`TBL_RIGHT`.`name`) 6) 7 8?SELECT?*?FROM?`band_members`?AS?`TBL_LEFT` 910WHERE?NOT?EXISTS?(11SELECT?1?FROM?`band_instruments`?AS?`TBL_RIGHT`12WHERE?(`TBL_LEFT`.`name`?=?`TBL_RIGHT`.`name`)13)
小
結
本章介紹了強大的數據表連接操作,在實際工作中,連接操作的速度是非常快的,效率極高。對于內連接、全連接、左連接、右連接是我們工作中最常用的連接方法,需要牢牢把握。我們還介紹了如何根據多個鍵值進行連接,并簡要介紹了半連接和反連接的概念和操作方法。需要注意的是,當進行復雜連接時,一定要用by參數指定不同表格中用于連接的鍵,否則容易發生錯誤。
——————————————
往期精彩:
IT男,程序猿在婚戀市場有多受歡迎?
都挺好,怎么好?
史上最污技術解讀,讓你秒懂IT術語
R語言中文社區2018年終文章整理(作者篇)
R語言中文社區2018年終文章整理(類型篇)
總結
以上是生活随笔為你收集整理的left join 不重复_R语言ETL工程:连接(join)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL引擎innodb和mysum_
- 下一篇: c mysql转sqlite_Sqli