当前位置: 首页 > 知识库问答 >
问题:

do.call(rbind, list)对于不均匀的列数

越源
2023-03-14

我有一个列表,每个元素都是一个字符向量,长度不同。我想将数据绑定为行,这样列名就“对齐”,如果有额外的数据,就创建列,如果缺少数据,就创建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)]

如果我确定每个元素的格式是相同的,下面的行通常是我会做的...

do.call(rbind,x)

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

共有3个答案

皮骏
2023-03-14

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

library(data.table)
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)]


x2 <- lapply(x, as.list)
rbindlist(x2, fill=TRUE)
#>       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

它增加了一个小的开销,因为它需要用as.list转换字符向量。这段话还可以为进程增加时间,具体取决于数据的生成方式。
另一方面,它似乎在大型数据集上执行得更快。
返回一个data.table

我重写了@Arun和@GSee的例子,以生成更大的样本。

# 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)  
}
l1 <- replicate(1e6, sample.fun()) # Arun's data, just bigger
l2 <- lapply(l1, as.list) # same data converted with as.list
library(microbenchmark)
library(data.table)
# Arun's function
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's function
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)
}
microbenchmark(t1 <- rbind.named.fill(l1), 
               t2 <- rbindlist(l2, fill=TRUE),
               t3 <- do.call(foo, l1),
               times=10)
#> Unit: seconds
#>                                 expr      min        lq        mean    median        uq      max neval
#> t1 <- rbind.named.fill(l1)      6.536782  7.545538   9.118771  9.304844 10.505814 11.28260    10
#> t2 <- rbindlist(l2, fill=TRUE)  5.250387  5.787712   6.910340  6.226065  7.579503 10.40524    10
#> t3 <- do.call(foo, l1)          9.590615 11.043557  13.504694 12.550535 15.364464 19.95877    10


identical(t1, data.frame(t2))
#> [1] TRUE
identical(t3, data.frame(t2))
#> [1] TRUE

由reprex包(v0.3.0)创建于2019-08-01

幸越泽
2023-03-14

如果你想得到一个矩阵。。。

我最近为一个想要将向量绑定到矩阵中的同事编写了这个函数

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"
澹台俊晖
2023-03-14

rbind.fill是一个很棒的函数,在data.frames.列表上做得非常好但是恕我直言,对于这种情况,当列表只包含(命名)向量时,它可以做得更快。

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

基本上,我们得到了所有唯一的名称,以形成最终数据的列。框架然后,我们用length=input创建一个列表,并用NA填充其余的值。这可能是最“棘手”的部分,因为我们必须在填写NA时匹配名称。然后,我们最后为列设置一次名称(如果需要,也可以使用data.tablepackage中的setnames通过引用来设置)。

现在来看一些基准测试:

# 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
 类似资料:
  • 0.1-0.2:********** 0.2-0.3:******** 0.3-0.4:********* 0.5-0.6:********* 0.6-0.7:********* 0.7-0.8:********* 0.4-0.5:********* 0.5-0.6:********* 0.6-0.7:********* 0.1-0.2:********* 0.2-0.3:********* 0.

  • 问题内容: 我试图识别/创建一个函数(在Java中),该函数给我一个非均匀的分布式数字序列。如果我有一个函数说它将给我一个从到的随机数。 该函数最适合任何给定的函数,下面仅是我想要的示例。 但是,如果我们说函数将返回来自分布式的s nonuni。 我想例如说 约占所有案件的20%。 大约是所有情况的50%。 约占所有案件的20%。 大约是所有情况的10。 总之somting,给我一个数字,如正态分

  • 我们在AWS上运行16个节点kafka集群,每个节点是m4. xLargeEC2实例,具有2TB EBS(ST1)磁盘。Kafka版本0.10.1.0,目前我们有大约100个主题。一些繁忙的话题每天会有大约20亿个事件,一些低量的话题每天只有数千个。 我们的大多数主题在生成消息时使用UUID作为分区键,因此分区分布相当均匀。 我们有相当多的消费者使用消费群体从这个集群消费。每个使用者都有一个唯一的

  • 我经常会发现这样的问题:人们最终得到了一个未命名字符向量的未命名列表,并且希望将它们按行绑定到中。这里有一个例子: 一种典型的方法是从基R使用。 然而,这似乎是更多的步骤比它需要的。 因此,我的问题是什么是一种有效的或方法来将未命名字符向量的未命名列表按行绑定到中?

  • 我正在使用一个数据集,其中包含与相结合的度量值,例如: 我试图检测和删除可能出现的潜在峰值,如度量值。 到目前为止,我发现了一些东西: > 这个数据集的时间间隔从15秒一直到25分钟,这使得它非常不均匀 峰的宽度无法事先确定 峰值高度与其他值明显偏离 时间步长的标准化只应在去除异常值后进行,因为它们会干扰结果 由于其他异常(例如,负值、平线),即使没有这些异常,也“不可能”使其变得均匀,因为峰值会

  • 问题内容: 我知道如果我使用Java的Random生成器,并使用nextInt生成数字,则数字将均匀分布。但是,如果我使用2个Random实例,并使用两个Random类生成数字,会发生什么。数字是否会均匀分布? 问题答案: 每个实例生成的数字将均匀分布,因此,如果将两个实例生成的随机数序列组合在一起,则它们也应均匀分布。 请注意,即使结果分布是均匀的,您也可能要注意种子,以避免两个生成器的输出之间