列名が違う場合には縦結合は困難
各所に散在するデータベースを合体させて利用することがあります。
項目順が違ったり項目が不足していたり
同種のデータベースだからといっても、全てのデータベースが同一項目名同一順に構成されているとは限りません。
社員番号 | 部署 | 氏名 |
---|---|---|
1 | 営業部 | 山田太郎 |
2 | 営業部 | 鈴木花子 |
社員番号 | 氏名 | 役職 |
---|---|---|
3 | 杉本一郎 | 嘱託 |
4 | 支払益子 | 課長 |
役職 | 氏名 |
---|---|
課長 | 会計主水 |
一般 | 白鳥麗子 |
そんな時、rbind()ではエラー
これらの例はそれぞれに共通の項目もありますが、不足項目もあります。このような場合に縦結合するとどうなるのでしょうか。
R では縦結合するための関数として rbind() が用意されています。
まず、rbind()の動作を確認するために上の例に合わせたサンプル社員台帳データフレームを作成します
。
用意した 社員台帳 と 社員マスタ に rbind() を実行してみます。
rbind(社員台帳,社員マスタ) ##以下にエラー match.names(clabs, names(xi)) : 名前が以前の名前と一致しません
このようにエラー(列名が異なる!)が発生します。
標準の rbind() では 列名や列順が異なると縦結合できません。
ではどうすれば良いのでしょうか。
列名が違う場合に縦結合可能とする方法(2)~項目順が異なる場合~
列名が違っても内容の同じ列が同じ順番に並んでいれば
列名が違う場合に縦結合可能とする方法(1)で強制結合できます。
が、ここでは項目の内容も並びもバラバラですので違う考え方が必要です。
ユーザー関数 rbindCNames() で解決する
rbind() は、「同名項目の列」が「同じ順に」並んでいるならば縦結合する仕様のようです。
dmr2008さんが、このことを踏まえた上で、統計分析パッケージSASで縦結合に用いるsetをイメージした関数を公開してくださっています(Rのお仕事:Rでset - livedoor Blog(ブログ))。
これをコア部分に流用させていただいたのが以下のユーザー関数です。
#------------------------------------------------------# # rbindCNames(df1,df2,df3…) # 三つ以上のデータフレームにも対応 # 列順に関係なく列名を揃えて縦結合。 # ない列はNAで埋める。 # a b c # a c d # ↓ # a b c NA # a NA c d #------------------------------------------------------# rbindCNames<-function(...) { df <- list(...) x<-df[[1]] for(i in 2:length(df)) { y<-df[[i]] ### <Dmr2008 さんの Set() 関数> coln <- unique(c(colnames(x),colnames(y))) x[coln[!coln %in% colnames(x)]] <- NA y[coln[!coln %in% colnames(y)]] <- NA x<- rbind(x,y) ### </Dmr2008 さんの Set() 関数> } return(x) }
ご使用は自己責任でお願いします。
▼使用例
社員台帳 ## 社員番号 部署 氏名 ##1 1 営業部 山田太郎 ##2 2 営業部 鈴木花子 社員マスタ ## 社員番号 氏名 役職 ##1 3 杉本一郎 嘱託 ##2 4 支払益子 課長 社員マスタ2 ## 役職 氏名 ##1 課長 会計主水 ##2 一般 白鳥麗子 rbindCNames(社員台帳,社員マスタ,社員マスタ2) ## 社員番号 部署 氏名 役職 ##1 1 営業部 山田太郎 NA ##2 2 営業部 鈴木花子 NA ##3 3 NA 杉本一郎 嘱託 ##4 4 NA 支払益子 課長 ##5 NA NA 会計主水 課長 ##6 NA NA 白鳥麗子 一般
つまり、①結合元のデータセットに使われている列を最小公倍数的に抽出し、
②該当列がない場合にはNAをあてることで列を揃えて結合しています。
先人諸賢の知恵
なお、上記set関数作者の dmr2008さん は3つ以上のデータセットを結合するset2関数も公開してくださっています Rのお仕事:Rでset2(複数のデータフレームに対応) - livedoor Blog(ブログ)
また、plyrパッケージのrbind.fill関数 、dplyrパッケージのrbind_all関数、rbind_list関数でも対応できるとのことです。
rbind.fillの機能はrbind_listに含まれている - 盆栽日記