data.frameのrbindにはみんな苦労しているようだ
id:gepuroさんの日記が目にとまった。
R言語でデータを縦に結合させる
どうも、このかたも同じことで苦労されていたようだ。
私はSASを使ったことが無い。だからset関数を知らない。
でも、Rのrbindの仕様はSAS使いの人を混乱させるようだ。
で、それぞれのブログにあるset関数とset2関数はこんな関数だった。
- set関数なら
> x <- data.frame(A=1:5,B=5:1,row.names=1:5) > y <- data.frame(B=1:5,C=5:9,row.names=1:5) > z <- data.frame(C=3:8,A=8:13,row.names=2:7) > > set <- function(x,y) + { + coln <- unique(c(colnames(x),colnames(y))) + x[coln[!coln %in% colnames(x)]] <- NA + y[coln[!coln %in% colnames(y)]] <- NA + rbind(x,y) + } > set(z,set(x,y)) C A B 2 3 8 NA 3 4 9 NA 4 5 10 NA 5 6 11 NA 6 7 12 NA 7 8 13 NA 71 NA 1 5 8 NA 2 4 9 NA 3 3 10 NA 4 2 11 NA 5 1 12 5 NA 1 13 6 NA 2 14 7 NA 3 15 8 NA 4 16 9 NA 5
- set2関数なら
> set2 <- function(x,...){ + df <- x + for(i in list(...)){ + df <- set(df,i) + } + df + } > set2(z,x,y) C A B 2 3 8 NA 3 4 9 NA 4 5 10 NA 5 6 11 NA 6 7 12 NA 7 8 13 NA 71 NA 1 5 8 NA 2 4 9 NA 3 3 10 NA 4 2 11 NA 5 1 12 5 NA 1 13 6 NA 2 14 7 NA 3 15 8 NA 4 16 9 NA 5
set2関数の方が拡張性があるのかなぁ?
でも、明示的にオブジェクトを指定するのでsetを打ち込む手間が省けるだけのような気もする…
オブジェクトが増えたならforでなんとかできるし…
> dat <- list(x,y,z) > for(i in seq(dat)[-1]) dat[[1]] <- set(dat[[1]], dat[[i]]) > dat[[1]] A B C 1 1 5 NA 2 2 4 NA 3 3 3 NA 4 4 2 NA 5 5 1 NA 6 NA 1 5 7 NA 2 6 8 NA 3 7 9 NA 4 8 10 NA 5 9 21 8 NA 3 31 9 NA 4 41 10 NA 5 51 11 NA 6 61 12 NA 7 71 13 NA 8
個人的にはrbind関数の副作用は同じrownameがあるとき、rownamseが連番になってくれないことと思っている。
で、私も昔はこんな関数を書いていたことを思い出した。
> rbind2 <- function(list, mn=TRUE){ + ncol <- unique(unlist(lapply(list,colnames))) + nrow <- unlist(lapply(list,rownames)) + + list <- lapply(list, function(x,nc=ncol){ + mat <- matrix(NA, ncol=sum(!nc%in%colnames(x)), nrow=nrow(x), + dimnames=list(rownames(x),nc[!nc%in%colnames(x)])) + cbind(x,mat)[,nc] + }) + + if(mn){ + nrow <- unique(nrow) + dat <- matrix(NA,ncol=length(ncol),nrow=length(nrow),dimnames=list(seq(nrow),ncol)) + for(i in nrow) for(j in ncol) + dat[i,j] <- mean(unlist(sapply(list, function(mat,xy=c(i,j)) mat[xy[1],xy[2]])) + , na.rm=TRUE) + }else{ + dat <- do.call("rbind",list) + rownames(dat) <- seq(nrow(dat)) + } + dat[is.na(dat)] <- NA + return(as.data.frame(dat)) + } > list <- list(x,y,z) > rbind2(list,mn=TRUE) A B C 1 1 3 5.0 2 5 3 4.5 3 6 3 5.5 4 7 3 6.5 5 8 3 7.5 6 12 NA 7.0 7 13 NA 8.0 > rbind2(list,mn=FALSE) A B C 1 1 5 NA 2 2 4 NA 3 3 3 NA 4 4 2 NA 5 5 1 NA 6 NA 1 5 7 NA 2 6 8 NA 3 7 9 NA 4 8 10 NA 5 9 11 8 NA 3 12 9 NA 4 13 10 NA 5 14 11 NA 6 15 12 NA 7 16 13 NA 8
もう、何に使ったのかすら思い出せないけど。