Как я могу предотвратить rbind() от получения действительно медленно, как фрейм данных становится больше?


У меня есть фрейм данных только с 1 строкой. Для этого я начинаю добавлять строки с помощью rbind

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

}

Это становится очень медленным, когда я расту. Почему это так? и как я могу сделать этот тип кода быстрее?

2 8

2 ответа:

Вы находитесь во 2-м круге ада, а именно не в состоянии предварительно выделить структуры данных.

Выращивание объектов таким образом-очень и очень плохая вещь в R. либо предварительно выделить и вставить:

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

Или реструктурируйте код, чтобы избежать такого рода инкрементного добавления строк. Как обсуждалось в ссылке, которую я цитирую, причина медлительности заключается в том, что каждый раз, когда вы добавляете строку, R должен найти новый непрерывный блок памяти, чтобы соответствовать фрейму данных. Много копирования.

Я попробовал пример. Как бы то ни было, он соглашается с утверждением пользователя о том, что вставка строк в фрейм данных также очень медленная. Я не совсем понимаю, что происходит, поскольку я ожидал, что проблема распределения превзойдет скорость копирования. Может ли кто-нибудь повторить это, или объяснить, почему результаты ниже (rbind

Edit: в первый раз я забыл инициализировать объект в 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