如果列数不均匀,请调用(rbind,list)

如果列数不均匀,请调用(rbind,list),r,list,data-binding,R,List,Data Binding,我有一个列表,每个元素都是不同长度的字符向量 我希望将数据绑定为行,以便列名“对齐”,如果有额外数据,则创建列,如果缺少数据,则创建NAs 下面是我正在处理的数据的模拟示例 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]]) <- LETT

我有一个列表,每个元素都是不同长度的字符向量 我希望将数据绑定为行,以便列名“对齐”,如果有额外数据,则创建列,如果缺少数据,则创建NAs

下面是我正在处理的数据的模拟示例

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)]

我希望有人能想出一个很好的解决方案,匹配列名并用
NA
s填空,同时添加新列,如果在绑定过程中发现新列…

如果您希望结果是矩阵

我最近为一位同事编写了这个函数,他想将向量rbind到矩阵中

foo <- function (...) 
{
  dargs <- list(...)
  if (!all(vapply(dargs, is.vector, TRUE))) 
      stop("all inputs must be vectors")
  if (!all(vapply(dargs, function(x) !is.null(names(x)), TRUE))) 
      stop("all input vectors must be named.")
  all.names <- unique(names(unlist(dargs)))
  out <- do.call(rbind, lapply(dargs, `[`, all.names))
  colnames(out) <- all.names
  out
}

R > do.call(foo, x)
     A   B   C   D   E   F   G   H   I   J   L   O   R   P   T  
[1,] "b" "d" "f" "h" "j" "l" "n" "p" "r" "t" NA  NA  NA  NA  NA 
[2,] NA  NA  "c" NA  NA  "f" NA  NA  "i" NA  "l" "o" "r" NA  NA 
[3,] NA  NA  NA  "d" NA  NA  NA  "h" NA  NA  "l" NA  NA  "p" "t"

foo
rbind.fill
是一个很棒的函数,在data.frames列表中表现得非常出色。但是,在这种情况下,当列表只包含(命名的)向量时,它可以更快地完成

rbind.fill
方式 更直接的方法(至少在这种情况下是有效的): 功能:
#plyr的rbind.fill版本:

rbind.fill.plyr这是一个使用包
data.table
的版本,对于非常大的数据来说速度要快一点。 它使用函数
rbindlist
及其传递给函数
do.call的参数
fill=TRUE

库(data.table)

x将名称向量转换为单个数据帧后,可以使用
dplyr::bind_rows

dplyr::bind_rows(lapply(x,function(y) as.data.frame(t(y),stringsAsFactors=FALSE)))

#     A    B    C    D    E    F    G    H    I    J    L    O    R    P    T
#1    b    d    f    h    j    l    n    p    r    t <NA> <NA> <NA> <NA> <NA>
#2 <NA> <NA>    c <NA> <NA>    f <NA> <NA>    i <NA>    l    o    r <NA> <NA>
#3 <NA> <NA> <NA>    d <NA> <NA> <NA>    h <NA> <NA>    l <NA> <NA>    p    t

这将提供与上述相同的输出

plyr:::rbind.fill
:rbinds用NA填充缺失列的数据帧列表。
plyr:::rbind.fill(lappy(x,function(y){as.data.frame(t(y))})
将所有字符转换为因子…无论如何都要去掉它?在节日结束后再做。转置变量会无意中将其更改为矩阵。一旦它强制它回到data.frame,字符就会被编码成factors
rbind.fill(lappy(x,函数(y){as.data.frame(t(y),stringsAsFactors=FALSE)})
@h.l.m,当您在每个列表元素上调用
as.data.frame
时,这将是非常低效的。我不认为这是“最好/最快”的解决方案。基准测试+1。如果删除了参数检查(即带有vapply的If语句),我认为我的语句甚至可能会超前一点。(但它们的速度非常接近;论证检查可能是值得的)@GSee,说得好。我今天打算改变这一点。现在我做到了。是的,它确实更快。无论如何,我喜欢你的代码紧凑性和想法。我会在
rbind.named.fill()
中使用
lappy()
而不是
sapply()
,因为sapply将nam“简化”为矩阵,
unique()
在矩阵和列表上的工作方式不同。
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)
}
# 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)
}
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
dplyr::bind_rows(lapply(x,function(y) as.data.frame(t(y),stringsAsFactors=FALSE)))

#     A    B    C    D    E    F    G    H    I    J    L    O    R    P    T
#1    b    d    f    h    j    l    n    p    r    t <NA> <NA> <NA> <NA> <NA>
#2 <NA> <NA>    c <NA> <NA>    f <NA> <NA>    i <NA>    l    o    r <NA> <NA>
#3 <NA> <NA> <NA>    d <NA> <NA> <NA>    h <NA> <NA>    l <NA> <NA>    p    t
purrr::map_df(x, ~as.data.frame(t(.x),stringsAsFactors = FALSE))