20

各要素が文字ベクトルで、長さが異なるリストがあります。データを行としてバインドして、列名が「整列」し、余分なデータがある場合は列を作成し、データが欠落している場合は列を作成します次に、NA を作成します。

以下は、私が扱っているデータのモック例です

x <- list()
x[[1]] <- letters[seq(2,20,by=2)]
names(x[[1]]) <- LETTERS[c(1:length(x[[1]]))]
x[[2]] <- letters[seq(3,20, by=3)]
names(x[[2]]) <- LETTERS[seq(3,20, by=3)]
x[[3]] <- letters[seq(4,20, by=4)]
names(x[[3]]) <- LETTERS[seq(4,20, by=4)]

以下の行は、通常、各要素の形式が同じであると確信している場合に行うことです...

do.call(rbind,x)

NAバインディングプロセスで新しい列が見つかった場合に新しい列を追加しながら、列名を一致させ、空白を s で埋める素敵な小さな解決策を誰かが思いついたことを望んでいました...

4

4 に答える 4

30

rbind.fillは、data.frames のリストで非常にうまく機能する素晴らしい関数です。しかし、私見ですが、この場合、リストに(名前付きの)ベクトルのみが含まれていると、はるかに高速に実行できます。

rbind.fill方法_

require(plyr)
rbind.fill(lapply(x,function(y){as.data.frame(t(y),stringsAsFactors=FALSE)}))

より簡単な方法 (少なくともこのシナリオでは効率的):

rbind.named.fill <- function(x) {
    nam <- sapply(x, names)
    unam <- unique(unlist(nam))
    len <- sapply(x, length)
    out <- vector("list", length(len))
    for (i in seq_along(len)) {
        out[[i]] <- unname(x[[i]])[match(unam, nam[[i]])]
    }
    setNames(as.data.frame(do.call(rbind, out), stringsAsFactors=FALSE), unam)
}

基本的に、最終的な data.frame の列を形成するために、一意の名前をすべて取得します。次に、長さ = 入力のリストを作成し、残りの値を で埋めますNA。NA を埋める際に名前を一致させる必要があるため、これはおそらく「最も難しい」部分です。そして、最後に列に名前を設定します (必要に応じてsetnamesfromdata.tableパッケージを使用して参照によって設定することもできます)。


次に、いくつかのベンチマークに進みます。

データ:

# generate some huge random data:
set.seed(45)
sample.fun <- function() {
    nam <- sample(LETTERS, sample(5:15))
    val <- sample(letters, length(nam))
    setNames(val, nam)  
}
ll <- replicate(1e4, sample.fun())

機能:

# plyr's rbind.fill version:
rbind.fill.plyr <- function(x) {
    rbind.fill(lapply(x,function(y){as.data.frame(t(y),stringsAsFactors=FALSE)}))
}

rbind.named.fill <- function(x) {
    nam <- sapply(x, names)
    unam <- unique(unlist(nam))
    len <- sapply(x, length)
    out <- vector("list", length(len))
    for (i in seq_along(len)) {
        out[[i]] <- unname(x[[i]])[match(unam, nam[[i]])]
    }
    setNames(as.data.frame(do.call(rbind, out), stringsAsFactors=FALSE), unam)
}

更新(GSeeの機能も追加):

foo <- function (...) 
{
  dargs <- list(...)
  all.names <- unique(names(unlist(dargs)))
  out <- do.call(rbind, lapply(dargs, `[`, all.names))
  colnames(out) <- all.names
  as.data.frame(out, stringsAsFactors=FALSE)
}

ベンチマーク:

require(microbenchmark)
microbenchmark(t1 <- rbind.named.fill(ll), 
               t2 <- rbind.fill.plyr(ll), 
               t3 <- do.call(foo, ll), times=10)
identical(t1, t2) # TRUE
identical(t1, t3) # TRUE

Unit: milliseconds
                       expr        min         lq     median         uq        max neval
 t1 <- rbind.named.fill(ll)   243.0754   258.4653   307.2575   359.4332   385.6287    10
  t2 <- rbind.fill.plyr(ll) 16808.3334 17139.3068 17648.1882 17890.9384 18220.2534    10
     t3 <- do.call(foo, ll)   188.5139   204.2514   229.0074   339.6309   359.4995    10
于 2013-06-25T23:36:58.973 に答える