Как я могу сохранить результаты в списке эффективным способом памяти?

В моем текущем проекте у меня есть функция вычисления, которая выполняется на одном элементе вектора 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 
Другие вопросы по тегам