Как я могу сохранить результаты в списке эффективным способом памяти?
В моем текущем проекте у меня есть функция вычисления, которая выполняется на одном элементе вектора A и возвращает элемент списка, который я вставляю в список B. Элемент return содержит несколько больших матриц произвольного размера, которые относятся к первому списку.
В качестве примера возьмем функцию, которая принимает исходное число n и генерирует случайную матрицу nx n.
vector.A <- sample(1:2000, 15000, replace = TRUE)
list.B <- as.list(rep(NA, length(vector.A)))
arbitraryMatrix <- function(n) {
matrix(rnorm(n*n), ncol = n, nrow = n)
}
for ( i in which(is.na(list.B)) ) {
print(i)
list.B[[i]] <- arbitraryMatrix( vector.A[i] )
}
Эта функция замедляет больший список list.B (на самом деле я почти уверен, что произойдет сбой R до завершения цикла). Мне пришло в голову, что к элементу list.B снова не обращаются после его создания, чтобы его можно было записать на диск, а не занимать память таким образом, который замедляет вычисления.
Я мог бы написать скрипт, который бы делал это, сохраняя куски в файлы.rda, но я надеялся, что у кого-то будет более элегантное решение.
Пакет FF выглядел как интересная возможность для этого http://cran.r-project.org/web/packages/ff/ff.pdf но, насколько я могу судить, он не поддерживает объекты списка.
Предостережения:
- Я использую цикл for, потому что мне нравится иметь возможность исправлять ошибки, возникающие на 7000-й итерации, без необходимости повторного запуска первых 6999 итераций.
- В зависимости от вашей машины редактируйте параметры кода, пока он не сможет работать, но только медленно на вашем
компьютер. - Фактическая проблема, которую я имею, берет список в качестве входных данных, поэтому я не заинтересован в векторизации функции произвольной матрицы.
- Проблема памяти усугубляется в моей реальной проблеме, так как функция использует много памяти (она включает в себя подмножество фреймов данных).
РЕДАКТИРОВАТЬ: я рассматриваю пакет mmap, который отображает r объектов во временные файлы, но я все еще пытаюсь решить, как использовать его для этой проблемы.
1 ответ
Вот ответ, используя пакет filehash. Это хороший метод, потому что он имеет впечатляюще малый объем памяти, который едва увеличивается с развитием функции. Так что это выполнило одну из ваших целей.
Тем не менее, это плохой метод, потому что у него есть два существенных недостатка... (1) он невероятно медленный, если вы откроете монитор процесса, то увидите, что обмен дисками и памятью происходит с довольно неторопливой скоростью (на моей машине, в наименее). На самом деле это так медленно, я не уверен, будет ли оно медленнее, чем дальше. Я не запустил его до завершения, только после того, как у меня возникла ошибка, когда я запустил функцию в памяти (примерно пункт 350 или около того), чтобы убедить себя, что это лучше, чем запустить в памяти (в этот момент объект диска было 73 гб). И это второй недостаток, объект диска, который создает, является массивным.
Поэтому мы надеемся, что кто-то другой придет с лучшим ответом на ваш вопрос (возможно, с mmap
?), Мне будет очень интересно посмотреть.
# set up disk storage object
library(filehash)
dbCreate("myTestDB")
db <- dbInit("myTestDB")
# put data on disk
db$A <- sample(1:2000, 15000, replace = TRUE)
db$B <- as.list(rep(NA, length(db$A)))
# function
arbitraryMatrix <- function(n) {
matrix(rnorm(n*n), ncol = n, nrow = n)
}
# run function by accessing disk objects
for ( i in which(is.na(db$B)) ) {
print(i)
db$B[[i]] <- arbitraryMatrix( db$A[i] )
}
# run function by accessing disk objects, following
# Jon's comment to treat db as a list
for ( i in which(is.na(db$B)) ) {
print(i)
db[[as.character(i)]] <- arbitraryMatrix( db$A[i] )
}
# use db[[as.character(1)]] etc to access the list items