11

我有一个只有 1 行的数据框。为此,我开始使用 rbind 添加行

df #mydataframe with only one row
for (i in 1:20000)
{
    df<- rbind(df, newrow)

}

随着我的成长,这变得非常缓慢。这是为什么?以及如何使这种类型的代码更快?

4

2 回答 2

21

您处于地狱的第二圈,即未能预先分配数据结构。

以这种方式增长对象在 R 中是一件非常非常糟糕的事情。预分配和插入:

df <- data.frame(x = rep(NA,20000),y = rep(NA,20000))

或重组您的代码以避免这种增量添加行。正如我在引用的链接中所讨论的那样,速度缓慢的原因是每次添加一行时,R 都需要找到一个新的连续内存块来适应数据框。大量复制。

于 2013-02-04T19:32:38.970 回答
1

我尝试了一个例子。对于它的价值,它同意用户的断言,即在数据框中插入行也很慢。我不太明白发生了什么,因为我预计分配问题会超过复制速度。任何人都可以复制这个,或者解释为什么下面的结果(rbind < appending < insert)通常是正确的,或者解释为什么这不是一个有代表性的例子(例如数据框太小)?

编辑:我第一次忘记将对象初始化hell2fun为数据帧,因此代码执行矩阵运算而不是数据帧运算,这要快得多。如果有机会,我会将比较扩展到数据框与矩阵。但是,第一段中的定性断言仍然成立。

N <- 1000
set.seed(101)
r <- matrix(runif(2*N),ncol=2)

## second circle of hell
hell2fun <- function() {
    df <- as.data.frame(rbind(r[1,])) ## initialize
    for (i in 2:N) {
        df <- rbind(df,r[i,])
    }
}

insertfun <- function() {
    df <- data.frame(x=rep(NA,N),y=rep(NA,N))
    for (i in 1:N) {
        df[i,] <- r[i,]
    }
}

rsplit <- as.list(as.data.frame(t(r)))
rbindfun <-  function() {
    do.call(rbind,rsplit)
}

library(rbenchmark)
benchmark(hell2fun(),insertfun(),rbindfun())

##          test replications elapsed relative user.self 
## 1  hell2fun()          100  32.439  484.164    31.778 
## 2 insertfun()          100  45.486  678.896    42.978 
## 3  rbindfun()          100   0.067    1.000     0.076 
于 2013-02-04T22:22:40.403 回答