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
※ 本記事中、列名、ヘッダ、列見出しすべて同じ意味で使用しています。