R語言數據合併

這裡所謂的跨對象數據合併,主要指的是兩個數據框、數據表的合併,尤其是使用merge()函數進行數據框的合併,就像Excel做vlookup那樣常用又實用。本篇主要圍繞以下內容展開介紹:

1、合併數據框:merge()函數

2、合併數據表:使用key鍵合併數據表

為方便有興趣的朋友動手實踐,我們在這裡使用R語言中airquality數據集,這是一則美國紐約空氣質量監測數據,共153條記錄,6個變數,分別是Ozone(臭氧指數),Solar.R(太陽輻射),Wind(風速),Temp(溫度),Month(觀測月份),Day(觀測日)。

在進行其他操作前,我們先來看看數據。

head(airquality) Ozone Solar.R Wind Temp Month Day1 41 190 7.4 67 5 12 36 118 8.0 72 5 23 12 149 12.6 74 5 34 18 313 11.5 62 5 45 NA NA 14.3 56 5 56 28 NA 14.9 66 5 6

可以看到數據有瑕疵,比如存在NA值。

我們需要將所有含有NA的觀測值移除,新建一個數據集,newairquality.

newairquality<-na.omit(airquality)

#na.omit()函數可以用來移除所有含有NA的行。

我再看newairquality數據集目前的行數:

nrow(newairquality)[1] 111

較原始數據的153行,減少了42行,說明共有42條記錄存有缺陷。

接下來,我們還需要給newairquality數據集添加一列編號(ID),用於各行之間彼此區分,也是為後續匹配操作做準備。

ID=seq(1,111,1)ID=data.frame(ID)newairquality<-cbind(ID,newairquality)head(newairquality) ID Ozone Solar.R Wind Temp Month Day1 1 41 190 7.4 67 5 12 2 36 118 8.0 72 5 23 3 12 149 12.6 74 5 34 4 18 313 11.5 62 5 47 5 23 299 8.6 65 5 78 6 19 99 13.8 59 5 8

語句解讀:

#ID=seq(1,111,1)

seq()函數用於生成一串序列序列,序列起點為1,終點為111,步長(間隔)為1.

ID的本質是向量,可以使用class()函數進行數據類型檢測:

class(ID)[1] "numeric"

#ID=data.frame(ID)

使用data.frame()函數將生成的序列轉換為數據框。

#newairquality<-cbind(ID,newairquality)

使用cbind()函數進行列連接,c為column的首字母。

接下來,為了演示merge()函數的使用效果,我們需要將newairquality數據集拆分為兩部分,形成part1和part2.

myvars<- names(newairquality) %in% c("Wind", "Temp")myvars[1] FALSE FALSE FALSE TRUE TRUE FALSE FALSEpart1<-newairquality[!myvars]head(part1) ID Ozone Solar.R Month Day1 1 41 190 5 12 2 36 118 5 23 3 12 149 5 34 4 18 313 5 47 5 23 299 5 78 6 19 99 5 8

#myvars<- names(newairquality) %in% c("Wind", "Temp")

用於判斷newairquality所有列名是否在c("Wind", "Temp")中,結果為布爾值(TRUE/FALSE)

#part1<-newairquality[!myvars]

用於選擇不在c("Wind", "Temp")中的其餘欄位。

part2<-newairquality[,c("ID","Wind","Temp")]head(part2) ID Wind Temp1 1 7.4 672 2 8.0 723 3 12.6 744 4 11.5 627 5 8.6 658 6 13.8 59

#part2<-newairquality[,c("ID","Wind","Temp")]選擇"ID","Wind","Temp"欄位列所有數據。

至此,我們構造好了演示數據part1和part2。

接下來,我們的工作就是使用merge()函數,將part1和part2再合併回去。看到這兒,可能會有朋友覺得,「嗯,你真是夠了!」,但是,和數據打交道往往就是這樣,折騰來折騰去的,求的只是熟練,然後提升我們的效率。

話不多說,我們接著干!

為了讓合併(也叫匹配)效果更加明顯,我們先來個乾坤大挪移,將part1和part2的數據都打亂順序,以防有些愛走捷徑的傢伙直接cbind()一下就完事大吉,因為本來工作中的情況就很複雜。

這裡需要用到一個新的包——doBy,請先安裝並載入它。

install.packages("doBy")library(doBy)

使用doBy包中的orderBy()函數對數據進行排序,默認為升序。

part1<-orderBy(~Ozone,part1)head(part1) ID Ozone Solar.R Month Day21 17 1 8 5 2123 19 4 25 5 2318 14 6 78 5 1876 45 7 48 7 15147 106 7 49 9 249 7 8 19 5 9

#part1<-orderBy(~Ozone,part1)

~Ozone表示按照臭氧指數進行升序排列。

延伸:~Ozone+Solar.R 表示先按臭氧指數進行升序排列,對於臭氧指數相同的再按太陽輻射指數升序排列。

同樣,對part2也進行排序,可以隨心所欲,我選擇了Wind+Temp組合排列。

