一所懸命に手抜きする

デスクワークばかりのスポーツ嫌いで50歳も過ぎ、いよいよ足腰に衰えを感じつつある昨今。

rbind()とbind_rows() の違い 【R】

rbind()とbind_rows()

 例えば、2018年の売上データと2019年の売上データを結合するといった、フィールド構造が同じ(列名が同じ)複数のデータフレームを縦に結合したい場合があります。

縦結合といえば rbind()

 R言語では、縦結合にはrbind()という関数があります。

rbind()
> S2018<-data.frame(car=822,boat=9)
> S2019<-data.frame(car=816,boat=8)
> rbind(S2018,S2019)
  car boat
1 822    9
2 816    8

ただ、rbindは制約が厳しく、
・列数が違うと結合できません。

> S2018<-data.frame(car=822,boat=9,bike=423)
> S2019<-data.frame(car=816,boat=8)
> rbind(S2018,S2019)
 rbind(deparse.level, ...) でエラー:  
引数の列の数が一致しません

・列名が違うと結合できません。

> S2018<-data.frame(car=822,boat=9)
> x2019<-data.frame(car=816,board=8)
> rbind(S2018,x2019)
 match.names(clabs, names(xi)) でエラー:  
名前が以前の名前と一致しません
bind_rows()は多少融通が利きます

 dplyr ライブラリ中の関数にbind_rows()というものがあります。意図する機能はrbind()と同じです。私は、実行ログを監査法人に渡すのですが、bind_rows()ならば簡単な英語がわかる人ならば理解しやすいと思います。
 bind_rows() は rbind() の拡張版のようなものです。

・列数が違ってもNAで補いながら結合

>library("dplyr")
>  S2018<-data.frame(year=2018,car=822,boat=9,bike=423)
>  S2019<-data.frame(year=2019,car=816,boat=8)
>  bind_rows(S2018,S2019)
  year car boat bike
1 2018 822    9  423
2 2019 816    8   NA

・列名が違ってもNAで補いながら結合

>library("dplyr")
>  S2018<-data.frame(year=2018,car=822,boat=9)
>  x2019<-data.frame(year=2019,car=816,boad=8)
>  bind_rows(S2018,x2019)
  year car boat boad
1 2018 822    9   NA
2 2019 816   NA    8

bind_rows()の方が速い

 dplyr はRCPPを用いて主要パーツがC++にて作成されているため速いとの売り込みです。実際はどうなのか、10列×100万行のダミーデータで試してみると…私の環境では bind_rows()は rbind() の約3倍の速度でした。

> M1<-data.frame(matrix(1, nrow=1000000, ncol=10))
> system.time(a<-rbind(M1,M1))
   ユーザ   システム       経過  
      0.09       0.00       0.10 
>library("dplyr")
> system.time(b<-bind_rows(M1,M1))
   ユーザ   システム       経過  
      0.03       0.00       0.03 

おまけ : 列名が違うデータフレームを強制的に縦結合する方法

 毎回思いつきでヘッダを付けていると、例えば社員名のヘッダに「社員」「社員名」「氏名」などというように、微妙に異なる列名を付けてしまう人がいます。rbind()できない理由がそれだけならば、解決策はあります。
 結合したいデータフレームの列名を全て揃えてしまうことで、列名の差違をなくして結合してしまうのです。

> S2018<-data.frame(year=2018,car=822,boat=9)
> x2019<-data.frame(year=2019,car=816,board=8)
> # 列名を強制的に揃えます。
>   colnames(x2019)<-colnames(S2018)
> 
> # 列名が揃えばrbindできます
> rbind(S2018,x2019)
  year car boat
1 2018 822    9
2 2019 816    8
> 
> # bind_rowsもできます
>library("dplyr")
>bind_rows(S2018,x2019)
  year car boat
1 2018 822    9
2 2019 816    8

※ 本記事中、列名、ヘッダ、列見出しすべて同じ意味で使用しています。