Подтвердить что ты не робот

Память эффективная альтернатива rbind - на месте rbind?

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

df <- rbind(df, df.extension)

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

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

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

4b9b3361

Ответ 1

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

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)

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

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

Ответ 2

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

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

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

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

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

Тест script:

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()

Ответ 4

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

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

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