part2<-orderBy(~Wind+Temp,part2)head(part2) ID Wind Temp121 80 2.3 94126 85 2.8 93117 77 3.4 8199 63 4.0 8962 34 4.1 8466 37 4.6 83

為了讓merge()函數的神通充分發揮出來,我還要繼續把數據做的「亂」一點,我需要讓part1和part2數據長度不一致,即行數不同。

生成兩個演示數據集x和y,其中x為part1中ID號小於10的數據,共9行數據。

x<-subset(part1,ID<10)x ID Ozone Solar.R Month Day9 7 8 19 5 913 9 11 290 5 133 3 12 149 5 312 8 16 256 5 124 4 18 313 5 48 6 19 99 5 87 5 23 299 5 72 2 36 118 5 21 1 41 190 5 1

y為part2中ID號大於8小於15的數據,共6行數據。

y<-subset(part2,ID<15&ID>8)y ID Wind Temp13 9 9.2 6614 10 10.9 6816 12 11.5 6417 13 12.0 6615 11 13.2 5818 14 18.4 57

這裡用到了取數據函數subset(),可以簡單的理解為:

subset(數據集,篩選條件)

後續我將在專欄中介紹更為詳盡的用法。

我們構造的兩個演示數據x、y特點如下:

1、有共同欄位(ID列)

2、共同欄位ID列中有共同的元素(ID=9)

2、數據行數不一致(9行/6行),欄位不一致(準確的說,除了ID列,都不一致)

3、數據順序不一致(已經通過排序打亂順序)

這些特徵足夠滿足工作中較為複雜的現狀。

那麼,鋪墊了那麼......那麼多,接下來就請merge()函數出場吧!

一、merge()函數參數說明

merge(x, y, by,suffixes=c(".x",".y")...)

#x,y 為要合併的兩個數據集

#by用於設置合併的方式,常見的合併方式有4種:inner模式、outer模式、left模式、right模式,接下來我們分別演示

#suffixes =c(".x",".y" )表示當x ,y 數據集存在相同欄位名,且不用於by 中的欄位,為防止重複,而無法區分,可以在匹配的結果中通過添加.x ,.y 的方式加以區分。

二、merge()函數演示

1、inner模式

所謂inner模式,指取兩個數據集的交集。

例:取x、y數據集的交集,並將y中的信息匹配到x中。

data1<-merge(x,y,by="ID") ID Ozone Solar.R Month Day Wind Temp1 9 11 290 5 13 9.2 66

#by="ID"指定連接列(兩個數據集均有的列)為ID欄位。如果需要用多個列進行匹配,則設置by= c( "欄位1","欄位2")即可。

這裡,x、y演示數據ID列交集只有一行,ID=9,因此只返回一行數據。

匹配的信息(Wind、Temp欄位)會添加到x數據的後面。

默認會按照連接列(這裡是ID)對匹配結果進行升序排列。

1、outer模式

將x、y表的數據粗暴匯總,就像大雜燴一樣。

data2<-merge(x,y,all = TRUE) ID Ozone Solar.R Month Day Wind Temp1 1 41 190 5 1 NA NA2 2 36 118 5 2 NA NA3 3 12 149 5 3 NA NA4 4 18 313 5 4 NA NA5 5 23 299 5 7 NA NA6 6 19 99 5 8 NA NA7 7 8 19 5 9 NA NA8 8 16 256 5 12 NA NA9 9 11 290 5 13 9.2 6610 10 NA NA NA NA 10.9 6811 11 NA NA NA NA 13.2 5812 12 NA NA NA NA 11.5 6413 13 NA NA NA NA 12.0 6614 14 NA NA NA NA 18.4 57

x數據集原有9行數據,y數據集原有6行數據,匯總後,數據行數為9+6-1=14行,這裡減1,指的是x、y均有的一行(ID=10)。

想必你也注意到大片的NA了,這些東西的出現主要是因為x、y數據集中沒有相應的信息,但是我們merge()函數在outer模式下給它們又留了座位,就當缺席的朋友吧。

如果你不放心自己是否匹配正確,可以使用以下代碼進行查看非NA 部分的數據:

head (na.omit(data2))

如果你是個強迫症數據處理者,看不慣NA 的出現,我們可以使用下面的代碼將所有含有NA 值的欄位記錄替換為0。

例如:

data2$Temp [is.na(data2$Temp)]<-0

3、left 模式

例:通過ID欄位作為連接列,將y中信息匹配到x數據集中。

data3<-merge(x,y,by="ID",all.x = TRUE) ID Ozone Solar.R Month Day Wind Temp1 1 41 190 5 1 NA NA2 2 36 118 5 2 NA NA3 3 12 149 5 3 NA NA4 4 18 313 5 4 NA NA5 5 23 299 5 7 NA NA6 6 19 99 5 8 NA NA7 7 8 19 5 9 NA NA8 8 16 256 5 12 NA NA9 9 11 290 5 13 9.2 66

#by="ID"指定連接列(兩個數據集均有的列)為ID欄位。

#all.x = TRUE表示以x數據集為參照,將y中的信息匹配過來。對於y中有,而x中沒有的行,不添加到x數據集中。

