rbind.data.frame的性能

Nic*_*bbe 8 performance r dataframe rbind

我有一个数据框列表,我确信它们都至少包含一行(事实上,有些行只包含一行,其他行包含给定数量的行),并且它们都具有相同的列(名称和类型).如果重要的话,我也确定行中的任何地方都没有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),]})
Run Code Online (Sandbox Code Playgroud)

我已设置参数(随机化),以便它们接近我的真实情况.

现在,我想在一个数据帧中统一所有这些数据帧.我认为使用rbind可以做到这一点,就像这样:

system.time(
result<-do.call(rbind, someParts)
)
Run Code Online (Sandbox Code Playgroud)

现在,在我的系统上(这不是特别慢),并且使用上面的设置,这需要system.time的输出:

   user  system elapsed 
   5.61    0.00    5.62
Run Code Online (Sandbox Code Playgroud)

rbind-ing 254(在我的情况下)200行变量的行近6秒?当然必须有一种方法来改善这里的表现?在我的代码中,我必须经常做类似的事情(这是来自多个插补),所以我需要尽可能快.

Aar*_*ica 13

你能用数字变量建立你的矩阵并在最后转换成一个因子吗? rbind在数字矩阵上快得多.

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

> system.time(result<-do.call(rbind, someParts))
   user  system elapsed 
  2.628   0.000   2.636 
Run Code Online (Sandbox Code Playgroud)

使用所有数字矩阵构建列表:

onerowdfr2 <- matrix(as.numeric(onerowdfr), nrow=1)
someParts2<-lapply(rbinom(200, 1, 14/200)*6+1, 
                   function(reps){onerowdfr2[rep(1, reps),]})
Run Code Online (Sandbox Code Playgroud)

结果更快rbind.

> system.time(result2<-do.call(rbind, someParts2))
   user  system elapsed 
  0.001   0.000   0.001
Run Code Online (Sandbox Code Playgroud)

编辑:这是另一种可能性; 它只是依次组合每一列.

> 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  
Run Code Online (Sandbox Code Playgroud)

但仍然没有使用矩阵那么快.

编辑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)
}
Run Code Online (Sandbox Code Playgroud)

我的系统的时间是:

   user  system elapsed 
   0.090    0.00    0.091 
Run Code Online (Sandbox Code Playgroud)

  • 如果你将`[[`更改为`.subset2`(它不应该导致它的内部函数),它运行速度提高2倍. (2认同)

Ric*_*ton 5

不是一个巨大的推动力,但是从包中交换rbind可以节省大约10%的运行时间(使用样本数据集,在我的机器上).rbind.fillplyr


小智 5

如果你真的想data.frame更快地操作你的 s ,我建议使用 packagedata.table和 function rbindlist()。我没有执行广泛的测试,但对于我的数据集(3000 个数据帧,每个数据帧 1000 行 x 40 列)rbindlist()只需要 20 秒。