Память эффективная альтернатива rbind - на месте rbind?
Мне нужно перевернуть два больших кадра данных. Прямо сейчас я использую
df <- rbind(df, df.extension)
но у меня (почти) мгновенно заканчивается память. Я предполагаю, потому что df удерживается в памяти дважды. В будущем я могу увидеть еще большие кадры данных, поэтому мне нужно какое-то место на месте.
Итак, мой вопрос: есть ли способ избежать дублирования данных в памяти при использовании rbind?
Я нашел этот question, который использует SqlLite, но я действительно хочу избежать использования жесткого диска в качестве кеша.
Ответы
Ответ 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()
Ответ 3
data.table
- ваш друг!
C.f. http://www.mail-archive.com/[email protected]/msg175877.html
Следуя комментарию nikola, вот описание ?rbindlist
(новое в v1.8.2):
То же, что и do.call("rbind",l)
, но гораздо быстрее.
Ответ 4
Это идеальный кандидат для bigmemory
. Для получения дополнительной информации см. сайт. Вот три аспекта использования:
- Хорошо использовать HD: отображение памяти на HD намного быстрее, чем практически любой другой доступ, поэтому вы можете не видеть замедление. Время от времени я полагаюсь нa > 1 ТБ матриц с отображением памяти, хотя большинство из них составляет от 6 до 50 ГБ. Более того, поскольку объект является матрицей, для использования этого объекта не требуется никаких реальных накладных расходов на переписывание кода.
- Если вы используете матрицу с файловой поддержкой или нет, вы можете использовать
separated = TRUE
для разделения столбцов. Я не использовал это много, из-за моего третьего совета:
- Вы можете перераспределить пространство HD, чтобы обеспечить больший размер потенциальной матрицы, но загружать только подматрицу, представляющую интерес. Таким образом, не нужно делать
rbind
.
Примечание. Хотя исходный вопрос, посвященный кадры данных и bigmemory, подходит для матриц, можно легко создать разные матрицы для разных типов данных, а затем объединить объекты в ОЗУ, чтобы создать фрейм данных, если это действительно необходимо.