データのマージ (結合)

横にくっつける (列の追加)

merge関数で2つのデータフレームを横にくっつけられる。R-tipsも参考。

# 例示データ
datA <- data.frame(id=paste("ps", 1:10, sep=""), v1=rnorm(10), v2=gl(2, 5, label=c("ga", "gb")), v3=sample(1:5, replace=T))
datB <- data.frame(id=paste("ps", 101:110, sep=""), v2=gl(2, 5, label=c("gb", "gc")), v3=sample(1:5, replace=T)) # id重複なし
datC <- data.frame(id=paste("ps", 1:6, sep=""), v5=rnorm(6)) # id重複
# 確認しよう
datA
datB
datC

# 単純に横につなげるだけ
data.frame(datA, datB)
cbind(datA, datB)
data.frame(datA, datC) # 行数が違うとエラー


  • merge関数は共通する変数を下につなげ、足りない変数を横につなげる。
  • idで関連づけて結合。データが無いところはNAにする。同じ変数名があるときは.1とか.2とかついて別変数が生成される。
  • 一方のデータフレームに"id"という名前の変数がなくても、by.x="id", by.y="idとして扱う変数"で指定すればいい。
  • sort=Fで並べ替えを抑制できる。
  • 引数 all.x と all.y でそれぞれのデータフレームにおいて,どちらのデータを残すか否か(all.x : 左結合,all.y : 右結合)を指定することが出来る。

自分のためのmergeのまとめ

# パターン1: 同じid, 同じ変数がある場合
x <- data.frame(id=c(1,2,3), v1=c(4,5,6))
y <- data.frame(id=c(1,2,3), v1=c(44,55,66))
merge(x,y, sort=F) # エラーになりマージできない
merge(x,y, all=T, sort=F) # データが縦に結合されるのと同じになる。
data.frame(x,y) # データの重複になるので、idで並べ替えた上でdata.frame関数で結合したほうがよい。

# パターン2: 同じid, 違う変数がある場合
x <- data.frame(id=c(1,2,3), v1=c(4,5,6))
y <- data.frame(id=c(1,2,3), v2=c(44,55,66))
merge(x,y, sort=F) # idはひとつになり、変数が横に結合される。
merge(x,y,all=T, sort=F) # 上と同じ

# パターン3: 同じid名、違うid内容, 違う変数がある場合
x <- data.frame(id=c(1,2,3), v1=c(4,5,6))
y <- data.frame(id=c(11,22,33), v2=c(44,55,66))
merge(x,y, sort=F) # エラーになりマージできない
merge(x,y,all=T, sort=F) # idはひとつになり、変数が横に結合される。

# パターン4: 違うid, 同じ変数がある場合
x <- data.frame(id=c(1,2,3), v1=c(4,5,6))
y <- data.frame(id2=c(1,2,3), v1=c(44,55,66))
merge(x,y, sort=F) # エラーになりマージできない
merge(x,y, by="id", sort=F) # "id"という変数が共通してないのでエラー
merge(x,y,all=T, sort=F) # "同じ変数 (v1) " がidのように扱われる。
# この場合はidの変数名をそろえる。パターン2か3と同じになる。

# パターン5: 違うid, 違う変数がある場合...そんなものをマージしなくてよい。
それかやはりidをそろえてパターン2か3と同じにする。
x <- data.frame(id=c(1,2,3), v1=c(4,5,6))
y <- data.frame(id2=c(1,2,3), v2=c(44,55,66))
merge(x,y, sort=F) # 全ての変数が記録される。ゆえに重複もある
merge(x,y,all=T, sort=F) # 上と同じ

つまるところ、merge関数を使うときはパターン2かパターン3のみということ。
これ以上複雑なパターンのときはこれを使う。


下にくっつける (行の追加)

rbind関数を使う。2つのデータフレームが同じ変数でないとダメ

# 例示データ
datD <- data.frame(id=paste("ps", 1:10, sep=""), v1=rnorm(10), v2=gl(2, 5, label=c("ga", "gb")), v3=sample(1:5, replace=T))
datD

rbind(datA, datD)
rbind(datA, datC) # エラー。結合したい場合は事前にどちらかのデータフレームの変数を削除 or 使いすること


シンプルな例

# サンプルデータ
dat1 <- data.frame(id=paste("ps", 1:10, sep=""), v1=rnorm(10), v2=gl(2, 5, label=c("ga", "gb")), v3=sample(1:5, replace=T))
dat2 <- data.frame(id=paste("ps", 101:110, sep=""), v2=gl(2, 5, label=c("gb", "gc")), v3=sample(1:5, replace=T)) # id重複なし
dat3 <- data.frame(id=paste("ps", 1:6, sep=""), v5=rnorm(6)) # id重複

# 縦にくっつける
merge(dat1, dat2, all=T)
merge(dat1, dat3, all=T)

# 横にくっつける
cbind(dat1, dat2)
data.frame(dat1, dat2) # 自動で重複する変数名を変えてくれる


複数のデータファイルを読み込み、結合する

# 複数のデータファイルを一括してリストに読み込む
fnames <- dir(pattern=".csv") # とすると、作業ディレクトリ内のcsvファイルのみを選んでくれる
# fnamesp <- choose.files() # ファイルを選ぶ。パスのベクトルが保存される。リストの要素名には使いづらい
csvlist <- lapply(fnames, read.csv)
names(csvlist) <- fnames
csvlist

# 読み込んだcsvをマージする
n <- length(csvlist)
temp <- csvlist[[1]]
for (i in 2:n) {
temp <- merge(temp, csvlist[[i]], all=T)
}
res <- temp
res

## 青木先生のmerge.allを参考にした。感謝
http://aoki2.si.gunma-u.ac.jp/lecture/mb-arc/arc040/03212.html
merge.all <- function(...)
{
n <- length(list(...))
temp <- list(...)[[1]]
for (i in 2:n) {
temp <- merge(temp, list(...)[[i]], all=TRUE)
}
return(temp)
}


要素数の違うリストをマージしてデータフレームにする

参考: データの集計 要素数の違うリストの各要素の集計

# 例示データ
x <- c(A=1,B=2)
y <- c(A=66,B=77, C=88)
z <- c(A=100,C=200)
lst <- list(x,y,z)
names(lst) <- c("x", "y", "z")
lst # 要素数の違うリスト

# 各要素をデータフレームにする。要素の変数名を列名に使いたいので転置する。
# すでにデータフレームの場合 (たとえばリストの要素ごとにdescribe関数を適用した場合など) はこのステップは不要
xx <- lapply(lst, function(a) t(data.frame(a)))
## 各要素がtableのときはdata.frameではなくas.vectorにする
n <- length(xx)
temp <- xx[[1]]
for (i in 2:n) {
temp <- merge(temp, xx[[i]], all=T, sort=F)
}
res <- temp
rownames(res) <- names(lst)
res
# エレガントじゃないのう