如果需要按照多列進行匹配,可以寫作:

merge(x,y,by=c("欄位1","欄位2")

4、right模式

例:通過ID欄位作為連接列,將x數據集中信息匹配到y中。

data4<-merge(x,y,by="ID",all.y = TRUE) ID Ozone Solar.R Month Day Wind Temp1 9 11 290 5 13 9.2 662 10 NA NA NA NA 10.9 683 11 NA NA NA NA 13.2 584 12 NA NA NA NA 11.5 645 13 NA NA NA NA 12.0 666 14 NA NA NA NA 18.4 57

#by="ID"設置了兩個數據集的連接通道。

#all.y = TRUE表示,y數據集不變,將x數據集中信息匹配過來,沒有信息的則返回NA。

至此,merge()函數在工作中的常見用法就介紹完了。

看,其實也不難!

下面,我們還有介紹另一種數據匹配的方式——使用key鍵合併數據表。

細心的朋友可能已經注意到了,這裡我們合併的對象是數據表,不是數據框,那首先需要解決的問題便是——數據框和數據表的轉換問題。

依舊使用上述演示數據集x、y,將這兩個數據框轉換為數據表:

首先需要安裝並載入data.table包

install.packages("data.table")library(data.table)

使用as.data.table()函數將x、y數據集轉換為數據表

x_table<-as.data.table(x)y_table<-as.data.table(y)class(x_table)[1] "data.table" "data.frame"class(y_table)[1] "data.table" "data.frame"

使用class()函數檢驗是否轉換成功,返回結果為[1] "data.table" "data.frame"表明x、y數據集已經轉換為數據表和數據框的兼容模式。部分數據框的操作也可以對數據表進行。

在進行匹配前,再來看看數據:

x_table ID Ozone Solar.R Month Day1: 1 41 190 5 12: 2 36 118 5 23: 3 12 149 5 34: 4 18 313 5 45: 5 23 299 5 76: 6 19 99 5 87: 7 8 19 5 98: 8 16 256 5 129: 9 11 290 5 13

y_table ID Wind Temp1: 9 9.2 662: 10 10.9 683: 12 11.5 644: 13 12.0 665: 11 13.2 586: 14 18.4 57

給x_table設置key鍵——ID列

setkey(x_table,ID)

進行匹配:

1、將x_table中數據匹配到y_table中,保留y_table中有而x_table中沒有的記錄(對應merge()函數的right模式):

x_table[y_table,on="ID"]ID Ozone Solar.R Month Day Wind Temp1: 9 11 290 5 13 9.2 662: 10 NA NA NA NA 10.9 683: 12 NA NA NA NA 11.5 644: 13 NA NA NA NA 12.0 665: 11 NA NA NA NA 13.2 586: 14 NA NA NA NA 18.4 57

#on="ID"表示以ID列為連接列

默認匹配到y_table中的x_table的欄位會放在y_table原有欄位前面。

2、將y_table中數據匹配到x_table中,保留x_table中有而y_table中沒有的記錄(對應merge()函數的left模式):

y_table[x_table,on="ID"]ID Wind Temp Ozone Solar.R Month Day1: 1 NA NA 41 190 5 12: 2 NA NA 36 118 5 23: 3 NA NA 12 149 5 34: 4 NA NA 18 313 5 45: 5 NA NA 23 299 5 76: 6 NA NA 19 99 5 87: 7 NA NA 8 19 5 98: 8 NA NA 16 256 5 129: 9 9.2 66 11 290 5 13

3、將y_table中數據匹配到x_table中,保留x_table中有且y_table中也有的記錄(對應merge()函數的inner模式):

y_table[x_table,on="ID",nomatch=0] ID Wind Temp Ozone Solar.R Month Day1: 9 9.2 66 11 290 5 13

使用數據表加key鍵的模式相對數據框的優勢何在?

下面用系統時間耗用給你答案。

system.time(y_table[x_table,on="ID",nomatch=0])用戶 系統 流逝 0 0 0 system.time(merge(x,y,by="ID"))用戶 系統 流逝 0.02 0.00 0.01

同樣的匹配效果,設置key鍵的table模式明顯比直接對數據框進行merge更節約系統資源,這對於處理大型數據來說,簡直是福音。

題外話:

本文中涉及的包主要有doBy、data.table,需要的朋友可以到我的雲盤下載。

鏈接:pan.baidu.com/s/1MEnt_M 密碼:io3m

手動載入包方法如下(以RStudio為例)

1、Tools-Install Packages...

2、Install from:選擇第二個選項——Packages Archive File(.zip;.tar.gz),再點擊Browse...

3、選擇本地的包,open,Install即可。


推薦閱讀:

機器學習筆記:利用scikit-learn進行數據預處理
Python之matplotlib入門教程
實踐—簡單數據處理和分析
Python數據科學(五)- 數據處理和數據採集
用2600條文本數據,為你揭秘TED受歡迎的真正原因!

TAG:R編程語言 | 數據處理 | 匹配 |