我有一个数据框列表,可以确定它们都至少包含一行(实际上,有些仅包含一行,而另一些则包含给定的行数),并且它们都具有相同的列(名称和类型)。如果很重要,我还可以确定行中的任何地方都没有NA。

情况可以这样模拟:

#create one row
onerowdfr<-do.call(data.frame, c(list(), rnorm(100) , lapply(sample(letters[1:2], 100, replace=TRUE), function(x){factor(x, levels=letters[1:2])})))
colnames(onerowdfr)<-c(paste("cnt", 1:100, sep=""), paste("cat", 1:100, sep=""))
#reuse it in a list
someParts<-lapply(rbinom(200, 1, 14/200)*6+1, function(reps){onerowdfr[rep(1, reps),]})

我已经设置了(随机化的)参数,以使它们近似于我的真实情况。

现在,我想将所有这些数据框合并为一个数据框。我认为使用rbind可以解决问题,如下所示:
system.time(
result<-do.call(rbind, someParts)
)

现在,在我的系统上(速度不是特别慢),并使用上面的设置,这就是system.time的输出:
   user  system elapsed
   5.61    0.00    5.62

对254个行(在我的情况下)进行200个变量的查询将近6秒?肯定有一种方法可以改善此处的性能吗?在我的代码中,我必须经常做类似的事情(这是多次插补的结果),因此我需要尽快。

最佳答案

您是否可以仅使用数字变量构建矩阵,然后最后转换为因子? rbind在数字矩阵上要快得多。

在我的系统上,使用数据框:

> system.time(result<-do.call(rbind, someParts))
   user  system elapsed
  2.628   0.000   2.636

而是使用所有数字矩阵构建列表:
onerowdfr2 <- matrix(as.numeric(onerowdfr), nrow=1)
someParts2<-lapply(rbinom(200, 1, 14/200)*6+1,
                   function(reps){onerowdfr2[rep(1, reps),]})

导致rbind更快。
> system.time(result2<-do.call(rbind, someParts2))
   user  system elapsed
  0.001   0.000   0.001

编辑:这是另一种可能性;它只是依次组合每列。
> system.time({
+   n <- 1:ncol(someParts[[1]])
+   names(n) <- names(someParts[[1]])
+   result <- as.data.frame(lapply(n, function(i)
+                           unlist(lapply(someParts, `[[`, i))))
+ })
   user  system elapsed
  0.810   0.000   0.813

仍然不及使用矩阵快。

编辑2:

如果只有数字和因数,那么将所有内容转换为数字,对其进行rbind并将必要的列转换回因数并不难。假设所有因素都具有完全相同的水平。从整数转换为因数也比从数字转换为因数要快,因此我强制首先转换为整数。
someParts2 <- lapply(someParts, function(x)
                     matrix(unlist(x), ncol=ncol(x)))
result<-as.data.frame(do.call(rbind, someParts2))
a <- someParts[[1]]
f <- which(sapply(a, class)=="factor")
for(i in f) {
  lev <- levels(a[[i]])
  result[[i]] <- factor(as.integer(result[[i]]), levels=seq_along(lev), labels=lev)
}

我的系统上的时间是:
   user  system elapsed
   0.090    0.00    0.091

关于rbind.data.frame的性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5980240/

10-12 17:34