Эффективная память альтернатива rbind - на месте rbind? - PullRequest
27 голосов
/ 17 августа 2011

Мне нужно привязать два больших фрейма данных.Прямо сейчас я использую

df <- rbind(df, df.extension)

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

Итак, мой вопрос: есть ли способ избежать дублирования данных в памяти при использовании rbind?

Я нашел этот вопрос , который использует SqlLite, но я очень хочуизбегать использования жесткого диска в качестве кеша.

Ответы [ 4 ]

18 голосов
/ 18 августа 2012

data.table твой друг!

C.f. http://www.mail-archive.com/r-help@r-project.org/msg175877.html


После комментария Николая, вот описание ?rbindlist (новое в v1.8.2):

То же, что и do.call("rbind",l), но намного быстрее.

17 голосов
/ 17 августа 2011

Прежде всего: используйте решение из другого вопроса, на который вы ссылаетесь, если вы хотите быть в безопасности. Поскольку R - это вызов по значению, забудьте о методе «на месте», который не копирует ваши кадры данных в память.

Один не рекомендуется метод сохранения большого количества памяти, это притворяться, что ваши фреймы данных являются списками, приводить список с помощью цикла for (apply будет использовать память как ад) и заставить R поверить в это на самом деле это датафрейм.

Я предупреждаю вас еще раз: использование этого на более сложных фреймах данных вызывает проблемы и трудно обнаруживаемые ошибки. Поэтому убедитесь, что вы тестируете достаточно хорошо, и, если возможно, избегайте этого как можно больше.

Вы можете попробовать следующий подход:

n1 <- 1000000
n2 <- 1000000
ncols <- 20
dtf1 <- as.data.frame(matrix(sample(n1*ncols), n1, ncols))
dtf2 <- as.data.frame(matrix(sample(n2*ncols), n1, ncols))

dtf <- list()

for(i in names(dtf1)){
  dtf[[i]] <- c(dtf1[[i]],dtf2[[i]])
}

attr(dtf,"row.names") <- 1:(n1+n2)
attr(dtf,"class") <- "data.frame"

Он удаляет имена строк, которые у вас действительно были (вы можете восстановить их, но проверьте наличие дубликатов имен строк!). Он также не выполняет все другие тесты, включенные в rbind.

Сохраняет вам около половины памяти в моих тестах, и в моем тесте dtfcomb и dtf равны. Красное поле - rbind, желтое - мой подход, основанный на списках.

enter image description here

Тестовый скрипт:

n1 <- 3000000
n2 <- 3000000
ncols <- 20

dtf1 <- as.data.frame(matrix(sample(n1*ncols), n1, ncols))
dtf2 <- as.data.frame(matrix(sample(n2*ncols), n1, ncols))

gc()
Sys.sleep(10)
dtfcomb <- rbind(dtf1,dtf2)
Sys.sleep(10)
gc()
Sys.sleep(10)
rm(dtfcomb)
gc()
Sys.sleep(10)
dtf <- list()
for(i in names(dtf1)){
  dtf[[i]] <- c(dtf1[[i]],dtf2[[i]])
}
attr(dtf,"row.names") <- 1:(n1+n2)
attr(dtf,"class") <- "data.frame"
Sys.sleep(10)
gc()
Sys.sleep(10)
rm(dtf)
gc()
10 голосов
/ 18 августа 2011

Прямо сейчас я разработал следующее решение:

nextrow = nrow(df)+1
df[nextrow:(nextrow+nrow(df.extension)-1),] = df.extension
# we need to assure unique row names
row.names(df) = 1:nrow(df)

Теперь мне не хватает памяти. Я думаю, потому что я храню

object.size(df) + 2 * object.size(df.extension)

в то время как с rbind R потребуется

object.size(rbind(df,df.extension)) + object.size(df) + object.size(df.extension). 

После этого я использую

rm(df.extension)
gc(reset=TRUE)

чтобы освободить память, которая мне больше не нужна.

Это решило мою проблему на данный момент, но я чувствую, что есть более продвинутый способ сделать rbind эффективным с точки зрения памяти. Я ценю любые комментарии по этому решению.

5 голосов
/ 17 августа 2011

Это идеальный кандидат на bigmemory.Смотрите сайт для получения дополнительной информации.Вот три аспекта использования:

  1. Можно использовать HD: отображение памяти на HD гораздо быстрее, чем при любом другом доступе, поэтому вы можете не заметить замедления.Время от времени я полагаюсь на> 1 ТБ отображенных в памяти матриц, хотя большинство составляет от 6 до 50 ГБ.Более того, поскольку объект является матрицей, для его использования не требуются реальные затраты на переписывание кода.
  2. Используете ли вы матрицу с файловой поддержкой или нет, вы можете использоватьseparated = TRUE чтобы разделить столбцы.Я не использовал это много, потому что мой третий совет:
  3. Вы можете перераспределить пространство HD, чтобы учесть больший потенциальный размер матрицы, но только загрузить интересующую подматрицу.Таким образом, нет необходимости делать rbind.

Примечание. Хотя исходный вопрос касается фреймов данных и большой памяти, подходит для матриц, можно легко создать разные матрицы для разных типов данных, а затемобъединить объекты в оперативной памяти для создания информационного кадра, если это действительно необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...