rbind.fill
是一个很棒的函数,对于数据框列表表现得非常出色。但在我看来,如果列表只包含(命名)向量,它可以更快地完成。
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)
}
基本上,我们获取总共的“唯一名称”以形成最终数据框的列。然后,我们创建一个长度为输入值的列表,并将其余的值填充为“NA”。这可能是最棘手的部分,因为我们必须在填充NA时匹配名称。然后,我们最终将名称设置为列名(如果需要,可以使用data.table包中的setnames通过引用设置列)。
现在进行一些基准测试:
数据:
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())
功能:
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)
}
Benchmarking:
require(microbenchmark)
microbenchmark(t1 <- rbind.named.fill(ll),
t2 <- rbind.fill.plyr(ll),
t3 <- do.call(foo, ll), times=10)
identical(t1, t2)
identical(t1, t3)
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
plyr:::rbind.fill
:将数据框的列表按行连接起来,用NA填充缺失的列。 - Roman Luštrikplyr:::rbind.fill(lapply(x,function(y){as.data.frame(t(y))}))
将所有字符转换为因子...有没有什么方法可以摆脱这个问题? - h.l.mrbind.fill(lapply(x,function(y){as.data.frame(t(y),stringsAsFactors=FALSE)}))
- h.l.mas.data.frame
。我不认为这是“最佳/最快”的解决方案。 - Arun