Как управлять памятью в агентном моделировании с помощью R - PullRequest
10 голосов
/ 01 июня 2019

Я строю агентную модель с помощью R, но у меня возникают проблемы с памятью при попытке использовать большие объекты.В частности, при инициализации создается 8 трехмерных массивов, и на каждом временном шаге каждый трехмерный массив заполняется различными функциями.

На данный момент ПРО работает более 1825 дней, и 2500 человек симулируются для перемещения по ландшафту.В ландшафтах 1000 ячеек.В этой конфигурации у меня нет проблем с памятью.

При инициализации

  • 1 3D-массив выглядит так:

    h <- array(NA, dim=c(1825, 48, 2500),
               dimnames=list(NULL, NULL, as.character(seq(1, 2500, 1))))
               ## 3th dimension = individual ID
    
  • 1 3D-массив похож на:

    p <- array(NA, dim=c(1825, 38, 1000),
               dimnames=list(NULL, NULL, as.character(seq(1, 1000, 1))))
               ## 3th dimension = cell ID
    
  • 6 3D-массивы похожи на:

    t <- array(NA, dim=c(1825, 41, 2500),
               dimnames=list(NULL, NULL, as.character(seq(1, 2500, 1))))
               ## 3th dimension = individual ID
    

Массивы содержат символ/ string типы данных.

В идеале я хотел бы увеличить количество отдельных лиц и / или количество исправлений, но это невозможно из-за проблем с памятью.Кажется, что есть некоторые инструменты, такие как bigmemory, gc для управления памятью.Эти инструменты эффективны?Я новичок в программировании, и у меня нет опыта управления памятью и высокопроизводительными вычислениями.Спасибо за любые советы, спасибо за ваше время.

sessionInfo () R версия 3.5.3 (2019-03-11) Платформа: x86_64-w64-mingw32 / x64 (64-разрядная версия) Работаетпод: Windows 7 x64 (сборка 7601) с пакетом обновления 1

Ответы [ 2 ]

4 голосов
/ 04 июня 2019

Насколько я понимаю, bigmemory работает только с матрицами, а не с многомерными массивами, но вы можете сохранить многомерный массив в виде списка матриц.

gc - это просто сборщик мусора, и вы нена самом деле не нужно вызывать его, так как он будет вызываться автоматически, но в руководстве также говорится:

Может быть полезно вызвать gc после удаления большого объекта, поскольку это может вызвать запрос Rчтобы вернуть память операционной системе.

Я думаю, что наиболее полезный пакет для вашей задачи будет ff.Вот короткий пример, иллюстрирующий силу пакета ff, который хранит данные на диске и почти не влияет на память.

Массивы инициализации с base-R:

p <- array(NA, dim=c(1825, 38, 1000),
           dimnames=list(NULL, NULL, as.character(seq(1, 1000, 1))))

format(object.size(p), units="Mb")

"264,6 Мб"

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


Массивы инициализации с помощью ff:

library(ff)
myArr <- ff(NA, dim=c(1825, 38, 1000), 
            dimnames=list(NULL, NULL, as.character(seq(1, 1000, 1))),
            filename="arr.ffd", vmode="logical", overwrite = T)

format(object.size(myArr), units="Mb")

[1] "0,1 Мб"


Проверка на равенство:

euqals <- list()
for (i in 1:dim(p)[1]) {
  euqals[[i]] <-  all.equal(p[i,,],
                            myArr[i,,])
}
all(unlist(euqals))

[1] ИСТИНА

3 голосов
/ 10 июня 2019

Есть ли какая-либо причина, по которой вам нужно придерживаться типа данных массива?
Если в ваших массивах присутствует много NA, это означает, что вы используете больше памяти, чем вам действительно нужно.Это обратная сторона массивов в R. Если выполняемые вами операции не обязательно требуют, чтобы ваши данные были массивами, вам следует сэкономить некоторую память , изменив ее как data.frame.

Ниже приведен пример того, как ваш data.frame может выглядеть после преобразования из массива.Обратите внимание, что мне пришлось явно использовать na.rm=FALSE, в противном случае результатом будет 0 строк данных.

devtools::install_github("Rdatatable/data.table@as.dt.array.null.dimnames")
library(data.table)

p <- array(NA, dim=c(1825, 38, 1000),
           dimnames=list(NULL, NULL, as.character(seq(1, 1000, 1))))
as.data.table(p, na.rm=FALSE)
#             V1    V2     V3  value
#          <int> <int> <char> <lgcl>
#       1:     1     1      1     NA
#       2:     1     1     10     NA
#       3:     1     1    100     NA
#       4:     1     1   1000     NA
#       5:     1     1    101     NA

Альтернативный способ - использовать пакет data.cube .Это будет в основном делать то, что я написал выше для вас за сценой.У вас все еще есть оператор массива [, но объекты data.cube не будут работать с функциями R, которые ожидают массив при вводе, так как они будут приводить к массиву data.cube, теряя все преимущества памяти.Преимущества памяти могут быть значительными, например, в виньетка data.cube :

array: 34.13 GB
data.cube: 0.01 GB
...